xref: /linux/drivers/net/wireless/realtek/rtw89/coex.c (revision 19354c4b346aeaee18a2e42e5dae60e7c1b52a5c)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2019-2020  Realtek Corporation
3  */
4 
5 #include "chan.h"
6 #include "coex.h"
7 #include "debug.h"
8 #include "fw.h"
9 #include "mac.h"
10 #include "phy.h"
11 #include "ps.h"
12 #include "reg.h"
13 
14 #define RTW89_COEX_VERSION 0x09180213
15 #define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/
16 #define BTC_E2G_LIMIT_DEF 80
17 
18 enum btc_fbtc_tdma_template {
19 	CXTD_OFF = 0x0,
20 	CXTD_OFF_B2,
21 	CXTD_OFF_EXT,
22 	CXTD_FIX,
23 	CXTD_PFIX,
24 	CXTD_AUTO,
25 	CXTD_PAUTO,
26 	CXTD_AUTO2,
27 	CXTD_PAUTO2,
28 	CXTD_MAX,
29 };
30 
31 enum btc_fbtc_tdma_type {
32 	CXTDMA_OFF = 0x0,
33 	CXTDMA_FIX = 0x1,
34 	CXTDMA_AUTO = 0x2,
35 	CXTDMA_AUTO2 = 0x3,
36 	CXTDMA_MAX
37 };
38 
39 enum btc_fbtc_tdma_rx_flow_ctrl {
40 	CXFLC_OFF = 0x0,
41 	CXFLC_NULLP = 0x1,
42 	CXFLC_QOSNULL = 0x2,
43 	CXFLC_CTS = 0x3,
44 	CXFLC_MAX
45 };
46 
47 enum btc_fbtc_tdma_wlan_tx_pause {
48 	CXTPS_OFF = 0x0,  /* no wl tx pause*/
49 	CXTPS_ON = 0x1,
50 	CXTPS_MAX
51 };
52 
53 enum btc_mlme_state {
54 	MLME_NO_LINK,
55 	MLME_LINKING,
56 	MLME_LINKED,
57 };
58 
59 struct btc_fbtc_1slot {
60 	u8 fver;
61 	u8 sid; /* slot id */
62 	struct rtw89_btc_fbtc_slot slot;
63 } __packed;
64 
65 static const struct rtw89_btc_fbtc_tdma t_def[] = {
66 	[CXTD_OFF]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
67 	[CXTD_OFF_B2]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 1, 0, 0},
68 	[CXTD_OFF_EXT]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 2, 0, 0},
69 	[CXTD_FIX]	= { CXTDMA_FIX,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
70 	[CXTD_PFIX]	= { CXTDMA_FIX,  CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
71 	[CXTD_AUTO]	= { CXTDMA_AUTO,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
72 	[CXTD_PAUTO]	= { CXTDMA_AUTO, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
73 	[CXTD_AUTO2]	= {CXTDMA_AUTO2,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
74 	[CXTD_PAUTO2]	= {CXTDMA_AUTO2, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0}
75 };
76 
77 #define __DEF_FBTC_SLOT(__dur, __cxtbl, __cxtype) \
78 	{ .dur = cpu_to_le16(__dur), .cxtbl = cpu_to_le32(__cxtbl), \
79 	  .cxtype = cpu_to_le16(__cxtype),}
80 
81 static const struct rtw89_btc_fbtc_slot s_def[] = {
82 	[CXST_OFF]	= __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX),
83 	[CXST_B2W]	= __DEF_FBTC_SLOT(5,   0xea5a5a5a, SLOT_ISO),
84 	[CXST_W1]	= __DEF_FBTC_SLOT(70,  0xea5a5a5a, SLOT_ISO),
85 	[CXST_W2]	= __DEF_FBTC_SLOT(15,  0xea5a5a5a, SLOT_ISO),
86 	[CXST_W2B]	= __DEF_FBTC_SLOT(15,  0xea5a5a5a, SLOT_ISO),
87 	[CXST_B1]	= __DEF_FBTC_SLOT(250, 0xe5555555, SLOT_MIX),
88 	[CXST_B2]	= __DEF_FBTC_SLOT(7,   0xea5a5a5a, SLOT_MIX),
89 	[CXST_B3]	= __DEF_FBTC_SLOT(5,   0xe5555555, SLOT_MIX),
90 	[CXST_B4]	= __DEF_FBTC_SLOT(50,  0xe5555555, SLOT_MIX),
91 	[CXST_LK]	= __DEF_FBTC_SLOT(20,  0xea5a5a5a, SLOT_ISO),
92 	[CXST_BLK]	= __DEF_FBTC_SLOT(500, 0x55555555, SLOT_MIX),
93 	[CXST_E2G]	= __DEF_FBTC_SLOT(5,   0xea5a5a5a, SLOT_MIX),
94 	[CXST_E5G]	= __DEF_FBTC_SLOT(5,   0xffffffff, SLOT_ISO),
95 	[CXST_EBT]	= __DEF_FBTC_SLOT(5,   0xe5555555, SLOT_MIX),
96 	[CXST_ENULL]	= __DEF_FBTC_SLOT(5,   0x55555555, SLOT_MIX),
97 	[CXST_WLK]	= __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX),
98 	[CXST_W1FDD]	= __DEF_FBTC_SLOT(50,  0xffffffff, SLOT_ISO),
99 	[CXST_B1FDD]	= __DEF_FBTC_SLOT(50,  0xffffdfff, SLOT_ISO),
100 };
101 
102 static const u32 cxtbl[] = {
103 	0xffffffff, /* 0 */
104 	0xaaaaaaaa, /* 1 */
105 	0xe5555555, /* 2 */
106 	0xee555555, /* 3 */
107 	0xd5555555, /* 4 */
108 	0x5a5a5a5a, /* 5 */
109 	0xfa5a5a5a, /* 6 */
110 	0xda5a5a5a, /* 7 */
111 	0xea5a5a5a, /* 8 */
112 	0x6a5a5aaa, /* 9 */
113 	0x6a5a6a5a, /* 10 */
114 	0x6a5a6aaa, /* 11 */
115 	0x6afa5afa, /* 12 */
116 	0xaaaa5aaa, /* 13 */
117 	0xaaffffaa, /* 14 */
118 	0xaa5555aa, /* 15 */
119 	0xfafafafa, /* 16 */
120 	0xffffddff, /* 17 */
121 	0xdaffdaff, /* 18 */
122 	0xfafadafa, /* 19 */
123 	0xea6a6a6a, /* 20 */
124 	0xea55556a, /* 21 */
125 	0xaafafafa, /* 22 */
126 	0xfafaaafa, /* 23 */
127 	0xfafffaff, /* 24 */
128 	0xea6a5a5a, /* 25 */
129 	0xfaff5aff, /* 26 */
130 	0xffffdfff, /* 27 */
131 	0xe6555555, /* 28 */
132 };
133 
134 static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
135 	/* firmware version must be in decreasing order for each chip */
136 	{RTL8922D, RTW89_FW_VER_CODE(0, 35, 119, 3),
137 	 .fcxbtcrpt = 11, .fcxtdma = 8,    .fcxslots = 7, .fcxcysta = 8,
138 	 .fcxstep = 7,    .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
139 	 .fcxbtver = 8,   .fcxbtscan = 8,  .fcxbtafh = 8, .fcxbtdevinfo = 8,
140 	 .fwlrole = 11,   .frptmap = 5,    .fcxctrl = 9,  .fcxinit = 11,
141 	 .fwevntrptl = 1, .fwc2hfunc = 4, .drvinfo_ver = 3, .info_buf = 1800,
142 	 .max_role_num = 6, .fcxosi = 7,   .fcxmlo = 2,   .bt_desired = 8,
143 	 .fcxtrx = 9,     .fcxtxpwr = 1,
144 	},
145 	{RTL8922D, RTW89_FW_VER_CODE(0, 35, 111, 0),
146 	 .fcxbtcrpt = 11, .fcxtdma = 8,    .fcxslots = 7, .fcxcysta = 8,
147 	 .fcxstep = 7,    .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
148 	 .fcxbtver = 8,   .fcxbtscan = 8,  .fcxbtafh = 8, .fcxbtdevinfo = 8,
149 	 .fwlrole = 10,   .frptmap = 5,    .fcxctrl = 9,  .fcxinit = 11,
150 	 .fwevntrptl = 1, .fwc2hfunc = 4, .drvinfo_ver = 3, .info_buf = 1800,
151 	 .max_role_num = 6, .fcxosi = 6,   .fcxmlo = 2,   .bt_desired = 8,
152 	 .fcxtrx = 9,     .fcxtxpwr = 1,
153 	},
154 	{RTL8922D, RTW89_FW_VER_CODE(0, 35, 94, 0),
155 	 .fcxbtcrpt = 11, .fcxtdma = 8,    .fcxslots = 7, .fcxcysta = 8,
156 	 .fcxstep = 7,    .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
157 	 .fcxbtver = 8,   .fcxbtscan = 8,  .fcxbtafh = 8, .fcxbtdevinfo = 8,
158 	 .fwlrole = 10,    .frptmap = 5,   .fcxctrl = 9,  .fcxinit = 10,
159 	 .fwevntrptl = 1,  .fwc2hfunc = 4, .drvinfo_ver = 3, .info_buf = 1800,
160 	 .max_role_num = 6, .fcxosi = 6,   .fcxmlo = 2,   .bt_desired = 8,
161 	 .fcxtrx = 9,     .fcxtxpwr = 1,
162 	},
163 	{RTL8852BT, RTW89_FW_VER_CODE(0, 29, 133, 0),
164 	 .fcxbtcrpt = 9, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
165 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
166 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
167 	 .fwlrole = 7,   .frptmap = 5,    .fcxctrl = 7,  .fcxinit = 107,
168 	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 103, .info_buf = 1800,
169 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
170 	 .fcxtrx = 107,  .fcxtxpwr = 0,
171 	},
172 	{RTL8852BT, RTW89_FW_VER_CODE(0, 29, 122, 0),
173 	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
174 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
175 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
176 	 .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
177 	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 1, .info_buf = 1800,
178 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
179 	 .fcxtrx = 0,    .fcxtxpwr = 0,
180 	},
181 	{RTL8852BT, RTW89_FW_VER_CODE(0, 29, 90, 0),
182 	 .fcxbtcrpt = 7, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
183 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
184 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
185 	 .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
186 	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 1, .info_buf = 1800,
187 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
188 	 .fcxtrx = 0,    .fcxtxpwr = 0,
189 	},
190 	{RTL8922A, RTW89_FW_VER_CODE(0, 35, 119, 3),
191 	 .fcxbtcrpt = 11, .fcxtdma = 8,    .fcxslots = 7, .fcxcysta = 8,
192 	 .fcxstep = 7,    .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
193 	 .fcxbtver = 8,   .fcxbtscan = 8,  .fcxbtafh = 8, .fcxbtdevinfo = 8,
194 	 .fwlrole = 11,   .frptmap = 5,    .fcxctrl = 9,  .fcxinit = 11,
195 	 .fwevntrptl = 1, .fwc2hfunc = 4, .drvinfo_ver = 3, .info_buf = 1800,
196 	 .max_role_num = 6, .fcxosi = 7,   .fcxmlo = 2,   .bt_desired = 8,
197 	 .fcxtrx = 9,     .fcxtxpwr = 1,
198 	},
199 	{RTL8922A, RTW89_FW_VER_CODE(0, 35, 111, 0),
200 	 .fcxbtcrpt = 11, .fcxtdma = 8,    .fcxslots = 7, .fcxcysta = 8,
201 	 .fcxstep = 7,    .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
202 	 .fcxbtver = 8,   .fcxbtscan = 8,  .fcxbtafh = 8, .fcxbtdevinfo = 8,
203 	 .fwlrole = 10,   .frptmap = 5,    .fcxctrl = 9,  .fcxinit = 11,
204 	 .fwevntrptl = 1, .fwc2hfunc = 4, .drvinfo_ver = 3, .info_buf = 1800,
205 	 .max_role_num = 6, .fcxosi = 6,   .fcxmlo = 2,   .bt_desired = 8,
206 	 .fcxtrx = 9,     .fcxtxpwr = 1,
207 	},
208 	{RTL8922A, RTW89_FW_VER_CODE(0, 35, 71, 0),
209 	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
210 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
211 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
212 	 .fwlrole = 8,   .frptmap = 4,    .fcxctrl = 7,  .fcxinit = 7,
213 	 .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_ver = 3, .info_buf = 1800,
214 	 .max_role_num = 6, .fcxosi = 1,  .fcxmlo = 1,   .bt_desired = 9,
215 	 .fcxtrx = 7,    .fcxtxpwr = 0,
216 	},
217 	{RTL8922A, RTW89_FW_VER_CODE(0, 35, 63, 0),
218 	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
219 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
220 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
221 	 .fwlrole = 8,   .frptmap = 4,    .fcxctrl = 7,  .fcxinit = 7,
222 	 .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_ver = 2, .info_buf = 1800,
223 	 .max_role_num = 6, .fcxosi = 1,  .fcxmlo = 1,   .bt_desired = 9,
224 	 .fcxtrx = 0,    .fcxtxpwr = 0,
225 	},
226 	{RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0),
227 	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
228 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
229 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
230 	 .fwlrole = 8,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
231 	 .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_ver = 1, .info_buf = 1800,
232 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
233 	 .fcxtrx = 0,    .fcxtxpwr = 0,
234 	},
235 	{RTL8851B, RTW89_FW_VER_CODE(0, 29, 133, 0),
236 	 .fcxbtcrpt = 9, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
237 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
238 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
239 	 .fwlrole = 7,   .frptmap = 5,    .fcxctrl = 7,  .fcxinit = 107,
240 	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 103, .info_buf = 1800,
241 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
242 	 .fcxtrx = 107,  .fcxtxpwr = 0,
243 	},
244 	{RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0),
245 	 .fcxbtcrpt = 105, .fcxtdma = 3,  .fcxslots = 1, .fcxcysta = 5,
246 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
247 	 .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
248 	 .fwlrole = 2,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
249 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1800,
250 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
251 	 .fcxtrx = 0,    .fcxtxpwr = 0,
252 	},
253 	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 130, 1),
254 	 .fcxbtcrpt = 205, .fcxtdma = 4,  .fcxslots = 2, .fcxcysta = 105,
255 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
256 	 .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
257 	 .fwlrole = 101, .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
258 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1280,
259 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
260 	 .fcxtrx = 107,  .fcxtxpwr = 0,
261 	},
262 	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 97, 0),
263 	 .fcxbtcrpt = 4, .fcxtdma = 4,    .fcxslots = 2, .fcxcysta = 105,
264 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
265 	 .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
266 	 .fwlrole = 101, .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
267 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1280,
268 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
269 	 .fcxtrx = 107,  .fcxtxpwr = 0,
270 	},
271 	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0),
272 	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
273 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
274 	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
275 	 .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
276 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1280,
277 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
278 	 .fcxtrx = 0,    .fcxtxpwr = 0,
279 	},
280 	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0),
281 	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
282 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
283 	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
284 	 .fwlrole = 1,   .frptmap = 2,    .fcxctrl = 1,  .fcxinit = 0,
285 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1280,
286 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
287 	 .fcxtrx = 0,    .fcxtxpwr = 0,
288 	},
289 	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0),
290 	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
291 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
292 	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
293 	 .fwlrole = 1,   .frptmap = 2,    .fcxctrl = 1,  .fcxinit = 0,
294 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1280,
295 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
296 	 .fcxtrx = 0,    .fcxtxpwr = 0,
297 	},
298 	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 133, 0),
299 	 .fcxbtcrpt = 9, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
300 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 8,
301 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
302 	 .fwlrole = 7,   .frptmap = 105,  .fcxctrl = 7,  .fcxinit = 107,
303 	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 103, .info_buf = 1800,
304 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
305 	 .fcxtrx = 107,  .fcxtxpwr = 0,
306 	},
307 	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 122, 0),
308 	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
309 	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
310 	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
311 	 .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
312 	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_ver = 1, .info_buf = 1800,
313 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
314 	 .fcxtrx = 0,    .fcxtxpwr = 0,
315 	},
316 	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0),
317 	 .fcxbtcrpt = 105, .fcxtdma = 3,  .fcxslots = 1, .fcxcysta = 5,
318 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
319 	 .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
320 	 .fwlrole = 2,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
321 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1800,
322 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
323 	 .fcxtrx = 0,    .fcxtxpwr = 0,
324 	},
325 	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0),
326 	 .fcxbtcrpt = 5, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 4,
327 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
328 	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
329 	 .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
330 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1800,
331 	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
332 	 .fcxtrx = 0,    .fcxtxpwr = 0,
333 	},
334 	{RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0),
335 	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
336 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
337 	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
338 	 .fwlrole = 1,   .frptmap = 1,    .fcxctrl = 1,  .fcxinit = 0,
339 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1280,
340 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
341 	 .fcxtrx = 0,    .fcxtxpwr = 0,
342 	},
343 	{RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0),
344 	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
345 	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
346 	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
347 	 .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
348 	 .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_ver = 0, .info_buf = 1280,
349 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
350 	 .fcxtrx = 0,    .fcxtxpwr = 0,
351 	},
352 	{RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0),
353 	 .fcxbtcrpt = 1, .fcxtdma = 1,    .fcxslots = 1, .fcxcysta = 2,
354 	 .fcxstep = 2,   .fcxnullsta = 1, .fcxmreg = 1,  .fcxgpiodbg = 1,
355 	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
356 	 .fwlrole = 0,   .frptmap = 0,    .fcxctrl = 0,  .fcxinit = 0,
357 	 .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_ver = 0, .info_buf = 1024,
358 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
359 	 .fcxtrx = 0,    .fcxtxpwr = 0,
360 	},
361 
362 	/* keep it to be the last as default entry */
363 	{0, RTW89_FW_VER_CODE(0, 0, 0, 0),
364 	 .fcxbtcrpt = 1, .fcxtdma = 1,    .fcxslots = 1, .fcxcysta = 2,
365 	 .fcxstep = 2,   .fcxnullsta = 1, .fcxmreg = 1,  .fcxgpiodbg = 1,
366 	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
367 	 .fwlrole = 0,   .frptmap = 0,    .fcxctrl = 0,  .fcxinit = 0,
368 	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1024,
369 	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
370 	 .fcxtrx = 0,    .fcxtxpwr = 0,
371 	},
372 };
373 
374 #define RTW89_DEFAULT_BTC_VER_IDX (ARRAY_SIZE(rtw89_btc_ver_defs) - 1)
375 
376 static const union rtw89_btc_wl_state_map btc_scanning_map = {
377 	.map = {
378 		.scan = 1,
379 		.dhcp = 1,
380 		.roaming = 1,
381 		.transacting = 1,
382 		._4way = 1,
383 		.handshake = 1,
384 	},
385 };
386 
387 static u32 chip_id_to_bt_rom_code_id(u32 id)
388 {
389 	switch (id) {
390 	case RTL8852A:
391 	case RTL8852B:
392 	case RTL8852C:
393 	case RTL8852BT:
394 		return 0x8852;
395 	case RTL8851B:
396 		return 0x8851;
397 	case RTL8922A:
398 	case RTL8922D:
399 		return 0x8922;
400 	default:
401 		return 0;
402 	}
403 }
404 
405 #define CASE_BTC_MLME_STATE(e) case MLME_##e: return #e
406 
407 static const char *id_to_mlme_state(u32 id)
408 {
409 	switch (id) {
410 	CASE_BTC_MLME_STATE(NO_LINK);
411 	CASE_BTC_MLME_STATE(LINKING);
412 	CASE_BTC_MLME_STATE(LINKED);
413 	default:
414 		return "unknown";
415 	}
416 }
417 
418 static char *chip_id_str(u32 id)
419 {
420 	switch (id) {
421 	case RTL8852A:
422 		return "RTL8852A";
423 	case RTL8852B:
424 		return "RTL8852B";
425 	case RTL8852C:
426 		return "RTL8852C";
427 	case RTL8852BT:
428 		return "RTL8852BT";
429 	case RTL8851B:
430 		return "RTL8851B";
431 	case RTL8922A:
432 		return "RTL8922A";
433 	case RTL8922D:
434 		return "RTL8922D";
435 	default:
436 		return "UNKNOWN";
437 	}
438 }
439 
440 struct rtw89_btc_btf_tlv {
441 	u8 type;
442 	u8 len;
443 	u8 val[];
444 } __packed;
445 
446 struct rtw89_btc_btf_tlv_v7 {
447 	u8 type;
448 	u8 ver;
449 	u8 len;
450 	u8 val[];
451 } __packed;
452 
453 enum btc_btf_set_report_en {
454 	RPT_EN_TDMA,
455 	RPT_EN_CYCLE,
456 	RPT_EN_MREG,
457 	RPT_EN_BT_VER_INFO,
458 	RPT_EN_BT_SCAN_INFO,
459 	RPT_EN_BT_DEVICE_INFO,
460 	RPT_EN_BT_AFH_MAP,
461 	RPT_EN_BT_AFH_MAP_LE,
462 	RPT_EN_BT_TX_PWR_LVL,
463 	RPT_EN_FW_STEP_INFO,
464 	RPT_EN_TEST,
465 	RPT_EN_WL_ALL,
466 	RPT_EN_BT_ALL,
467 	RPT_EN_ALL,
468 	RPT_EN_MONITER,
469 };
470 
471 struct rtw89_btc_btf_set_report_v1 {
472 	u8 fver;
473 	__le32 enable;
474 	__le32 para;
475 } __packed;
476 
477 struct rtw89_btc_btf_set_report_v8 {
478 	u8 type;
479 	u8 fver;
480 	u8 len;
481 	__le32 map;
482 } __packed;
483 
484 union rtw89_fbtc_rtp_ctrl {
485 	struct rtw89_btc_btf_set_report_v1 v1;
486 	struct rtw89_btc_btf_set_report_v8 v8;
487 };
488 
489 #define BTF_SET_SLOT_TABLE_VER 1
490 struct rtw89_btc_btf_set_slot_table {
491 	u8 fver;
492 	u8 tbl_num;
493 	struct rtw89_btc_fbtc_slot tbls[] __counted_by(tbl_num);
494 } __packed;
495 
496 struct rtw89_btc_btf_set_slot_table_v7 {
497 	u8 type;
498 	u8 ver;
499 	u8 len;
500 	struct rtw89_btc_fbtc_slot_v7 v7[CXST_MAX];
501 } __packed;
502 
503 struct rtw89_btc_btf_set_mon_reg_v1 {
504 	u8 fver;
505 	u8 reg_num;
506 	struct rtw89_btc_fbtc_mreg regs[] __counted_by(reg_num);
507 } __packed;
508 
509 struct rtw89_btc_btf_set_mon_reg_v7 {
510 	u8 type;
511 	u8 fver;
512 	u8 len;
513 	struct rtw89_btc_fbtc_mreg regs[] __counted_by(len);
514 } __packed;
515 
516 union rtw89_fbtc_set_mon_reg {
517 	struct rtw89_btc_btf_set_mon_reg_v1 v1;
518 	struct rtw89_btc_btf_set_mon_reg_v7 v7;
519 } __packed;
520 
521 enum btc_btf_set_cx_policy {
522 	CXPOLICY_TDMA = 0x0,
523 	CXPOLICY_SLOT = 0x1,
524 	CXPOLICY_TYPE = 0x2,
525 	CXPOLICY_MAX,
526 };
527 
528 enum btc_b2w_scoreboard {
529 	BTC_BSCB_ACT = BIT(0),
530 	BTC_BSCB_ON = BIT(1),
531 	BTC_BSCB_WHQL = BIT(2),
532 	BTC_BSCB_BT_S1 = BIT(3),
533 	BTC_BSCB_A2DP_ACT = BIT(4),
534 	BTC_BSCB_RFK_RUN = BIT(5),
535 	BTC_BSCB_RFK_REQ = BIT(6),
536 	BTC_BSCB_LPS = BIT(7),
537 	BTC_BSCB_BT_LNAB0 = BIT(8),
538 	BTC_BSCB_BT_LNAB1 = BIT(10),
539 	BTC_BSCB_WLRFK = BIT(11),
540 	BTC_BSCB_BT_HILNA = BIT(13),
541 	BTC_BSCB_BT_HILNA_56G = BIT(14),
542 	BTC_BSCB_CTCODE = BIT(15),
543 	BTC_BSCB_BT_CONNECT = BIT(16),
544 	BTC_BSCB_BT_CONNECT_56G = BIT(17),
545 	BTC_BSCB_BT_LNAB0_56G = BIT(18),
546 	BTC_BSCB_BT_LNAB1_56G = BIT(19),
547 	BTC_BSCB_BT_BACKOFF_LNA = BIT(21),
548 	BTC_BSCB_BT_15DOT4_TRX = BIT(22),
549 	BTC_BSCB_HID_ACT = BIT(23),
550 	BTC_BSCB_BT_15DOT4 = BIT(24),
551 	BTC_BSCB_BT_PROTECT = BIT(27),
552 	BTC_BSCB_PAN_ACT = BIT(28),
553 	BTC_BSCB_HFP_ACT = BIT(29),
554 	BTC_BSCB_PATCH_CODE = BIT(30),
555 	BTC_BSCB_ALL = GENMASK(30, 0),
556 };
557 
558 enum btc_phymap {
559 	BTC_PHY_0 = BIT(0),
560 	BTC_PHY_1 = BIT(1),
561 	BTC_PHY_ALL = BIT(0) | BIT(1),
562 };
563 
564 enum btc_cx_state_map {
565 	BTC_WIDLE = 0,
566 	BTC_WBUSY_BNOSCAN,
567 	BTC_WBUSY_BSCAN,
568 	BTC_WSCAN_BNOSCAN,
569 	BTC_WSCAN_BSCAN,
570 	BTC_WLINKING
571 };
572 
573 enum btc_ant_phase {
574 	BTC_ANT_WPOWERON = 0,
575 	BTC_ANT_WINIT,
576 	BTC_ANT_WONLY,
577 	BTC_ANT_WOFF,
578 	BTC_ANT_W2G,
579 	BTC_ANT_FDD,
580 	BTC_ANT_W25G,
581 	BTC_ANT_FREERUN,
582 	BTC_ANT_WRFK,
583 	BTC_ANT_WRFK2,
584 	BTC_ANT_PTA, /* for Multi-PTA, each hw-band has its own PTA */
585 	BTC_ANT_MAX
586 };
587 
588 enum btc_plt {
589 	BTC_PLT_NONE = 0,
590 	BTC_PLT_LTE_RX = BIT(0),
591 	BTC_PLT_GNT_BT_TX = BIT(1),
592 	BTC_PLT_GNT_BT_RX = BIT(2),
593 	BTC_PLT_GNT_WL = BIT(3),
594 	BTC_PLT_BT = BIT(1) | BIT(2),
595 	BTC_PLT_ALL = 0xf
596 };
597 
598 enum btc_cx_poicy_main_type {
599 	BTC_CXP_OFF = 0,
600 	BTC_CXP_OFFB,
601 	BTC_CXP_OFFE,
602 	BTC_CXP_FIX,
603 	BTC_CXP_PFIX,
604 	BTC_CXP_AUTO,
605 	BTC_CXP_PAUTO,
606 	BTC_CXP_AUTO2,
607 	BTC_CXP_PAUTO2,
608 	BTC_CXP_MANUAL,
609 	BTC_CXP_USERDEF0,
610 	BTC_CXP_MAIN_MAX
611 };
612 
613 enum btc_bslot_length {
614 	BTC_BSLOT_A2DP_HID = 60,
615 	BTC_BSLOT_A2DP = 50,
616 	BTC_BSLOT_A2DP_2 = 40,
617 	BTC_BSLOT_INQ = 30,
618 	BTC_BSLOT_IDLE = 20,
619 };
620 
621 enum btc_cx_poicy_type {
622 	/* TDMA off + pri: BT > WL */
623 	BTC_CXP_OFF_BT = (BTC_CXP_OFF << 8) | 0,
624 
625 	/* TDMA off + pri: WL > BT */
626 	BTC_CXP_OFF_WL = (BTC_CXP_OFF << 8) | 1,
627 
628 	/* TDMA off + pri: BT = WL */
629 	BTC_CXP_OFF_EQ0 = (BTC_CXP_OFF << 8) | 2,
630 
631 	/* TDMA off + pri: BT = WL > BT_Lo */
632 	BTC_CXP_OFF_EQ1 = (BTC_CXP_OFF << 8) | 3,
633 
634 	/* TDMA off + pri: WL = BT, BT_Rx > WL_Lo_Tx */
635 	BTC_CXP_OFF_EQ2 = (BTC_CXP_OFF << 8) | 4,
636 
637 	/* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
638 	BTC_CXP_OFF_EQ3 = (BTC_CXP_OFF << 8) | 5,
639 
640 	/* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
641 	BTC_CXP_OFF_EQ4 = (BTC_CXP_OFF << 8) | 6,
642 
643 	/* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
644 	BTC_CXP_OFF_EQ5 = (BTC_CXP_OFF << 8) | 7,
645 
646 	/* TDMA off + pri: BT_Hi > WL > BT_Lo */
647 	BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 8,
648 
649 	/* TDMA off + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */
650 	BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 9,
651 
652 	/* TDMA off + pri: WL_Hi-Tx > BT, BT_Hi > other-WL > BT_Lo */
653 	BTC_CXP_OFF_BWB2 = (BTC_CXP_OFF << 8) | 10,
654 
655 	/* TDMA off + pri: WL_Hi-Tx = BT */
656 	BTC_CXP_OFF_BWB3 = (BTC_CXP_OFF << 8) | 11,
657 
658 	/* TDMA off + pri: WL > BT, Block-BT*/
659 	BTC_CXP_OFF_WL2 = (BTC_CXP_OFF << 8) | 12,
660 
661 	/* TDMA off+Bcn-Protect + pri: BT_Hi > WL > BT_Lo */
662 	BTC_CXP_OFFB_BWB0 = (BTC_CXP_OFFB << 8) | 0,
663 
664 	/* TDMA off+Bcn-Protect + pri: BT_Hi_Tx = WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */
665 	BTC_CXP_OFFB_BWB1 = (BTC_CXP_OFFB << 8) | 1,
666 
667 	/* TDMA off+Bcn-Protect + pri: WL_Hi-Tx > BT, BT_Hi > other-WL > BT_Lo */
668 	BTC_CXP_OFFB_BWB2 = (BTC_CXP_OFFB << 8) | 2,
669 
670 	/* TDMA off+Bcn-Protect + pri: WL_Hi-Tx = BT*/
671 	BTC_CXP_OFFB_BWB3 = (BTC_CXP_OFFB << 8) | 3,
672 
673 	/* TDMA off+Bcn-Protect + pri: BT > WL*/
674 	BTC_CXP_OFFB_BWB4 = (BTC_CXP_OFFB << 8) | 4,
675 
676 	/* TDMA off + Ext-Ctrl + pri: default */
677 	BTC_CXP_OFFE_DEF = (BTC_CXP_OFFE << 8) | 0,
678 
679 	/* TDMA off + Ext-Ctrl + pri: E2G-slot block all BT */
680 	BTC_CXP_OFFE_DEF2 = (BTC_CXP_OFFE << 8) | 1,
681 
682 	/* TDMA off + Ext-Ctrl + pri: default */
683 	BTC_CXP_OFFE_2GBWISOB = (BTC_CXP_OFFE << 8) | 2,
684 
685 	/* TDMA off + Ext-Ctrl + pri: E2G-slot block all BT */
686 	BTC_CXP_OFFE_2GISOB = (BTC_CXP_OFFE << 8) | 3,
687 
688 	/* TDMA off + Ext-Ctrl + pri: E2G-slot WL > BT */
689 	BTC_CXP_OFFE_2GBWMIXB = (BTC_CXP_OFFE << 8) | 4,
690 
691 	/* TDMA off + Ext-Ctrl + pri: E2G/EBT-slot WL > BT */
692 	BTC_CXP_OFFE_WL = (BTC_CXP_OFFE << 8) | 5,
693 
694 	/* TDMA off + Ext-Ctrl + pri: default */
695 	BTC_CXP_OFFE_2GBWMIXB2 = (BTC_CXP_OFFE << 8) | 6,
696 
697 	/* TDMA Fix slot-0: W1:B1 = 30:30 */
698 	BTC_CXP_FIX_TD3030 = (BTC_CXP_FIX << 8) | 0,
699 
700 	/* TDMA Fix slot-1: W1:B1 = 50:50 */
701 	BTC_CXP_FIX_TD5050 = (BTC_CXP_FIX << 8) | 1,
702 
703 	/* TDMA Fix slot-2: W1:B1 = 20:30 */
704 	BTC_CXP_FIX_TD2030 = (BTC_CXP_FIX << 8) | 2,
705 
706 	/* TDMA Fix slot-3: W1:B1 = 40:10 */
707 	BTC_CXP_FIX_TD4010 = (BTC_CXP_FIX << 8) | 3,
708 
709 	/* TDMA Fix slot-4: W1:B1 = 70:10 */
710 	BTC_CXP_FIX_TD7010 = (BTC_CXP_FIX << 8) | 4,
711 
712 	/* TDMA Fix slot-5: W1:B1 = 20:60 */
713 	BTC_CXP_FIX_TD2060 = (BTC_CXP_FIX << 8) | 5,
714 
715 	/* TDMA Fix slot-6: W1:B1 = 30:60 */
716 	BTC_CXP_FIX_TD3060 = (BTC_CXP_FIX << 8) | 6,
717 
718 	/* TDMA Fix slot-7: W1:B1 = 20:80 */
719 	BTC_CXP_FIX_TD2080 = (BTC_CXP_FIX << 8) | 7,
720 
721 	/* TDMA Fix slot-8: W1:B1 = user-define */
722 	BTC_CXP_FIX_TDW1B1 = (BTC_CXP_FIX << 8) | 8,
723 
724 	/* TDMA Fix slot-9: W1:B1 = 40:10 */
725 	BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 9,
726 
727 	/* TDMA Fix slot-10: W1:B1 = 40:10 */
728 	BTC_CXP_FIX_TD4010ISO_DL = (BTC_CXP_FIX << 8) | 10,
729 
730 	/* TDMA Fix slot-11: W1:B1 = 40:10 */
731 	BTC_CXP_FIX_TD4010ISO_UL = (BTC_CXP_FIX << 8) | 11,
732 
733 	/* PS-TDMA Fix slot-0: W1:B1 = 30:30 */
734 	BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0,
735 
736 	/* PS-TDMA Fix slot-1: W1:B1 = 50:50 */
737 	BTC_CXP_PFIX_TD5050 = (BTC_CXP_PFIX << 8) | 1,
738 
739 	/* PS-TDMA Fix slot-2: W1:B1 = 20:30 */
740 	BTC_CXP_PFIX_TD2030 = (BTC_CXP_PFIX << 8) | 2,
741 
742 	/* PS-TDMA Fix slot-3: W1:B1 = 20:60 */
743 	BTC_CXP_PFIX_TD2060 = (BTC_CXP_PFIX << 8) | 3,
744 
745 	/* PS-TDMA Fix slot-4: W1:B1 = 30:70 */
746 	BTC_CXP_PFIX_TD3070 = (BTC_CXP_PFIX << 8) | 4,
747 
748 	/* PS-TDMA Fix slot-5: W1:B1 = 20:80 */
749 	BTC_CXP_PFIX_TD2080 = (BTC_CXP_PFIX << 8) | 5,
750 
751 	/* PS-TDMA Fix slot-6: W1:B1 = user-define */
752 	BTC_CXP_PFIX_TDW1B1 = (BTC_CXP_PFIX << 8) | 6,
753 
754 	/* TDMA Auto slot-0: W1:B1 = 50:200 */
755 	BTC_CXP_AUTO_TD50B1 = (BTC_CXP_AUTO << 8) | 0,
756 
757 	/* TDMA Auto slot-1: W1:B1 = 60:200 */
758 	BTC_CXP_AUTO_TD60B1 = (BTC_CXP_AUTO << 8) | 1,
759 
760 	/* TDMA Auto slot-2: W1:B1 = 20:200 */
761 	BTC_CXP_AUTO_TD20B1 = (BTC_CXP_AUTO << 8) | 2,
762 
763 	/* TDMA Auto slot-3: W1:B1 = user-define */
764 	BTC_CXP_AUTO_TDW1B1 = (BTC_CXP_AUTO << 8) | 3,
765 
766 	/* PS-TDMA Auto slot-0: W1:B1 = 50:200 */
767 	BTC_CXP_PAUTO_TD50B1 = (BTC_CXP_PAUTO << 8) | 0,
768 
769 	/* PS-TDMA Auto slot-1: W1:B1 = 60:200 */
770 	BTC_CXP_PAUTO_TD60B1 = (BTC_CXP_PAUTO << 8) | 1,
771 
772 	/* PS-TDMA Auto slot-2: W1:B1 = 20:200 */
773 	BTC_CXP_PAUTO_TD20B1 = (BTC_CXP_PAUTO << 8) | 2,
774 
775 	/* PS-TDMA Auto slot-3: W1:B1 = user-define */
776 	BTC_CXP_PAUTO_TDW1B1 = (BTC_CXP_PAUTO << 8) | 3,
777 
778 	/* TDMA Auto slot2-0: W1:B4 = 30:50 */
779 	BTC_CXP_AUTO2_TD3050 = (BTC_CXP_AUTO2 << 8) | 0,
780 
781 	/* TDMA Auto slot2-1: W1:B4 = 30:70 */
782 	BTC_CXP_AUTO2_TD3070 = (BTC_CXP_AUTO2 << 8) | 1,
783 
784 	/* TDMA Auto slot2-2: W1:B4 = 50:50 */
785 	BTC_CXP_AUTO2_TD5050 = (BTC_CXP_AUTO2 << 8) | 2,
786 
787 	/* TDMA Auto slot2-3: W1:B4 = 60:60 */
788 	BTC_CXP_AUTO2_TD6060 = (BTC_CXP_AUTO2 << 8) | 3,
789 
790 	/* TDMA Auto slot2-4: W1:B4 = 20:80 */
791 	BTC_CXP_AUTO2_TD2080 = (BTC_CXP_AUTO2 << 8) | 4,
792 
793 	/* TDMA Auto slot2-5: W1:B4 = user-define */
794 	BTC_CXP_AUTO2_TDW1B4 = (BTC_CXP_AUTO2 << 8) | 5,
795 
796 	/* PS-TDMA Auto slot2-0: W1:B4 = 30:50 */
797 	BTC_CXP_PAUTO2_TD3050 = (BTC_CXP_PAUTO2 << 8) | 0,
798 
799 	/* PS-TDMA Auto slot2-1: W1:B4 = 30:70 */
800 	BTC_CXP_PAUTO2_TD3070 = (BTC_CXP_PAUTO2 << 8) | 1,
801 
802 	/* PS-TDMA Auto slot2-2: W1:B4 = 50:50 */
803 	BTC_CXP_PAUTO2_TD5050 = (BTC_CXP_PAUTO2 << 8) | 2,
804 
805 	/* PS-TDMA Auto slot2-3: W1:B4 = 60:60 */
806 	BTC_CXP_PAUTO2_TD6060 = (BTC_CXP_PAUTO2 << 8) | 3,
807 
808 	/* PS-TDMA Auto slot2-4: W1:B4 = 20:80 */
809 	BTC_CXP_PAUTO2_TD2080 = (BTC_CXP_PAUTO2 << 8) | 4,
810 
811 	/* PS-TDMA Auto slot2-5: W1:B4 = user-define */
812 	BTC_CXP_PAUTO2_TDW1B4 = (BTC_CXP_PAUTO2 << 8) | 5,
813 
814 	BTC_CXP_MAX = 0xffff
815 };
816 
817 enum btc_wl_rfk_result {
818 	BTC_WRFK_REJECT = 0,
819 	BTC_WRFK_ALLOW = 1,
820 };
821 
822 enum btc_coex_info_map_en {
823 	BTC_COEX_INFO_CX = BIT(0),
824 	BTC_COEX_INFO_WL = BIT(1),
825 	BTC_COEX_INFO_BT = BIT(2),
826 	BTC_COEX_INFO_DM = BIT(3),
827 	BTC_COEX_INFO_MREG = BIT(4),
828 	BTC_COEX_INFO_SUMMARY = BIT(5),
829 	BTC_COEX_INFO_ALL = GENMASK(7, 0),
830 };
831 
832 #define BTC_CXP_MASK GENMASK(15, 8)
833 
834 enum btc_w2b_scoreboard {
835 	BTC_WSCB_ACTIVE = BIT(0),
836 	BTC_WSCB_ON = BIT(1),
837 	BTC_WSCB_SCAN = BIT(2),
838 	BTC_WSCB_UNDERTEST = BIT(3),
839 	BTC_WSCB_RXGAIN = BIT(4),
840 	BTC_WSCB_5GHICH = BIT(6),
841 	BTC_WSCB_WLBUSY = BIT(7),
842 	BTC_WSCB_EXTFEM = BIT(8),
843 	BTC_WSCB_TDMA = BIT(9),
844 	BTC_WSCB_FIX2M = BIT(10),
845 	BTC_WSCB_WLRFK = BIT(11),
846 	BTC_WSCB_RXSCAN_PRI = BIT(12),
847 	BTC_WSCB_BT_HILNA = BIT(13),
848 	BTC_WSCB_BTLOG = BIT(14),
849 	BTC_WSCB_CTCODE = BIT(15),
850 	BTC_WSCB_RXGAIN_56G = BIT(16),
851 	BTC_WSCB_BT_HILNA_56G = BIT(17),
852 	BTC_WSCB_BT_BACKOFF_LNA = BIT(18),
853 	BTC_WSCB_ALL = GENMASK(23, 0),
854 };
855 
856 enum btc_wl_link_mode_v0 {
857 	BTC_WLINK_V0_NOLINK = 0x0,
858 	BTC_WLINK_V0_2G_STA,
859 	BTC_WLINK_V0_2G_AP,
860 	BTC_WLINK_V0_2G_GO,
861 	BTC_WLINK_V0_2G_GC,
862 	BTC_WLINK_V0_2G_SCC,
863 	BTC_WLINK_V0_2G_MCC,
864 	BTC_WLINK_V0_25G_MCC,
865 	BTC_WLINK_V0_25G_DBCC,
866 	BTC_WLINK_V0_5G,
867 	BTC_WLINK_V0_2G_NAN,
868 	BTC_WLINK_V0_OTHER,
869 	BTC_WLINK_V0_MAX
870 };
871 
872 enum btc_wl_link_mode_v1 {
873 	BTC_WLINK_NOLINK = 0x0,
874 	BTC_WLINK_STA,
875 	BTC_WLINK_AP,
876 	BTC_WLINK_GO,
877 	BTC_WLINK_GC,
878 	BTC_WLINK_SCC,
879 	BTC_WLINK_SB_MCC,
880 	BTC_WLINK_DB_MCC, /* 2+0/0+2 Dual-RF-band MCC */
881 	BTC_WLINK_MAX
882 };
883 
884 #define CASE_BTC_WL_LINK_MODE(e) case BTC_WLINK_## e: return #e
885 
886 static const char *id_to_linkmode(u8 id)
887 {
888 	switch (id) {
889 	CASE_BTC_WL_LINK_MODE(NOLINK);
890 	CASE_BTC_WL_LINK_MODE(STA);
891 	CASE_BTC_WL_LINK_MODE(AP);
892 	CASE_BTC_WL_LINK_MODE(GO);
893 	CASE_BTC_WL_LINK_MODE(GC);
894 	CASE_BTC_WL_LINK_MODE(SCC);
895 	CASE_BTC_WL_LINK_MODE(SB_MCC);
896 	CASE_BTC_WL_LINK_MODE(DB_MCC);
897 	default:
898 		return "unknown";
899 	}
900 }
901 
902 enum btc_wl_mrole_type {
903 	BTC_WLMROLE_NONE = 0x0,
904 	BTC_WLMROLE_STA_GC,
905 	BTC_WLMROLE_STA_GC_NOA,
906 	BTC_WLMROLE_STA_GO,
907 	BTC_WLMROLE_STA_GO_NOA,
908 	BTC_WLMROLE_STA_STA,
909 	BTC_WLMROLE_MAX
910 };
911 
912 enum btc_bt_hid_type {
913 	BTC_HID_218 = BIT(0),
914 	BTC_HID_418 = BIT(1),
915 	BTC_HID_BLE = BIT(2),
916 	BTC_HID_RCU = BIT(3),
917 	BTC_HID_RCU_VOICE = BIT(4),
918 	BTC_HID_OTHER_LEGACY = BIT(5)
919 };
920 
921 enum btc_reset_module {
922 	BTC_RESET_CX = BIT(0),
923 	BTC_RESET_DM = BIT(1),
924 	BTC_RESET_CTRL = BIT(2),
925 	BTC_RESET_CXDM = BIT(0) | BIT(1),
926 	BTC_RESET_BTINFO = BIT(3),
927 	BTC_RESET_MDINFO = BIT(4),
928 	BTC_RESET_BT_PSD_DM = BIT(5),
929 	BTC_RESET_BTINFO2 = BIT(6),
930 	BTC_RESET_ALL =  GENMASK(7, 0),
931 };
932 
933 enum btc_gnt_state {
934 	BTC_GNT_HW	= 0,
935 	BTC_GNT_SW_LO,
936 	BTC_GNT_SW_HI,
937 	BTC_GNT_MAX,
938 
939 	BTC_GNT_SET_SKIP = 0xff,
940 };
941 
942 enum btc_ctr_path {
943 	BTC_CTRL_BY_BT = 0,
944 	BTC_CTRL_BY_WL
945 };
946 
947 enum btc_wlact_state {
948 	BTC_WLACT_HW = 0,
949 	BTC_WLACT_SW_LO,
950 	BTC_WLACT_SW_HI,
951 	BTC_WLACT_MAX,
952 };
953 
954 enum btc_wl_max_tx_time {
955 	BTC_MAX_TX_TIME_L1 = 500,
956 	BTC_MAX_TX_TIME_L2 = 1000,
957 	BTC_MAX_TX_TIME_L3 = 2000,
958 	BTC_MAX_TX_TIME_DEF = 5280
959 };
960 
961 enum btc_wl_max_tx_retry {
962 	BTC_MAX_TX_RETRY_L1 = 7,
963 	BTC_MAX_TX_RETRY_L2 = 15,
964 	BTC_MAX_TX_RETRY_DEF = 31,
965 };
966 
967 enum btc_reason_and_action {
968 	BTC_RSN_NONE,
969 	BTC_RSN_NTFY_INIT,
970 	BTC_RSN_NTFY_SWBAND,
971 	BTC_RSN_NTFY_WL_STA,
972 	BTC_RSN_NTFY_RADIO_STATE,
973 	BTC_RSN_UPDATE_BT_SCBD,
974 	BTC_RSN_NTFY_WL_RFK,
975 	BTC_RSN_UPDATE_BT_INFO,
976 	BTC_RSN_NTFY_SCAN_START,
977 	BTC_RSN_NTFY_SCAN_FINISH,
978 	BTC_RSN_NTFY_SPECIFIC_PACKET,
979 	BTC_RSN_NTFY_POWEROFF,
980 	BTC_RSN_NTFY_ROLE_INFO,
981 	BTC_RSN_CMD_SET_COEX,
982 	BTC_RSN_ACT1_WORK,
983 	BTC_RSN_BT_DEVINFO_WORK,
984 	BTC_RSN_RFK_CHK_WORK,
985 	BTC_RSN_UPDATE_BT_LEAUDINFO,
986 	BTC_RSN_NUM,
987 	BTC_ACT_NONE = 100,
988 	BTC_ACT_WL_ONLY,
989 	BTC_ACT_WL_5G,
990 	BTC_ACT_WL_OTHER,
991 	BTC_ACT_WL_IDLE,
992 	BTC_ACT_WL_NC,
993 	BTC_ACT_WL_RFK,
994 	BTC_ACT_WL_INIT,
995 	BTC_ACT_WL_OFF,
996 	BTC_ACT_FREERUN,
997 	BTC_ACT_BT_WHQL,
998 	BTC_ACT_BT_RFK,
999 	BTC_ACT_BT_OFF,
1000 	BTC_ACT_BT_IDLE,
1001 	BTC_ACT_BT_HFP,
1002 	BTC_ACT_BT_HID,
1003 	BTC_ACT_BT_A2DP,
1004 	BTC_ACT_BT_A2DPSINK,
1005 	BTC_ACT_BT_PAN,
1006 	BTC_ACT_BT_A2DP_HID,
1007 	BTC_ACT_BT_A2DP_PAN,
1008 	BTC_ACT_BT_PAN_HID,
1009 	BTC_ACT_BT_A2DP_PAN_HID,
1010 	BTC_ACT_BT_BIS,
1011 	BTC_ACT_BT_CIS,
1012 	BTC_ACT_WL_25G_MCC,
1013 	BTC_ACT_WL_2G_MCC,
1014 	BTC_ACT_WL_2G_SCC,
1015 	BTC_ACT_WL_2G_AP,
1016 	BTC_ACT_WL_2G_GO,
1017 	BTC_ACT_WL_2G_GC,
1018 	BTC_ACT_WL_2G_NAN,
1019 	BTC_ACT_LAST,
1020 	BTC_ACT_NUM = BTC_ACT_LAST - BTC_ACT_NONE,
1021 	BTC_ACT_EXT_BIT = BIT(14),
1022 	BTC_POLICY_EXT_BIT = BIT(15),
1023 };
1024 
1025 #define BTC_FREERUN_ANTISO_MIN 30
1026 #define BTC_TDMA_BTHID_MAX 2
1027 #define BTC_BLINK_NOCONNECT 0
1028 #define BTC_B1_MAX 250 /* unit ms */
1029 
1030 static void _run_coex(struct rtw89_dev *rtwdev,
1031 		      enum btc_reason_and_action reason);
1032 static void _write_scbd(struct rtw89_dev *rtwdev, u8 bid, u32 val, bool state);
1033 static u8 _sned_h2c_w2bscbd(struct rtw89_dev *rtwdev, bool force_exec, u8 bid);
1034 static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid, bool is_c2h);
1035 static void _update_sdm_map(struct rtw89_dev *rtwdev);
1036 static const char *id_to_h2c(u32 id);
1037 
1038 static void _reset_h2c_macro(struct rtw89_btc *btc)
1039 {
1040 	btc->hbuf_len = 0;
1041 	btc->hbuf_cnt = 0;
1042 	memset(btc->hbuf, 0, BTC_H2C_MAXLEN);
1043 }
1044 
1045 static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
1046 			void *param, u16 len)
1047 {
1048 	struct rtw89_btc *btc = &rtwdev->btc;
1049 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
1050 	struct rtw89_btc_cx *cx = &btc->cx;
1051 	struct rtw89_btc_wl_info *wl = &cx->wl;
1052 	struct rtw89_btc_dm *dm = &btc->dm;
1053 	u8 h2c_func_mask, bid = BTC_BT_1ST;
1054 	u8 *buf = param;
1055 	int ret;
1056 
1057 	if (len > BTC_H2C_MAXLEN || len == 0) {
1058 		btc->fwinfo.cnt_h2c_fail++;
1059 		dm->error.map.h2c_buffer_over = true;
1060 		return -EINVAL;
1061 	} else if (!wl->status.map.init_ok) {
1062 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1063 			    "[BTC], %s(): return by btc not init!!\n", __func__);
1064 		pfwinfo->cnt_h2c_fail++;
1065 		return -EINVAL;
1066 	} else if ((wl->status.map.rf_off_pre == BTC_LPS_RF_OFF &&
1067 		    wl->status.map.rf_off == BTC_LPS_RF_OFF) ||
1068 		   (wl->status.map.lps_pre == BTC_LPS_RF_OFF &&
1069 		    wl->status.map.lps == BTC_LPS_RF_OFF)) {
1070 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1071 			    "[BTC], %s(): return by wl off!!\n", __func__);
1072 		pfwinfo->cnt_h2c_fail++;
1073 		return -EINVAL;
1074 	}
1075 
1076 	h2c_func_mask = h2c_func & (~BT_H2C_FUNC_BT2ND);
1077 	if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT)
1078 		bid = !!(h2c_func & BT_H2C_FUNC_BT2ND);
1079 
1080 	if (btc->io_oflld_type != BTC_IO_OFLD_BTC_H2C || btc->cli_h2c_cmd ||
1081 	    h2c_func_mask == SET_H2C_MACRO ||
1082 	    (h2c_func_mask == SET_DRV_INFO && buf[0] == CXDRVINFO_TRX) ||
1083 	    (h2c_func_mask == SET_IOFLD_SCBD && dm->scbd_write_instant) ||
1084 	    h2c_func_mask == SET_BT_LNA_CONSTRAIN) {
1085 		h2c_class = BTFC_SET;
1086 
1087 		ret = rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func,
1088 						buf, len, false, true);
1089 
1090 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1091 			    "[BTC], %s():class=%d, bt%d-func=%s, len=%d\n",
1092 			    __func__, h2c_class, bid,
1093 			    id_to_h2c(h2c_func_mask), len);
1094 
1095 		if (h2c_func_mask == SET_H2C_MACRO) {
1096 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
1097 				    "[BTC], %s():Send H2C-MACRO cnt=%d, len=%d\n",
1098 				    __func__, btc->hbuf_cnt, btc->hbuf_len);
1099 			_reset_h2c_macro(btc); /* clear H2C MACRO buffer */
1100 		}
1101 
1102 		if (ret != 0) { /* Send H2C fail */
1103 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
1104 				    "[BTC], %s():return by rtw_hal_mac_send_h2c\n",
1105 				    __func__);
1106 			btc->fwinfo.cnt_h2c_fail++;
1107 			return 0;
1108 		}
1109 
1110 		btc->fwinfo.cnt_h2c++;
1111 		return 0;
1112 	} else { /* Fill H2C MACRO buffer(TLV format) temporarily */
1113 		if (btc->hbuf_cnt == 0)
1114 			_reset_h2c_macro(btc);
1115 
1116 		/* Type:1 byte, Length:2 Bytes, Data:len bytes */
1117 		if (btc->hbuf_len + len + 3 > BTC_H2C_MAXLEN) {
1118 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
1119 				    "[BTC], %s():return by MACRO buf full(%d)\n",
1120 				    __func__, btc->hbuf_len + len + 3);
1121 			btc->fwinfo.cnt_h2c_fail++;
1122 			return 0;
1123 		}
1124 
1125 		btc->hbuf[btc->hbuf_len] = h2c_func;
1126 		btc->hbuf[btc->hbuf_len + 1] = len & GENMASK(7, 0);
1127 		btc->hbuf[btc->hbuf_len + 2] = (len & GENMASK(15, 8)) >> 8;
1128 
1129 		memcpy(&btc->hbuf[btc->hbuf_len + 3], buf, len);
1130 		btc->hbuf_len = btc->hbuf_len + len + 3;
1131 		btc->hbuf_cnt++;
1132 
1133 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1134 			    "[BTC], %s():Buffer H2C-MACRO cnt=%d/bt%d-func=%s/len=%d\n",
1135 			    __func__, btc->hbuf_cnt, bid,
1136 			    id_to_h2c(h2c_func_mask), len);
1137 
1138 		h2c_func = SET_H2C_MACRO;
1139 		buf = btc->hbuf;
1140 		len = btc->hbuf_len;
1141 	}
1142 
1143 	ret = rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, buf, len,
1144 					false, true);
1145 	if (ret)
1146 		pfwinfo->cnt_h2c_fail++;
1147 	else
1148 		pfwinfo->cnt_h2c++;
1149 
1150 	if (h2c_func == SET_H2C_MACRO)
1151 		_reset_h2c_macro(btc);
1152 
1153 	return ret;
1154 }
1155 
1156 #define BTC_DEFAULT_SIR_THRES 51 /* dB, BT Pin - This = TDD/FDD swtch thres */
1157 #define BTC_FDDR_TP_SETUP_TIME 1 /* in second */
1158 #define BTC_FDDR_TP_HOLD_TIME 3 /* in second */
1159 #define BTC_FDDR_RX_LOW_RATE_THRES 4  /* low rate for TDD swotch */
1160 
1161 static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
1162 {
1163 	struct rtw89_btc *btc = &rtwdev->btc;
1164 	struct rtw89_btc_cx *cx = &btc->cx;
1165 	const struct rtw89_btc_ver *ver = btc->ver;
1166 	struct rtw89_btc_bt_info *bt0 = &cx->bt0;
1167 	struct rtw89_btc_bt_info *bt1 = &cx->bt1;
1168 	u8 i;
1169 
1170 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
1171 
1172 	if (type & BTC_RESET_CX) {
1173 		memset(cx, 0, sizeof(*cx));
1174 		cx->bt_ext.max_tx_pwr = RTW89_BTC_BT_DEF_LE_TX_PWR;
1175 		cx->bt_ext.ant_iso_to_wl = RTW89_BTC_DEFAULT_ANISO;
1176 	}
1177 
1178 	if (type & BTC_RESET_BTINFO) {/* only for BT enable */
1179 		memset(bt0, 0, sizeof(*bt0));
1180 		bt0->link_info.bt_txpwr_desc.br_dbm = RTW89_BTC_BT_DEF_BR_TX_PWR;
1181 		bt0->link_info_56g.bt_txpwr_desc.br_dbm = RTW89_BTC_BT_DEF_BR_TX_PWR;
1182 		bt0->link_info.bt_txpwr_desc.le_dbm = RTW89_BTC_BT_DEF_LE_TX_PWR;
1183 		bt0->link_info_56g.bt_txpwr_desc.le_dbm = RTW89_BTC_BT_DEF_LE_TX_PWR;
1184 		bt0->ant_iso_to_wl = RTW89_BTC_DEFAULT_ANISO;
1185 	} else if (type & BTC_RESET_BTINFO2) {
1186 		memset(bt1, 0, sizeof(*bt1));
1187 		bt1->link_info.bt_txpwr_desc.br_dbm = RTW89_BTC_BT_DEF_BR_TX_PWR;
1188 		bt1->link_info_56g.bt_txpwr_desc.br_dbm = RTW89_BTC_BT_DEF_BR_TX_PWR;
1189 		bt1->link_info.bt_txpwr_desc.le_dbm = RTW89_BTC_BT_DEF_LE_TX_PWR;
1190 		bt1->link_info_56g.bt_txpwr_desc.le_dbm = RTW89_BTC_BT_DEF_LE_TX_PWR;
1191 		bt1->ant_iso_to_wl = RTW89_BTC_DEFAULT_ANISO;
1192 	}
1193 
1194 	if (type & BTC_RESET_CTRL) {
1195 		memset(&btc->ctrl, 0, sizeof(btc->ctrl));
1196 		btc->ctrl.trace_step = FCXDEF_STEP;
1197 	}
1198 
1199 	/* Init Coex variables that are not zero */
1200 	if (type & BTC_RESET_DM) {
1201 		memset(&btc->dm, 0, sizeof(btc->dm));
1202 
1203 		/* set the slot_now table to original */
1204 		btc->dm.tdma_now = t_def[CXTD_OFF];
1205 		btc->dm.tdma = t_def[CXTD_OFF];
1206 		if (ver->fcxslots >= 2) {
1207 			for (i = 0; i < ARRAY_SIZE(s_def); i++) {
1208 				btc->dm.slot.v7[i].dur = s_def[i].dur;
1209 				btc->dm.slot.v7[i].cxtype = s_def[i].cxtype;
1210 				btc->dm.slot.v7[i].cxtbl = s_def[i].cxtbl;
1211 			}
1212 			memcpy(&btc->dm.slot_now.v7, &btc->dm.slot.v7,
1213 			       sizeof(btc->dm.slot_now.v7));
1214 		} else {
1215 			memcpy(&btc->dm.slot_now.v1, s_def,
1216 			       sizeof(btc->dm.slot_now.v1));
1217 			memcpy(&btc->dm.slot.v1, s_def,
1218 			       sizeof(btc->dm.slot.v1));
1219 		}
1220 
1221 		btc->policy_len = 0;
1222 		btc->bt_req_len[RTW89_PHY_0] = 0;
1223 		btc->bt_req_len[RTW89_PHY_1] = 0;
1224 		btc->hubmsg_cnt = 0;
1225 
1226 		btc->dm.coex_info_map = BTC_COEX_INFO_ALL;
1227 		btc->dm.wl_tx_limit.tx_time = BTC_MAX_TX_TIME_DEF;
1228 		btc->dm.wl_tx_limit.tx_retry = BTC_MAX_TX_RETRY_DEF;
1229 		btc->dm.bt_slot_flood = BTC_B1_MAX;
1230 		btc->dm.sir_thres = BTC_DEFAULT_SIR_THRES;
1231 		btc->dm.fddr_info.tp_setup_time = BTC_FDDR_TP_SETUP_TIME;
1232 		btc->dm.fddr_info.tp_hold_time = BTC_FDDR_TP_HOLD_TIME;
1233 		btc->dm.fddr_info.wl_rx_rate_thres = BTC_FDDR_RX_LOW_RATE_THRES;
1234 		btc->dm.fddt_info.type = BTC_FDDT_TYPE_AUTO;
1235 
1236 		btc->dm.wl_pre_agc_rb = BTC_PREAGC_NOTFOUND;
1237 		btc->dm.wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_NOTFOUND;
1238 	}
1239 
1240 	if (type & BTC_RESET_MDINFO) {
1241 		memset(&btc->mdinfo, 0, sizeof(btc->mdinfo));
1242 		btc->mdinfo.ant.isolation = RTW89_BTC_DEFAULT_ANISO;
1243 	}
1244 }
1245 
1246 static u8 _search_reg_index(struct rtw89_dev *rtwdev, u8 mreg_num, u16 reg_type, u32 target)
1247 {
1248 	const struct rtw89_chip_info *chip = rtwdev->chip;
1249 	u8 i;
1250 
1251 	for (i = 0; i < mreg_num; i++)
1252 		if (le16_to_cpu(chip->mon_reg[i].type) == reg_type &&
1253 		    le32_to_cpu(chip->mon_reg[i].offset) == target) {
1254 			return i;
1255 	}
1256 	return BTC_REG_NOTFOUND;
1257 }
1258 
1259 static void _get_reg_status(struct rtw89_dev *rtwdev, u8 type, u8 *val)
1260 {
1261 	struct rtw89_btc *btc = &rtwdev->btc;
1262 	const struct rtw89_btc_ver *ver = btc->ver;
1263 	struct rtw89_btc_module *md = &btc->mdinfo;
1264 	union rtw89_btc_fbtc_mreg_val *pmreg;
1265 	u32 pre_agc_addr = R_BTC_BB_PRE_AGC_S1;
1266 	u32 reg_val;
1267 	u8 idx;
1268 
1269 	if (btc->btg_pos == RF_PATH_A)
1270 		pre_agc_addr = R_BTC_BB_PRE_AGC_S0;
1271 
1272 	switch (type) {
1273 	case BTC_CSTATUS_TXDIV_POS:
1274 		if (md->bt0_sw_type == BTC_SWITCH_INTERNAL)
1275 			*val = BTC_ANT_DIV_MAIN;
1276 		break;
1277 	case BTC_CSTATUS_RXDIV_POS:
1278 		if (md->bt0_sw_type == BTC_SWITCH_INTERNAL)
1279 			*val = BTC_ANT_DIV_MAIN;
1280 		break;
1281 	case BTC_CSTATUS_BB_GNT_MUX:
1282 		reg_val = rtw89_phy_read32(rtwdev, R_BTC_BB_BTG_RX);
1283 		*val = !(reg_val & B_BTC_BB_GNT_MUX);
1284 		break;
1285 	case BTC_CSTATUS_BB_GNT_MUX_MON:
1286 		if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
1287 			return;
1288 
1289 		pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
1290 		if (ver->fcxmreg == 1) {
1291 			idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
1292 						REG_BB, R_BTC_BB_BTG_RX);
1293 			if (idx == BTC_REG_NOTFOUND) {
1294 				*val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
1295 			} else {
1296 				reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]);
1297 				*val = !(reg_val & B_BTC_BB_GNT_MUX);
1298 			}
1299 		} else if (ver->fcxmreg == 2) {
1300 			idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
1301 						REG_BB, R_BTC_BB_BTG_RX);
1302 			if (idx == BTC_REG_NOTFOUND) {
1303 				*val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
1304 			} else {
1305 				reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]);
1306 				*val = !(reg_val & B_BTC_BB_GNT_MUX);
1307 			}
1308 		}
1309 		break;
1310 	case BTC_CSTATUS_BB_PRE_AGC:
1311 		reg_val = rtw89_phy_read32(rtwdev, pre_agc_addr);
1312 		reg_val &= B_BTC_BB_PRE_AGC_MASK;
1313 		*val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
1314 		break;
1315 	case BTC_CSTATUS_BB_PRE_AGC_MON:
1316 		if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
1317 			return;
1318 
1319 		pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
1320 		if (ver->fcxmreg == 1) {
1321 			idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
1322 						REG_BB, pre_agc_addr);
1323 			if (idx == BTC_REG_NOTFOUND) {
1324 				*val = BTC_PREAGC_NOTFOUND;
1325 			} else {
1326 				reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]) &
1327 					  B_BTC_BB_PRE_AGC_MASK;
1328 				*val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
1329 			}
1330 		} else if (ver->fcxmreg == 2) {
1331 			idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
1332 						REG_BB, pre_agc_addr);
1333 			if (idx == BTC_REG_NOTFOUND) {
1334 				*val = BTC_PREAGC_NOTFOUND;
1335 			} else {
1336 				reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]) &
1337 					  B_BTC_BB_PRE_AGC_MASK;
1338 				*val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
1339 			}
1340 		}
1341 		break;
1342 	default:
1343 		break;
1344 	}
1345 }
1346 
1347 #define BTC_RPT_HDR_SIZE 3
1348 #define BTC_CHK_WLSLOT_DRIFT_MAX 15
1349 #define BTC_CHK_BTSLOT_DRIFT_MAX 15
1350 #define BTC_CHK_HANG_MAX 3
1351 #define BTC_NULLTX_CHK_PERIOD 100
1352 #define BTC_NULLTX_FAIL_TH 8
1353 
1354 static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt)
1355 {
1356 	struct rtw89_btc *btc = &rtwdev->btc;
1357 	union rtw89_btc_fbtc_cynullsta_info *ns = &btc->fwinfo.rpt_fbtc_nullsta.finfo;
1358 	union rtw89_btc_fbtc_cysta_info *pcysta = &btc->fwinfo.rpt_fbtc_cysta.finfo;
1359 	struct rtw89_btc_cx *cx = &btc->cx;
1360 	struct rtw89_btc_bt_info *bt = &cx->bt0;
1361 	struct rtw89_btc_bt_a2dp_desc *a2dp = &bt->link_info.a2dp_desc;
1362 	struct rtw89_btc_wl_info *wl = &cx->wl;
1363 	struct rtw89_btc_dm *dm = &btc->dm;
1364 	const struct rtw89_btc_ver *ver = btc->ver;
1365 	u32 empty_streak = 0, empty_streak_max = 0;
1366 	u32 slot_pair, c_begin, c_end, cycle, s_id;
1367 	u32 tx_cnt, late, ok;
1368 
1369 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1370 		    "[BTC], %s(): type:%d cnt:%d\n",
1371 		    __func__, type, cnt);
1372 
1373 	switch (type) {
1374 	case BTC_DCNT_WL_FW_VER_MATCH:
1375 		if ((wl->ver_info.fw_coex & 0xffff0000) !=
1376 		     rtwdev->chip->wlcx_desired) {
1377 			wl->fw_ver_mismatch = true;
1378 			dm->error.map.wl_ver_mismatch = true;
1379 		} else {
1380 			wl->fw_ver_mismatch = false;
1381 			dm->error.map.wl_ver_mismatch = false;
1382 		}
1383 		break;
1384 	case BTC_DCNT_RPT_HANG:
1385 		if (dm->cnt_dm[BTC_DCNT_RPT] == cnt && btc->fwinfo.rpt_en_map)
1386 			dm->cnt_dm[BTC_DCNT_RPT_HANG]++;
1387 		else
1388 			dm->cnt_dm[BTC_DCNT_RPT_HANG] = 0;
1389 
1390 		if (dm->cnt_dm[BTC_DCNT_RPT_HANG] >= BTC_CHK_HANG_MAX)
1391 			dm->error.map.wl_fw_hang = true;
1392 		else
1393 			dm->error.map.wl_fw_hang = false;
1394 
1395 		dm->cnt_dm[BTC_DCNT_RPT] = cnt;
1396 		break;
1397 	case BTC_DCNT_CYCLE_HANG:
1398 		if (dm->cnt_dm[BTC_DCNT_CYCLE] == cnt &&
1399 		    (dm->tdma_now.type != CXTDMA_OFF ||
1400 		     dm->tdma_now.ext_ctrl == CXECTL_EXT))
1401 			dm->cnt_dm[BTC_DCNT_CYCLE_HANG]++;
1402 		else
1403 			dm->cnt_dm[BTC_DCNT_CYCLE_HANG] = 0;
1404 
1405 		if (dm->cnt_dm[BTC_DCNT_CYCLE_HANG] >= BTC_CHK_HANG_MAX)
1406 			dm->error.map.cycle_hang = true;
1407 		else
1408 			dm->error.map.cycle_hang = false;
1409 
1410 		dm->cnt_dm[BTC_DCNT_CYCLE] = cnt;
1411 		break;
1412 	case BTC_DCNT_W1_HANG:
1413 		if (dm->cnt_dm[BTC_DCNT_W1] == cnt &&
1414 		    dm->tdma_now.type != CXTDMA_OFF)
1415 			dm->cnt_dm[BTC_DCNT_W1_HANG]++;
1416 		else
1417 			dm->cnt_dm[BTC_DCNT_W1_HANG] = 0;
1418 
1419 		if (dm->cnt_dm[BTC_DCNT_W1_HANG] >= BTC_CHK_HANG_MAX)
1420 			dm->error.map.w1_hang = true;
1421 		else
1422 			dm->error.map.w1_hang = false;
1423 
1424 		dm->cnt_dm[BTC_DCNT_W1] = cnt;
1425 		break;
1426 	case BTC_DCNT_B1_HANG:
1427 		if (dm->cnt_dm[BTC_DCNT_B1] == cnt &&
1428 		    dm->tdma_now.type != CXTDMA_OFF)
1429 			dm->cnt_dm[BTC_DCNT_B1_HANG]++;
1430 		else
1431 			dm->cnt_dm[BTC_DCNT_B1_HANG] = 0;
1432 
1433 		if (dm->cnt_dm[BTC_DCNT_B1_HANG] >= BTC_CHK_HANG_MAX)
1434 			dm->error.map.b1_hang = true;
1435 		else
1436 			dm->error.map.b1_hang = false;
1437 
1438 		dm->cnt_dm[BTC_DCNT_B1] = cnt;
1439 		break;
1440 	case BTC_DCNT_E2G_HANG:
1441 		if (dm->cnt_dm[BTC_DCNT_E2G] == cnt &&
1442 		    dm->tdma_now.ext_ctrl == CXECTL_EXT)
1443 			dm->cnt_dm[BTC_DCNT_E2G_HANG]++;
1444 		else
1445 			dm->cnt_dm[BTC_DCNT_E2G_HANG] = 0;
1446 
1447 		if (dm->cnt_dm[BTC_DCNT_E2G_HANG] >= BTC_CHK_HANG_MAX)
1448 			dm->error.map.wl_e2g_hang = true;
1449 		else
1450 			dm->error.map.wl_e2g_hang = false;
1451 
1452 		dm->cnt_dm[BTC_DCNT_E2G] = cnt;
1453 		break;
1454 	case BTC_DCNT_TDMA_NONSYNC:
1455 		if (cnt != 0) /* if tdma not sync between drv/fw  */
1456 			dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC]++;
1457 		else
1458 			dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] = 0;
1459 
1460 		if (dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] >= BTC_CHK_HANG_MAX)
1461 			dm->error.map.tdma_no_sync = true;
1462 		else
1463 			dm->error.map.tdma_no_sync = false;
1464 		break;
1465 	case BTC_DCNT_SLOT_NONSYNC:
1466 		if (cnt != 0) /* if slot not sync between drv/fw  */
1467 			dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC]++;
1468 		else
1469 			dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] = 0;
1470 
1471 		if (dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] >= BTC_CHK_HANG_MAX)
1472 			dm->error.map.slot_no_sync = true;
1473 		else
1474 			dm->error.map.slot_no_sync = false;
1475 		break;
1476 	case BTC_DCNT_BTTX_HANG:
1477 		cnt = bt->bcnt[BTC_BCNT_LOPRI_TX];
1478 
1479 		if (cnt == 0 && bt->link_info.slave_role)
1480 			dm->cnt_dm[BTC_DCNT_BTTX_HANG]++;
1481 		else
1482 			dm->cnt_dm[BTC_DCNT_BTTX_HANG] = 0;
1483 
1484 		if (dm->cnt_dm[BTC_DCNT_BTTX_HANG] >= BTC_CHK_HANG_MAX)
1485 			dm->error.map.bt_tx_hang = true;
1486 		else
1487 			dm->error.map.bt_tx_hang = false;
1488 		break;
1489 	case BTC_DCNT_BTCNT_HANG:
1490 		cnt = bt->bcnt[BTC_BCNT_HIPRI_RX] +
1491 		      bt->bcnt[BTC_BCNT_HIPRI_TX] +
1492 		      bt->bcnt[BTC_BCNT_LOPRI_RX] +
1493 		      bt->bcnt[BTC_BCNT_LOPRI_TX];
1494 
1495 		if (cnt == 0)
1496 			dm->cnt_dm[BTC_DCNT_BTCNT_HANG]++;
1497 		else
1498 			dm->cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;
1499 		break;
1500 	case BTC_DCNT_WL_SLOT_DRIFT:
1501 		if (cnt >= BTC_CHK_WLSLOT_DRIFT_MAX)
1502 			dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT]++;
1503 		else
1504 			dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] = 0;
1505 
1506 		if (dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
1507 			dm->error.map.wl_slot_drift = true;
1508 		else
1509 			dm->error.map.wl_slot_drift = false;
1510 		break;
1511 	case BTC_DCNT_BT_SLOT_DRIFT:
1512 		if (cnt >= BTC_CHK_BTSLOT_DRIFT_MAX)
1513 			dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT]++;
1514 		else
1515 			dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT] = 0;
1516 
1517 		if (dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
1518 			dm->error.map.bt_slot_drift = true;
1519 		else
1520 			dm->error.map.bt_slot_drift = false;
1521 
1522 		break;
1523 	case BTC_DCNT_BT_SLOT_FLOOD:
1524 		if (!btc->fwinfo.rpt_fbtc_cysta.cinfo.valid ||
1525 		    dm->cnt_dm[BTC_DCNT_CYCLE] == cnt)
1526 			break;
1527 
1528 		if (cnt < BTC_CYCLE_SLOT_MAX ||
1529 		    (dm->tdma_now.type != CXTDMA_AUTO &&
1530 		     dm->tdma_now.type != CXTDMA_AUTO2 &&
1531 		     dm->tdma_now.ext_ctrl != CXECTL_EXT)) {
1532 			dm->error.map.bt_slot_flood = false;
1533 			dm->cnt_dm[BTC_DCNT_BT_SLOT_FLOOD] = 0;
1534 			a2dp->no_empty_streak_2s = 0;
1535 			a2dp->no_empty_streak_max = 0;
1536 			break;
1537 		}
1538 
1539 		/* 1 cycle = 1 wl-slot + 1 bt-slot */
1540 		slot_pair = BTC_CYCLE_SLOT_MAX / 2;
1541 		if (cnt - dm->cnt_dm[BTC_DCNT_CYCLE] > slot_pair)
1542 			c_begin = cnt - slot_pair + 1;
1543 		else
1544 			c_begin = dm->cnt_dm[BTC_DCNT_CYCLE] + 1;
1545 
1546 		c_end = cnt;
1547 		for (cycle = c_begin; cycle <= c_end; cycle++) {
1548 			s_id = ((cycle - 1) % slot_pair) * 2;
1549 			if (le16_to_cpu(pcysta->v7.slot_step_time[s_id]) >=
1550 			    dm->bt_slot_flood)
1551 				dm->cnt_dm[BTC_DCNT_BT_SLOT_FLOOD]++;
1552 			/* calculate no-A2DP-empty streak count */
1553 			if (pcysta->v7.a2dp_trx[s_id].empty_cnt == 0 &&
1554 			    pcysta->v7.a2dp_trx[s_id + 1].empty_cnt == 0) {
1555 				empty_streak++;
1556 				if (empty_streak > empty_streak_max)
1557 					empty_streak_max = empty_streak;
1558 			} else {
1559 				empty_streak = 0;
1560 			}
1561 		}
1562 
1563 		a2dp->no_empty_streak_2s = empty_streak_max;
1564 		if (a2dp->no_empty_streak_2s > a2dp->no_empty_streak_max)
1565 			a2dp->no_empty_streak_max = a2dp->no_empty_streak_2s;
1566 
1567 		dm->error.map.bt_slot_flood =
1568 			!!dm->cnt_dm[BTC_DCNT_BT_SLOT_FLOOD];
1569 		break;
1570 	case BTC_DCNT_WL_STA_NTFY:
1571 		cnt = dm->cnt_notify[BTC_NCNT_WL_STA] -
1572 		      dm->cnt_notify[BTC_NCNT_WL_STA_LAST];
1573 
1574 		dm->cnt_notify[BTC_NCNT_WL_STA_LAST] =
1575 			dm->cnt_notify[BTC_NCNT_WL_STA];
1576 
1577 		if (cnt == 0 &&
1578 		    (dm->tdd_bind.wl_link_mode != BTC_WLINK_NOLINK ||
1579 		     dm->fdd_bind.wl_link_mode != BTC_WLINK_NOLINK))
1580 			dm->cnt_dm[BTC_DCNT_WL_STA_NTFY]++;
1581 		else
1582 			dm->cnt_dm[BTC_DCNT_WL_STA_NTFY] = 0;
1583 
1584 		if (dm->cnt_dm[BTC_DCNT_WL_STA_NTFY] >= BTC_CHK_HANG_MAX)
1585 			dm->error.map.wl_no_sta_ntfy = true;
1586 		else
1587 			dm->error.map.wl_no_sta_ntfy = false;
1588 		break;
1589 	case BTC_DCNT_W2B_SCBD_NOSYNC:
1590 		if (!(rtwdev->chip->para_ver & BTC_FEAT_MULTI_PTA))
1591 			return; /* return if no-support W2B scbd readback */
1592 
1593 		if (wl->scbd_rb[BTC_BT_1ST] != wl->scbd[BTC_BT_1ST] ||
1594 		    wl->scbd_rb[BTC_BT_2ND] != wl->scbd[BTC_BT_2ND])
1595 			dm->cnt_dm[BTC_DCNT_W2B_SCBD_NOSYNC]++;
1596 		else
1597 			dm->cnt_dm[BTC_DCNT_W2B_SCBD_NOSYNC] = 0;
1598 
1599 		if (dm->cnt_dm[BTC_DCNT_W2B_SCBD_NOSYNC] >= BTC_CHK_HANG_MAX)
1600 			dm->error.map.w2b_scbd_no_sync = true;
1601 		else
1602 			dm->error.map.w2b_scbd_no_sync = false;
1603 		break;
1604 	case BTC_DCNT_NULL_TX_FAIL:
1605 		if (dm->fddt_train)
1606 			break;
1607 
1608 		if (ver->fcxnullsta == 7) {
1609 			ok = le32_to_cpu(ns->v7.result[1][1]);
1610 			late = le32_to_cpu(ns->v7.result[1][2]);
1611 			tx_cnt = le32_to_cpu(ns->v7.result[1][4]);
1612 		} else if (ver->fcxnullsta == 2) {
1613 			ok = le32_to_cpu(ns->v2.result[1][1]);
1614 			late = le32_to_cpu(ns->v2.result[1][2]);
1615 			tx_cnt = le32_to_cpu(ns->v2.result[1][4]);
1616 		} else if (ver->fcxnullsta == 1) {
1617 			ok = le32_to_cpu(ns->v1.result[1][1]);
1618 			late = le32_to_cpu(ns->v1.result[1][2]);
1619 			tx_cnt = 0;
1620 		} else {
1621 			break;
1622 		}
1623 
1624 		if (tx_cnt < BTC_NULLTX_CHK_PERIOD)
1625 			break;
1626 
1627 		if (late * BTC_NULLTX_FAIL_TH > ok)
1628 			dm->cnt_dm[BTC_DCNT_NULL_TX_FAIL]++;
1629 		else
1630 			dm->cnt_dm[BTC_DCNT_NULL_TX_FAIL] = 0;
1631 
1632 		dm->error.map.null1_tx_late =
1633 			dm->cnt_dm[BTC_DCNT_NULL_TX_FAIL] >= BTC_CHK_HANG_MAX;
1634 		break;
1635 	}
1636 }
1637 
1638 static void _update_bt_afh_conflict(struct rtw89_dev *rtwdev,
1639 				    struct rtw89_btc_bt_info *bt,
1640 				    u8 map_type)
1641 {
1642 	struct rtw89_btc *btc = &rtwdev->btc;
1643 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
1644 	struct rtw89_btc_dm *dm = &btc->dm;
1645 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
1646 	struct rtw89_btc_bt_leaudio_desc *leaudio = &b->leaudio_desc;
1647 	u8 hw_band = wl->role_info.pta_req_band;
1648 	u32 cnt, cnt_ch, cnt_le, cnt_ch_le;
1649 	u8 i, omap, xmap, afh_en;
1650 
1651 	if (map_type & RPT_BT_AFH_SEQ_LEGACY) {
1652 		bt->bcnt[BTC_BCNT_AFH_UPDATE]++;
1653 		bt->bcnt[BTC_BCNT_AFH_CONFLICT] = 0;
1654 		dm->error.map.bt_afh_conflict = 0;
1655 	}
1656 
1657 	afh_en = wl->afh_info[hw_band][RTW89_BAND_2G].en;
1658 
1659 	for (i = 0; i < 12; i++) {
1660 		if (!(map_type & RPT_BT_AFH_SEQ_LEGACY) ||
1661 		    !b->status.map.connect)
1662 			break;
1663 
1664 		omap = b->afh_map[i];
1665 		xmap = omap & wl->ch_map[i];
1666 		cnt_ch = hweight8(omap);
1667 		cnt = afh_en ? hweight8(xmap) : 0;
1668 
1669 		if (i == 11) {
1670 			bt->bcnt[BTC_BCNT_AFH_CHN] = cnt_ch;
1671 			bt->bcnt[BTC_BCNT_AFH_CONFLICT] = cnt;
1672 			dm->error.map.bt_afh_conflict = !!cnt;
1673 		}
1674 	}
1675 
1676 	if (map_type & RPT_BT_AFH_SEQ_LE) {
1677 		bt->bcnt[BTC_BCNT_AFH_LE_UPDATE]++;
1678 		bt->bcnt[BTC_BCNT_AFH_LE_CONFLICT] = 0;
1679 		dm->error.map.bt_leafh_conflict = 0;
1680 	}
1681 
1682 	for (i = 0; i < 5; i++) {
1683 		if (!(map_type & RPT_BT_AFH_SEQ_LE) ||
1684 		    (!b->status.map.ble_connect &&
1685 		     !leaudio->bis_exist && !leaudio->cis_exist))
1686 			break;
1687 
1688 		omap = b->afh_map_le[i];
1689 		xmap = omap & wl->ch_map_le[i];
1690 		cnt_ch_le = hweight8(omap);
1691 		cnt_le = afh_en ? hweight8(xmap) : 0;
1692 
1693 		if (i == 4) {
1694 			bt->bcnt[BTC_BCNT_AFH_LE_CHN] = cnt_ch_le;
1695 			bt->bcnt[BTC_BCNT_AFH_LE_CONFLICT] = cnt_le;
1696 			dm->error.map.bt_leafh_conflict = !!cnt_le;
1697 		}
1698 	}
1699 }
1700 
1701 static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
1702 {
1703 	struct rtw89_btc *btc = &rtwdev->btc;
1704 	const struct rtw89_btc_ver *ver = btc->ver;
1705 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
1706 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
1707 	struct rtw89_btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc;
1708 	union  rtw89_btc_fbtc_btver *pver = &btc->fwinfo.rpt_fbtc_btver.finfo;
1709 	struct rtw89_btc_fbtc_btafh_v2 *pafh_v2 = NULL;
1710 	struct rtw89_btc_fbtc_btafh_v7 *pafh_v7 = NULL;
1711 	struct rtw89_btc_fbtc_btdevinfo *pdev = NULL;
1712 	struct rtw89_btc_fbtc_btafh *pafh_v1 = NULL;
1713 	struct rtw89_btc_fbtc_btscan_v1 *pscan_v1;
1714 	struct rtw89_btc_fbtc_btscan_v2 *pscan_v2;
1715 	struct rtw89_btc_fbtc_btscan_v7 *pscan_v7;
1716 	bool scan_update = true;
1717 	int i;
1718 
1719 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1720 		    "[BTC], %s(): rpt_type:%d\n",
1721 		    __func__, rpt_type);
1722 
1723 	switch (rpt_type) {
1724 	case BTC_RPT_TYPE_BT_VER:
1725 		if (ver->fcxbtver == 8) {
1726 			pver->v8 = *(struct rtw89_btc_fbtc_btver_v8 *)pfinfo;
1727 			bt = pver->v8.bt_id ? &btc->cx.bt1 : &btc->cx.bt0;
1728 			bt->ver_info.fw = le32_to_cpu(pver->v8.fw_ver);
1729 			bt->ver_info.fw_coex = le32_get_bits(pver->v8.coex_ver,
1730 							     GENMASK(7, 0));
1731 			bt->feature = le32_to_cpu(pver->v8.feature);
1732 		} else if (ver->fcxbtver == 7) {
1733 			pver->v7 = *(struct rtw89_btc_fbtc_btver_v7 *)pfinfo;
1734 			bt->ver_info.fw = le32_to_cpu(pver->v7.fw_ver);
1735 			bt->ver_info.fw_coex = le32_get_bits(pver->v7.coex_ver,
1736 							     GENMASK(7, 0));
1737 			bt->feature = le32_to_cpu(pver->v7.feature);
1738 		} else {
1739 			pver->v1 = *(struct rtw89_btc_fbtc_btver_v1 *)pfinfo;
1740 			bt->ver_info.fw = le32_to_cpu(pver->v1.fw_ver);
1741 			bt->ver_info.fw_coex = le32_get_bits(pver->v1.coex_ver,
1742 							     GENMASK(7, 0));
1743 			bt->feature = le32_to_cpu(pver->v1.feature);
1744 		}
1745 		break;
1746 	case BTC_RPT_TYPE_BT_SCAN:
1747 		if (ver->fcxbtscan == 1) {
1748 			pscan_v1 = (struct rtw89_btc_fbtc_btscan_v1 *)pfinfo;
1749 			for (i = 0; i < BTC_SCAN_MAX1; i++) {
1750 				bt->scan_info_v1[i] = pscan_v1->scan[i];
1751 				if (bt->scan_info_v1[i].win == 0 &&
1752 				    bt->scan_info_v1[i].intvl == 0)
1753 					scan_update = false;
1754 			}
1755 		} else if (ver->fcxbtscan == 2) {
1756 			pscan_v2 = (struct rtw89_btc_fbtc_btscan_v2 *)pfinfo;
1757 			for (i = 0; i < CXSCAN_MAX; i++) {
1758 				bt->scan_info_v2[i] = pscan_v2->para[i];
1759 				if ((pscan_v2->type & BIT(i)) &&
1760 				    pscan_v2->para[i].win == 0 &&
1761 				    pscan_v2->para[i].intvl == 0)
1762 					scan_update = false;
1763 			}
1764 		} else if (ver->fcxbtscan == 7) {
1765 			pscan_v7 = (struct rtw89_btc_fbtc_btscan_v7 *)pfinfo;
1766 			for (i = 0; i < CXSCAN_MAX; i++) {
1767 				bt->scan_info_v2[i] = pscan_v7->para[i];
1768 				if ((pscan_v7->type & BIT(i)) &&
1769 				    pscan_v7->para[i].win == 0 &&
1770 				    pscan_v7->para[i].intvl == 0)
1771 					scan_update = false;
1772 			}
1773 		} else if (ver->fcxbtscan == 8) {
1774 			struct rtw89_btc_fbtc_btscan_v8 *pscan_v8 =
1775 				(struct rtw89_btc_fbtc_btscan_v8 *)pfinfo;
1776 
1777 			bt = pscan_v8->bt_id ? &btc->cx.bt1 : &btc->cx.bt0;
1778 			for (i = 0; i < CXSCAN_MAX; i++) {
1779 				bt->scan_info_v2[i] = pscan_v8->para[i];
1780 				if ((pscan_v8->type & BIT(i)) &&
1781 				    pscan_v8->para[i].win == 0 &&
1782 				    pscan_v8->para[i].intvl == 0)
1783 					scan_update = false;
1784 			}
1785 		}
1786 		if (scan_update)
1787 			bt->scan_info_update = 1;
1788 		break;
1789 	case BTC_RPT_TYPE_BT_AFH:
1790 		if (ver->fcxbtafh == 2) {
1791 			pafh_v2 = (struct rtw89_btc_fbtc_btafh_v2 *)pfinfo;
1792 			if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LEGACY) {
1793 				memcpy(&bt_linfo->afh_map[0], pafh_v2->afh_l, 4);
1794 				memcpy(&bt_linfo->afh_map[4], pafh_v2->afh_m, 4);
1795 				memcpy(&bt_linfo->afh_map[8], pafh_v2->afh_h, 2);
1796 			}
1797 			if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LE) {
1798 				memcpy(&bt_linfo->afh_map_le[0], pafh_v2->afh_le_a, 4);
1799 				memcpy(&bt_linfo->afh_map_le[4], pafh_v2->afh_le_b, 1);
1800 			}
1801 			_update_bt_afh_conflict(rtwdev, bt, pafh_v2->map_type);
1802 		} else if (ver->fcxbtafh == 7) {
1803 			pafh_v7 = (struct rtw89_btc_fbtc_btafh_v7 *)pfinfo;
1804 			if (pafh_v7->map_type & RPT_BT_AFH_SEQ_LEGACY) {
1805 				memcpy(&bt_linfo->afh_map[0], pafh_v7->afh_l, 4);
1806 				memcpy(&bt_linfo->afh_map[4], pafh_v7->afh_m, 4);
1807 				memcpy(&bt_linfo->afh_map[8], pafh_v7->afh_h, 2);
1808 			}
1809 			if (pafh_v7->map_type & RPT_BT_AFH_SEQ_LE) {
1810 				memcpy(&bt_linfo->afh_map_le[0], pafh_v7->afh_le_a, 4);
1811 				memcpy(&bt_linfo->afh_map_le[4], pafh_v7->afh_le_b, 1);
1812 			}
1813 			_update_bt_afh_conflict(rtwdev, bt, pafh_v7->map_type);
1814 		} else if (ver->fcxbtafh == 8) {
1815 			struct rtw89_btc_fbtc_btafh_v8 *pafh_v8 =
1816 				(struct rtw89_btc_fbtc_btafh_v8 *)pfinfo;
1817 			struct rtw89_btc_bt_info *tbt =
1818 				pafh_v8->bt_id ? &btc->cx.bt1 : &btc->cx.bt0;
1819 			struct rtw89_btc_bt_link_info *tbt_linfo = &tbt->link_info;
1820 
1821 			if (pafh_v8->map_type & RPT_BT_AFH_SEQ_LEGACY) {
1822 				memcpy(&tbt_linfo->afh_map[0], pafh_v8->afh_l, 4);
1823 				memcpy(&tbt_linfo->afh_map[4], pafh_v8->afh_m, 4);
1824 				memcpy(&tbt_linfo->afh_map[8], pafh_v8->afh_h, 2);
1825 			}
1826 			if (pafh_v8->map_type & RPT_BT_AFH_SEQ_LE) {
1827 				memcpy(&tbt_linfo->afh_map_le[0], pafh_v8->afh_le_a, 4);
1828 				memcpy(&tbt_linfo->afh_map_le[4], pafh_v8->afh_le_b, 1);
1829 			}
1830 			_update_bt_afh_conflict(rtwdev, tbt, pafh_v8->map_type);
1831 		} else if (ver->fcxbtafh == 1) {
1832 			pafh_v1 = (struct rtw89_btc_fbtc_btafh *)pfinfo;
1833 			memcpy(&bt_linfo->afh_map[0], pafh_v1->afh_l, 4);
1834 			memcpy(&bt_linfo->afh_map[4], pafh_v1->afh_m, 4);
1835 			memcpy(&bt_linfo->afh_map[8], pafh_v1->afh_h, 2);
1836 		}
1837 		break;
1838 	case BTC_RPT_TYPE_BT_DEVICE:
1839 		pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo;
1840 		if (ver->fcxbtdevinfo == 8) {
1841 			bt = pdev->rsvd ? &btc->cx.bt1 : &btc->cx.bt0;
1842 			a2dp = &bt->link_info.a2dp_desc;
1843 		}
1844 		a2dp->device_name = le32_to_cpu(pdev->dev_name);
1845 		a2dp->vendor_id = le16_to_cpu(pdev->vendor_id);
1846 		a2dp->flush_time = le32_to_cpu(pdev->flush_time);
1847 		break;
1848 	default:
1849 		break;
1850 	}
1851 }
1852 
1853 static void rtw89_btc_fw_rpt_evnt_ver(struct rtw89_dev *rtwdev, u8 *index)
1854 {
1855 	struct rtw89_btc *btc = &rtwdev->btc;
1856 	const struct rtw89_btc_ver *ver = btc->ver;
1857 
1858 	if (ver->fwevntrptl == 1)
1859 		return;
1860 
1861 	if (*index <= __BTC_RPT_TYPE_V0_SAME)
1862 		return;
1863 	else if (*index <= __BTC_RPT_TYPE_V0_MAX)
1864 		(*index)++;
1865 	else
1866 		*index = BTC_RPT_TYPE_MAX;
1867 }
1868 
1869 #define BTC_LEAK_AP_TH 10
1870 #define BTC_CYSTA_CHK_PERIOD 100
1871 
1872 struct rtw89_btc_prpt {
1873 	u8 type;
1874 	__le16 len;
1875 	u8 content[];
1876 } __packed;
1877 
1878 static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
1879 			   struct rtw89_btc_btf_fwinfo *pfwinfo,
1880 			   u8 *prptbuf, u32 index)
1881 {
1882 	struct rtw89_btc *btc = &rtwdev->btc;
1883 	struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver;
1884 	const struct rtw89_btc_ver *ver = btc->ver;
1885 	struct rtw89_btc_dm *dm = &btc->dm;
1886 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
1887 	struct rtw89_btc_cx *cx = &btc->cx;
1888 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
1889 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
1890 	union rtw89_btc_fbtc_rpt_ctrl_ver_info *prpt = NULL;
1891 	union rtw89_btc_fbtc_cysta_info *pcysta = NULL;
1892 	struct rtw89_btc_prpt *btc_prpt = NULL;
1893 	void *rpt_content = NULL, *pfinfo = NULL;
1894 	u8 rpt_type = 0;
1895 	u16 wl_slot_set = 0, wl_slot_real = 0, val16;
1896 	u32 trace_step = 0, rpt_len = 0, diff_t = 0;
1897 	u32 cnt_leak_slot, bt_slot_real, bt_slot_set, cnt_rx_imr;
1898 	u8 i, j, val = 0, val1, val2;
1899 	u32 *bt_cnt, start_idx;
1900 	const u8 *rpt_fver;
1901 
1902 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1903 		    "[BTC], %s(): index:%d\n",
1904 		    __func__, index);
1905 
1906 	if (!prptbuf) {
1907 		pfwinfo->err[BTFRE_INVALID_INPUT]++;
1908 		return 0;
1909 	}
1910 
1911 	btc_prpt = (struct rtw89_btc_prpt *)&prptbuf[index];
1912 	rpt_type = btc_prpt->type;
1913 	rpt_len = le16_to_cpu(btc_prpt->len);
1914 	rpt_content = btc_prpt->content;
1915 
1916 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1917 		    "[BTC], %s(): rpt_type:%d\n",
1918 		    __func__, rpt_type);
1919 
1920 	rtw89_btc_fw_rpt_evnt_ver(rtwdev, &rpt_type);
1921 
1922 	switch (rpt_type) {
1923 	case BTC_RPT_TYPE_CTRL:
1924 		pcinfo = &pfwinfo->rpt_ctrl.cinfo;
1925 		prpt = &pfwinfo->rpt_ctrl.finfo;
1926 		if (ver->fcxbtcrpt == 1) {
1927 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v1;
1928 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v1);
1929 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v1.fver;
1930 		} else if (ver->fcxbtcrpt == 4) {
1931 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v4;
1932 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v4);
1933 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v4.fver;
1934 		} else if (ver->fcxbtcrpt == 5) {
1935 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v5;
1936 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v5);
1937 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v5.fver;
1938 		} else if (ver->fcxbtcrpt == 105) {
1939 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v105;
1940 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v105);
1941 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v105.fver;
1942 			pcinfo->req_fver = 5;
1943 			break;
1944 		} else if (ver->fcxbtcrpt == 205) {
1945 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v205;
1946 			pcinfo->req_len =
1947 				sizeof(pfwinfo->rpt_ctrl.finfo.v205);
1948 			fwsubver->fcxbtcrpt =
1949 				pfwinfo->rpt_ctrl.finfo.v205.fver;
1950 			pcinfo->req_fver = 5;
1951 			break;
1952 		} else if (ver->fcxbtcrpt == 8) {
1953 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v8;
1954 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v8);
1955 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v8.fver;
1956 		} else if (ver->fcxbtcrpt == 7) {
1957 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v7;
1958 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v7);
1959 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v7.fver;
1960 		} else if (ver->fcxbtcrpt == 9) {
1961 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v9;
1962 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v9);
1963 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v9.fver;
1964 		} else if (ver->fcxbtcrpt == 11) {
1965 			pfinfo = &pfwinfo->rpt_ctrl.finfo.v11;
1966 			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v11);
1967 			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v11.fver;
1968 		} else {
1969 			goto err;
1970 		}
1971 		pcinfo->req_fver = ver->fcxbtcrpt;
1972 		break;
1973 	case BTC_RPT_TYPE_TDMA:
1974 		pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
1975 		if (ver->fcxtdma == 1) {
1976 			pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1;
1977 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1);
1978 			fwsubver->fcxtdma = 0;
1979 		} else if (ver->fcxtdma == 3 || ver->fcxtdma == 4 ||
1980 			   ver->fcxtdma == 7 || ver->fcxtdma == 8) {
1981 			pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3;
1982 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3);
1983 			fwsubver->fcxtdma = pfwinfo->rpt_fbtc_tdma.finfo.v3.fver;
1984 		} else {
1985 			goto err;
1986 		}
1987 		pcinfo->req_fver = ver->fcxtdma;
1988 		break;
1989 	case BTC_RPT_TYPE_SLOT:
1990 		pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
1991 		if (ver->fcxslots == 1) {
1992 			pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v1;
1993 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v1);
1994 			fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v1.fver;
1995 		} else if (ver->fcxslots == 2) {
1996 			pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v2;
1997 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v2);
1998 			fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v2.fver;
1999 		} else if (ver->fcxslots == 7) {
2000 			pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v7;
2001 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v7);
2002 			fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v7.fver;
2003 		} else {
2004 			goto err;
2005 		}
2006 		pcinfo->req_fver = ver->fcxslots;
2007 		break;
2008 	case BTC_RPT_TYPE_CYSTA:
2009 		pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
2010 		pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
2011 		if (ver->fcxcysta == 2) {
2012 			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v2;
2013 			pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2;
2014 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v2);
2015 			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v2.fver;
2016 		} else if (ver->fcxcysta == 3) {
2017 			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v3;
2018 			pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3;
2019 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v3);
2020 			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v3.fver;
2021 		} else if (ver->fcxcysta == 4) {
2022 			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v4;
2023 			pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4;
2024 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v4);
2025 			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v4.fver;
2026 		} else if (ver->fcxcysta == 5) {
2027 			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v5;
2028 			pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5;
2029 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v5);
2030 			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v5.fver;
2031 		} else if (ver->fcxcysta == 105) {
2032 			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v105;
2033 			pcysta->v105 = pfwinfo->rpt_fbtc_cysta.finfo.v105;
2034 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v105);
2035 			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v105.fver;
2036 		} else if (ver->fcxcysta == 7) {
2037 			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v7;
2038 			pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7;
2039 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v7);
2040 			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v7.fver;
2041 		} else if (ver->fcxcysta == 8) {
2042 			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v8;
2043 			pcysta->v8 = pfwinfo->rpt_fbtc_cysta.finfo.v8;
2044 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v8);
2045 			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v8.fver;
2046 		} else {
2047 			goto err;
2048 		}
2049 		pcinfo->req_fver = ver->fcxcysta;
2050 		break;
2051 	case BTC_RPT_TYPE_STEP:
2052 		pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
2053 		if (ver->fcxctrl != 7)
2054 			trace_step = btc->ctrl.trace_step;
2055 
2056 		if (ver->fcxstep == 2) {
2057 			pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v2;
2058 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) *
2059 					  trace_step +
2060 					  offsetof(struct rtw89_btc_fbtc_steps_v2, step);
2061 			fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v2.fver;
2062 		} else if (ver->fcxstep == 3) {
2063 			pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v3;
2064 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v3.step[0]) *
2065 					  trace_step +
2066 					  offsetof(struct rtw89_btc_fbtc_steps_v3, step);
2067 			fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v3.fver;
2068 		} else {
2069 			goto err;
2070 		}
2071 		pcinfo->req_fver = ver->fcxstep;
2072 		break;
2073 	case BTC_RPT_TYPE_NULLSTA:
2074 		pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
2075 		if (ver->fcxnullsta == 1) {
2076 			pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v1;
2077 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v1);
2078 			fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v1.fver;
2079 		} else if (ver->fcxnullsta == 2) {
2080 			pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v2;
2081 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v2);
2082 			fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v2.fver;
2083 		} else if (ver->fcxnullsta == 7) {
2084 			pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v7;
2085 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v7);
2086 			fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v7.fver;
2087 		} else {
2088 			goto err;
2089 		}
2090 		pcinfo->req_fver = ver->fcxnullsta;
2091 		break;
2092 	case BTC_RPT_TYPE_MREG:
2093 		pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
2094 		if (ver->fcxmreg == 1) {
2095 			pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v1;
2096 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v1);
2097 			fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v1.fver;
2098 		} else if (ver->fcxmreg == 2) {
2099 			pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v2;
2100 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v2);
2101 			fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v2.fver;
2102 		} else if (ver->fcxmreg == 7) {
2103 			pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v7;
2104 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v7);
2105 			fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v7.fver;
2106 		} else {
2107 			goto err;
2108 		}
2109 		pcinfo->req_fver = ver->fcxmreg;
2110 		break;
2111 	case BTC_RPT_TYPE_GPIO_DBG:
2112 		pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
2113 		if (ver->fcxgpiodbg == 7 || ver->fcxgpiodbg == 8) {
2114 			pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7;
2115 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7);
2116 			fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7.fver;
2117 		} else {
2118 			pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1;
2119 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1);
2120 			fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1.fver;
2121 		}
2122 		pcinfo->req_fver = ver->fcxgpiodbg;
2123 		break;
2124 	case BTC_RPT_TYPE_BT_VER:
2125 		pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo;
2126 		if (ver->fcxbtver == 1) {
2127 			pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v1;
2128 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v1);
2129 			fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v1.fver;
2130 		} else if (ver->fcxbtver == 7) {
2131 			pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v7;
2132 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v7);
2133 			fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v7.fver;
2134 		} else if (ver->fcxbtver == 8) {
2135 			pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v8;
2136 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v8);
2137 			fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v8.fver;
2138 		} else {
2139 			goto err;
2140 		}
2141 		pcinfo->req_fver = ver->fcxbtver;
2142 		break;
2143 	case BTC_RPT_TYPE_BT_SCAN:
2144 		pcinfo = &pfwinfo->rpt_fbtc_btscan.cinfo;
2145 		if (ver->fcxbtscan == 1) {
2146 			pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v1;
2147 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v1);
2148 			fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v1.fver;
2149 		} else if (ver->fcxbtscan == 2) {
2150 			pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v2;
2151 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v2);
2152 			fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v2.fver;
2153 		} else if (ver->fcxbtscan == 7) {
2154 			pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v7;
2155 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v7);
2156 			fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v7.fver;
2157 		} else if (ver->fcxbtscan == 8) {
2158 			pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v8;
2159 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v8);
2160 			fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v8.fver;
2161 		} else {
2162 			goto err;
2163 		}
2164 		pcinfo->req_fver = ver->fcxbtscan;
2165 		break;
2166 	case BTC_RPT_TYPE_BT_AFH:
2167 		pcinfo = &pfwinfo->rpt_fbtc_btafh.cinfo;
2168 		if (ver->fcxbtafh == 1) {
2169 			pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v1;
2170 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v1);
2171 			fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v1.fver;
2172 		} else if (ver->fcxbtafh == 2) {
2173 			pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v2;
2174 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v2);
2175 			fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v2.fver;
2176 		} else if (ver->fcxbtafh == 7) {
2177 			pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v7;
2178 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v7);
2179 			fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v7.fver;
2180 		} else if (ver->fcxbtafh == 8) {
2181 			pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v8;
2182 			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v8);
2183 			fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v8.fver;
2184 		} else {
2185 			goto err;
2186 		}
2187 		pcinfo->req_fver = ver->fcxbtafh;
2188 		break;
2189 	case BTC_RPT_TYPE_BT_DEVICE:
2190 		pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo;
2191 		pfinfo = &pfwinfo->rpt_fbtc_btdev.finfo;
2192 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btdev.finfo);
2193 		fwsubver->fcxbtdevinfo = pfwinfo->rpt_fbtc_btdev.finfo.fver;
2194 		pcinfo->req_fver = ver->fcxbtdevinfo;
2195 		break;
2196 	default:
2197 		pfwinfo->err[BTFRE_UNDEF_TYPE]++;
2198 		return 0;
2199 	}
2200 
2201 	pcinfo->rx_len = rpt_len;
2202 	pcinfo->rx_cnt++;
2203 
2204 	if (rpt_len != pcinfo->req_len) {
2205 		if (rpt_type < BTC_RPT_TYPE_MAX)
2206 			pfwinfo->len_mismch |= (0x1 << rpt_type);
2207 		else
2208 			pfwinfo->len_mismch |= BIT(31);
2209 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2210 			    "[BTC], %s(): %d rpt_len:%d!=req_len:%d\n",
2211 			    __func__, rpt_type, rpt_len, pcinfo->req_len);
2212 
2213 		pcinfo->valid = 0;
2214 		return 0;
2215 	} else if (!pfinfo || !rpt_content || !pcinfo->req_len) {
2216 		pfwinfo->err[BTFRE_EXCEPTION]++;
2217 		pcinfo->valid = 0;
2218 		return 0;
2219 	}
2220 
2221 	memcpy(pfinfo, rpt_content, pcinfo->req_len);
2222 	pcinfo->valid = 1;
2223 
2224 	/*
2225 	 * fver is the leading field of every report struct. A mismatch
2226 	 * vs the driver-selected version means ver_defs needs a fix, so
2227 	 * flag it for debug but keep processing the length-valid report.
2228 	 */
2229 	rpt_fver = pfinfo;
2230 	pcinfo->rsp_fver = rpt_fver[0];
2231 	if (pcinfo->rsp_fver != pcinfo->req_fver) {
2232 		pfwinfo->fver_mismch |= BIT(rpt_type);
2233 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2234 			    "[BTC], %s(): %d rsp_fver:%d!=req_fver:%d\n",
2235 			    __func__, rpt_type, pcinfo->rsp_fver,
2236 			    pcinfo->req_fver);
2237 	}
2238 
2239 	switch (rpt_type) {
2240 	case BTC_RPT_TYPE_CTRL:
2241 		if (ver->fcxbtcrpt == 1) {
2242 			prpt->v1 = pfwinfo->rpt_ctrl.finfo.v1;
2243 			btc->fwinfo.rpt_en_map = prpt->v1.rpt_enable;
2244 			wl->ver_info.fw_coex = prpt->v1.wl_fw_coex_ver;
2245 			wl->ver_info.fw = prpt->v1.wl_fw_ver;
2246 			dm->wl_fw_cx_offload = !!prpt->v1.wl_fw_cx_offload;
2247 
2248 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
2249 				     pfwinfo->event[BTF_EVNT_RPT]);
2250 
2251 			/* To avoid I/O if WL LPS or power-off */
2252 			if (wl->status.map.lps != BTC_LPS_RF_OFF &&
2253 			    !wl->status.map.rf_off) {
2254 				rtwdev->chip->ops->btc_update_bt_cnt(rtwdev);
2255 				_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2256 
2257 				bt->bcnt[BTC_BCNT_POLLUTED] =
2258 					rtw89_mac_get_plt_cnt(rtwdev,
2259 							      RTW89_MAC_0);
2260 			}
2261 		} else if (ver->fcxbtcrpt == 4) {
2262 			prpt->v4 = pfwinfo->rpt_ctrl.finfo.v4;
2263 			btc->fwinfo.rpt_en_map = le32_to_cpu(prpt->v4.rpt_info.en);
2264 			wl->ver_info.fw_coex = le32_to_cpu(prpt->v4.wl_fw_info.cx_ver);
2265 			wl->ver_info.fw = le32_to_cpu(prpt->v4.wl_fw_info.fw_ver);
2266 			dm->wl_fw_cx_offload = !!le32_to_cpu(prpt->v4.wl_fw_info.cx_offload);
2267 
2268 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
2269 				memcpy(&dm->gnt_val[i], &prpt->v4.gnt_val[i],
2270 				       sizeof(prpt->v4.gnt_val[i]));
2271 
2272 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
2273 				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_TX]);
2274 			bt->bcnt[BTC_BCNT_HIPRI_RX] =
2275 				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_RX]);
2276 			bt->bcnt[BTC_BCNT_LOPRI_TX] =
2277 				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_TX]);
2278 			bt->bcnt[BTC_BCNT_LOPRI_RX] =
2279 				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_RX]);
2280 			bt->bcnt[BTC_BCNT_POLLUTED] =
2281 				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_POLLUTED]);
2282 
2283 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2284 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
2285 				     pfwinfo->event[BTF_EVNT_RPT]);
2286 
2287 			if (le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
2288 				bt->rfk_info.map.timeout = 1;
2289 			else
2290 				bt->rfk_info.map.timeout = 0;
2291 
2292 			dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
2293 		} else if (ver->fcxbtcrpt == 5) {
2294 			prpt->v5 = pfwinfo->rpt_ctrl.finfo.v5;
2295 			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v5.rpt_info.en);
2296 			wl->ver_info.fw_coex = le32_to_cpu(prpt->v5.rpt_info.cx_ver);
2297 			wl->ver_info.fw = le32_to_cpu(prpt->v5.rpt_info.fw_ver);
2298 			dm->wl_fw_cx_offload = 0;
2299 
2300 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
2301 				memcpy(&dm->gnt_val[i], &prpt->v5.gnt_val[i],
2302 				       sizeof(prpt->v5.gnt_val[i]));
2303 
2304 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
2305 				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_TX]);
2306 			bt->bcnt[BTC_BCNT_HIPRI_RX] =
2307 				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_RX]);
2308 			bt->bcnt[BTC_BCNT_LOPRI_TX] =
2309 				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_TX]);
2310 			bt->bcnt[BTC_BCNT_LOPRI_RX] =
2311 				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_RX]);
2312 			bt->bcnt[BTC_BCNT_POLLUTED] =
2313 				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_POLLUTED]);
2314 
2315 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2316 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
2317 				     pfwinfo->event[BTF_EVNT_RPT]);
2318 
2319 			dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
2320 		} else if (ver->fcxbtcrpt == 105) {
2321 			prpt->v105 = pfwinfo->rpt_ctrl.finfo.v105;
2322 			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v105.rpt_info.en);
2323 			wl->ver_info.fw_coex = le32_to_cpu(prpt->v105.rpt_info.cx_ver);
2324 			wl->ver_info.fw = le32_to_cpu(prpt->v105.rpt_info.fw_ver);
2325 			dm->wl_fw_cx_offload = 0;
2326 
2327 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
2328 				memcpy(&dm->gnt_val[i], &prpt->v105.gnt_val[i],
2329 				       sizeof(prpt->v105.gnt_val[i]));
2330 
2331 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
2332 				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_HI_TX_V105]);
2333 			bt->bcnt[BTC_BCNT_HIPRI_RX] =
2334 				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_HI_RX_V105]);
2335 			bt->bcnt[BTC_BCNT_LOPRI_TX] =
2336 				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_LO_TX_V105]);
2337 			bt->bcnt[BTC_BCNT_LOPRI_RX] =
2338 				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_LO_RX_V105]);
2339 			bt->bcnt[BTC_BCNT_POLLUTED] =
2340 				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_POLLUTED_V105]);
2341 
2342 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2343 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
2344 				     pfwinfo->event[BTF_EVNT_RPT]);
2345 
2346 			dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
2347 		} else if (ver->fcxbtcrpt == 205) {
2348 			prpt->v205 = pfwinfo->rpt_ctrl.finfo.v205;
2349 			pfwinfo->rpt_en_map =
2350 				le32_to_cpu(prpt->v205.rpt_info.en);
2351 			wl->ver_info.fw_coex =
2352 				le32_to_cpu(prpt->v205.wl_fw_info.cx_ver);
2353 			wl->ver_info.fw =
2354 				le32_to_cpu(prpt->v205.wl_fw_info.fw_ver);
2355 			dm->wl_fw_cx_offload =
2356 				!!le32_to_cpu(prpt->v205.wl_fw_info.cx_offload);
2357 
2358 			memcpy(wl->ver_info.build_time,
2359 			       prpt->v205.build_time,
2360 			       sizeof(wl->ver_info.build_time));
2361 			memcpy(wl->ver_info.build_date,
2362 			       prpt->v205.build_date,
2363 			       sizeof(wl->ver_info.build_date));
2364 
2365 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
2366 				memcpy(&dm->gnt_val[i],
2367 				       &prpt->v205.gnt_val[i],
2368 				       sizeof(prpt->v205.gnt_val[i]));
2369 
2370 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
2371 				le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_HI_TX]);
2372 			bt->bcnt[BTC_BCNT_HIPRI_RX] =
2373 				le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_HI_RX]);
2374 			bt->bcnt[BTC_BCNT_LOPRI_TX] =
2375 				le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_LO_TX]);
2376 			bt->bcnt[BTC_BCNT_LOPRI_RX] =
2377 				le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_LO_RX]);
2378 			bt->bcnt[BTC_BCNT_POLLUTED] =
2379 				le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_POLLUTED]);
2380 
2381 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2382 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
2383 				     pfwinfo->event[BTF_EVNT_RPT]);
2384 			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
2385 			_chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
2386 
2387 			if (le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
2388 				bt->rfk_info.map.timeout = 1;
2389 			else
2390 				bt->rfk_info.map.timeout = 0;
2391 
2392 			dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
2393 		} else if (ver->fcxbtcrpt == 7) {
2394 			prpt->v7 = pfwinfo->rpt_ctrl.finfo.v7;
2395 			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v7.rpt_info.en);
2396 			wl->ver_info.fw_coex = le32_to_cpu(prpt->v7.rpt_info.cx_ver);
2397 			wl->ver_info.fw = le32_to_cpu(prpt->v7.rpt_info.fw_ver);
2398 
2399 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
2400 				memcpy(&dm->gnt_val[i], &prpt->v7.gnt_val[i],
2401 				       sizeof(prpt->v7.gnt_val[i]));
2402 
2403 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
2404 				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_HI_TX_V105]);
2405 			bt->bcnt[BTC_BCNT_HIPRI_RX] =
2406 				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_HI_RX_V105]);
2407 			bt->bcnt[BTC_BCNT_LOPRI_TX] =
2408 				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_LO_TX_V105]);
2409 			bt->bcnt[BTC_BCNT_LOPRI_RX] =
2410 				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_LO_RX_V105]);
2411 
2412 			val1 = le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_POLLUTED_V105]);
2413 			if (val1 > bt->bcnt[BTC_BCNT_POLUT_NOW])
2414 				val1 -= bt->bcnt[BTC_BCNT_POLUT_NOW]; /* diff */
2415 
2416 			bt->bcnt[BTC_BCNT_POLUT_DIFF] = val1;
2417 			bt->bcnt[BTC_BCNT_POLUT_NOW] =
2418 				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_POLLUTED_V105]);
2419 
2420 			val1 = pfwinfo->event[BTF_EVNT_RPT];
2421 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2422 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
2423 			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
2424 			_chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
2425 		} else if (ver->fcxbtcrpt == 8) {
2426 			prpt->v8 = pfwinfo->rpt_ctrl.finfo.v8;
2427 			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v8.rpt_info.en);
2428 			wl->ver_info.fw_coex = le32_to_cpu(prpt->v8.rpt_info.cx_ver);
2429 			wl->ver_info.fw = le32_to_cpu(prpt->v8.rpt_info.fw_ver);
2430 
2431 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
2432 				memcpy(&dm->gnt_val[i], &prpt->v8.gnt_val[i],
2433 				       sizeof(prpt->v8.gnt_val[i]));
2434 
2435 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
2436 				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_TX_V105]);
2437 			bt->bcnt[BTC_BCNT_HIPRI_RX] =
2438 				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_RX_V105]);
2439 			bt->bcnt[BTC_BCNT_LOPRI_TX] =
2440 				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_LO_TX_V105]);
2441 			bt->bcnt[BTC_BCNT_LOPRI_RX] =
2442 				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_LO_RX_V105]);
2443 
2444 			val1 = le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_POLLUTED_V105]);
2445 			if (val1 > bt->bcnt[BTC_BCNT_POLUT_NOW])
2446 				val1 -= bt->bcnt[BTC_BCNT_POLUT_NOW]; /* diff */
2447 
2448 			bt->bcnt[BTC_BCNT_POLUT_DIFF] = val1;
2449 			bt->bcnt[BTC_BCNT_POLUT_NOW] =
2450 				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_POLLUTED_V105]);
2451 
2452 			val1 = pfwinfo->event[BTF_EVNT_RPT];
2453 			if (((prpt->v8.rpt_len_max_h << 8) +
2454 			      prpt->v8.rpt_len_max_l) != ver->info_buf)
2455 				dm->error.map.h2c_c2h_buffer_mismatch = true;
2456 			else
2457 				dm->error.map.h2c_c2h_buffer_mismatch = false;
2458 
2459 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2460 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
2461 			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
2462 			_chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
2463 		}  else if (ver->fcxbtcrpt == 9) {
2464 			prpt->v9 = pfwinfo->rpt_ctrl.finfo.v9;
2465 			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v9.rpt_info.en);
2466 			wl->ver_info.fw_coex = le32_to_cpu(prpt->v9.rpt_info.cx_ver);
2467 			wl->ver_info.fw = le32_to_cpu(prpt->v9.rpt_info.fw_ver);
2468 
2469 			memcpy(wl->ver_info.build_time,
2470 			       prpt->v9.build_time,
2471 			       sizeof(wl->ver_info.build_time));
2472 			memcpy(wl->ver_info.build_date,
2473 			       prpt->v9.build_date,
2474 			       sizeof(wl->ver_info.build_date));
2475 
2476 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
2477 				memcpy(&dm->gnt_val[i], &prpt->v9.gnt_val[i],
2478 				       sizeof(prpt->v9.gnt_val[i]));
2479 
2480 			bt->bcnt[BTC_BCNT_HIPRI_TX] =
2481 				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_HI_TX_V105]);
2482 			bt->bcnt[BTC_BCNT_HIPRI_RX] =
2483 				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_HI_RX_V105]);
2484 			bt->bcnt[BTC_BCNT_LOPRI_TX] =
2485 				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_LO_TX_V105]);
2486 			bt->bcnt[BTC_BCNT_LOPRI_RX] =
2487 				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_LO_RX_V105]);
2488 
2489 			val1 = le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_POLLUTED_V105]);
2490 			if (val1 > bt->bcnt[BTC_BCNT_POLUT_NOW])
2491 				val1 -= bt->bcnt[BTC_BCNT_POLUT_NOW]; /* diff */
2492 
2493 			bt->bcnt[BTC_BCNT_POLUT_DIFF] = val1;
2494 			bt->bcnt[BTC_BCNT_POLUT_NOW] =
2495 				le16_to_cpu(prpt->v9.bt_cnt[BTC_BCNT_POLLUTED_V105]);
2496 
2497 			dm->pta_owner = prpt->v9.pta_owner;
2498 
2499 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2500 			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
2501 			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
2502 			_chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
2503 		} else if (ver->fcxbtcrpt == 11) {
2504 			prpt->v11 = pfwinfo->rpt_ctrl.finfo.v11;
2505 			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v11.rpt_info.en);
2506 			wl->ver_info.fw_coex = le32_to_cpu(prpt->v11.rpt_info.cx_ver);
2507 			wl->ver_info.fw = le32_to_cpu(prpt->v11.rpt_info.fw_ver);
2508 
2509 			memcpy(wl->ver_info.build_time,
2510 			       prpt->v11.build_time,
2511 			       sizeof(wl->ver_info.build_time));
2512 			memcpy(wl->ver_info.build_date,
2513 			       prpt->v11.build_date,
2514 			       sizeof(wl->ver_info.build_date));
2515 
2516 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
2517 				memcpy(&dm->gnt_val[i], &prpt->v11.gnt_val[i][0],
2518 				       sizeof(dm->gnt_val[i]));
2519 
2520 			for (i = BTC_BT_1ST; i <= BTC_BT_EXT; i++) {
2521 				if (i == BTC_BT_EXT) {
2522 					if (cx->bt_ext.func_type == BTC_BTF_NONE)
2523 						continue;
2524 					bt_cnt = cx->bt_ext.bcnt;
2525 				} else if (i == BTC_BT_2ND) {
2526 					if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
2527 						continue;
2528 					bt_cnt = cx->bt1.bcnt;
2529 					wl->scbd_rb[i] = le32_to_cpu(prpt->v11.scbd_w2b[i]);
2530 					cx->bt1.scbd_rb = le32_to_cpu(prpt->v11.scbd_b2w[i]);
2531 				} else {
2532 					bt_cnt = cx->bt0.bcnt;
2533 					wl->scbd_rb[i] = le32_to_cpu(prpt->v11.scbd_w2b[i]);
2534 					cx->bt0.scbd_rb = le32_to_cpu(prpt->v11.scbd_b2w[i]);
2535 				}
2536 
2537 				start_idx = BTC_BCNT_HIPRI_TX;
2538 				for (j = BTC_BCNT_HI_TX_V105; j <= BTC_BCNT_LO_RX_V105 ; j++)
2539 					bt_cnt[start_idx++] = le16_to_cpu(prpt->v11.bt_cnt[i][j]);
2540 
2541 				/* check if polut counter increase */
2542 				val1 = le16_to_cpu(prpt->v11.bt_cnt[i][BTC_BCNT_POLLUTED_V105]);
2543 				if (val1 > bt_cnt[BTC_BCNT_POLUT_NOW]) /* cnt increase*/
2544 					val2 = val1 - bt_cnt[BTC_BCNT_POLUT_NOW];
2545 				else
2546 					val2 = val1; /* overflow */
2547 
2548 				bt_cnt[BTC_BCNT_POLUT_DIFF] = val2;
2549 				bt_cnt[BTC_BCNT_POLUT_NOW] = val1;
2550 
2551 				if (i <= BTC_BT_2ND)
2552 					bt_cnt[BTC_BCNT_SCBDREAD]++;
2553 			}
2554 			dm->scbd_w2b_update = true;
2555 			dm->scbd_b2w_update = true;
2556 
2557 			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
2558 			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
2559 			_chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
2560 			_chk_btc_err(rtwdev, BTC_DCNT_WL_STA_NTFY, 0);
2561 			_chk_btc_err(rtwdev, BTC_DCNT_W2B_SCBD_NOSYNC, 0);
2562 		} else {
2563 			goto err;
2564 		}
2565 		break;
2566 	case BTC_RPT_TYPE_TDMA:
2567 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2568 			    "[BTC], %s(): check %d %zu\n", __func__,
2569 			    BTC_DCNT_TDMA_NONSYNC,
2570 			    sizeof(dm->tdma_now));
2571 		if (ver->fcxtdma == 1)
2572 			_chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
2573 				     memcmp(&dm->tdma_now,
2574 					    &pfwinfo->rpt_fbtc_tdma.finfo.v1,
2575 					    sizeof(dm->tdma_now)));
2576 		else if (ver->fcxtdma == 3 || ver->fcxtdma == 4 ||
2577 			 ver->fcxtdma == 7 || ver->fcxtdma == 8)
2578 			_chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
2579 				     memcmp(&dm->tdma_now,
2580 					    &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma,
2581 					    sizeof(dm->tdma_now)));
2582 		else
2583 			goto err;
2584 		break;
2585 	case BTC_RPT_TYPE_SLOT:
2586 		if (ver->fcxslots == 7) {
2587 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
2588 				    "[BTC], %s(): check %d %zu\n",
2589 				    __func__, BTC_DCNT_SLOT_NONSYNC,
2590 				    sizeof(dm->slot_now.v7));
2591 			_chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
2592 				     memcmp(dm->slot_now.v7,
2593 					    pfwinfo->rpt_fbtc_slots.finfo.v7.slot,
2594 					    sizeof(dm->slot_now.v7)));
2595 		} else if (ver->fcxslots == 2) {
2596 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
2597 				    "[BTC], %s(): check %d %zu\n",
2598 				    __func__, BTC_DCNT_SLOT_NONSYNC,
2599 				    sizeof(dm->slot_now.v7));
2600 			_chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
2601 				     memcmp(dm->slot_now.v7,
2602 					    pfwinfo->rpt_fbtc_slots.finfo.v2.slot,
2603 					    sizeof(dm->slot_now.v7)));
2604 		} else if (ver->fcxslots == 1) {
2605 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
2606 				    "[BTC], %s(): check %d %zu\n",
2607 				    __func__, BTC_DCNT_SLOT_NONSYNC,
2608 				    sizeof(dm->slot_now.v1));
2609 			_chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
2610 				     memcmp(dm->slot_now.v1,
2611 					    pfwinfo->rpt_fbtc_slots.finfo.v1.slot,
2612 					    sizeof(dm->slot_now.v1)));
2613 		}
2614 		break;
2615 	case BTC_RPT_TYPE_CYSTA:
2616 		if (ver->fcxcysta == 2) {
2617 			if (le16_to_cpu(pcysta->v2.cycles) < BTC_CYSTA_CHK_PERIOD)
2618 				break;
2619 			/* Check Leak-AP */
2620 			if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) != 0 &&
2621 			    le32_to_cpu(pcysta->v2.leakrx_cnt) != 0 && dm->tdma_now.rxflctrl) {
2622 				if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) <
2623 				    BTC_LEAK_AP_TH * le32_to_cpu(pcysta->v2.leakrx_cnt))
2624 					dm->leak_ap = 1;
2625 			}
2626 
2627 			/* Check diff time between WL slot and W1/E2G slot */
2628 			if (dm->tdma_now.type == CXTDMA_OFF &&
2629 			    dm->tdma_now.ext_ctrl == CXECTL_EXT) {
2630 				if (ver->fcxslots == 1)
2631 					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_E2G].dur);
2632 				else if (ver->fcxslots == 7)
2633 					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_E2G].dur);
2634 			} else {
2635 				if (ver->fcxslots == 1)
2636 					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
2637 				else if (ver->fcxslots == 7)
2638 					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
2639 			}
2640 
2641 			if (le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) > wl_slot_set) {
2642 				diff_t = le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) - wl_slot_set;
2643 				_chk_btc_err(rtwdev,
2644 					     BTC_DCNT_WL_SLOT_DRIFT, diff_t);
2645 			}
2646 
2647 			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
2648 				     le32_to_cpu(pcysta->v2.slot_cnt[CXST_W1]));
2649 			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
2650 				     le32_to_cpu(pcysta->v2.slot_cnt[CXST_B1]));
2651 			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
2652 				     le16_to_cpu(pcysta->v2.cycles));
2653 		} else if (ver->fcxcysta == 3) {
2654 			if (le16_to_cpu(pcysta->v3.cycles) < BTC_CYSTA_CHK_PERIOD)
2655 				break;
2656 
2657 			cnt_leak_slot = le32_to_cpu(pcysta->v3.slot_cnt[CXST_LK]);
2658 			cnt_rx_imr = le32_to_cpu(pcysta->v3.leak_slot.cnt_rximr);
2659 
2660 			/* Check Leak-AP */
2661 			if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
2662 			    dm->tdma_now.rxflctrl) {
2663 				if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
2664 					dm->leak_ap = 1;
2665 			}
2666 
2667 			/* Check diff time between real WL slot and W1 slot */
2668 			if (dm->tdma_now.type == CXTDMA_OFF) {
2669 				if (ver->fcxslots == 1)
2670 					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
2671 				else if (ver->fcxslots == 7)
2672 					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
2673 				wl_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_WL]);
2674 				if (wl_slot_real > wl_slot_set) {
2675 					diff_t = wl_slot_real - wl_slot_set;
2676 					_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
2677 				}
2678 			}
2679 
2680 			/* Check diff time between real BT slot and EBT/E5G slot */
2681 			if (dm->tdma_now.type == CXTDMA_OFF &&
2682 			    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
2683 			    btc->bt_req_len[RTW89_PHY_0] != 0) {
2684 				bt_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_BT]);
2685 				if (btc->bt_req_len[RTW89_PHY_0] > bt_slot_real) {
2686 					diff_t = btc->bt_req_len[RTW89_PHY_0] - bt_slot_real;
2687 					_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
2688 				}
2689 			}
2690 
2691 			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
2692 				     le32_to_cpu(pcysta->v3.slot_cnt[CXST_W1]));
2693 			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
2694 				     le32_to_cpu(pcysta->v3.slot_cnt[CXST_B1]));
2695 			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
2696 				     le16_to_cpu(pcysta->v3.cycles));
2697 		} else if (ver->fcxcysta == 4) {
2698 			if (le16_to_cpu(pcysta->v4.cycles) < BTC_CYSTA_CHK_PERIOD)
2699 				break;
2700 
2701 			cnt_leak_slot = le16_to_cpu(pcysta->v4.slot_cnt[CXST_LK]);
2702 			cnt_rx_imr = le32_to_cpu(pcysta->v4.leak_slot.cnt_rximr);
2703 
2704 			/* Check Leak-AP */
2705 			if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
2706 			    dm->tdma_now.rxflctrl) {
2707 				if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
2708 					dm->leak_ap = 1;
2709 			}
2710 
2711 			/* Check diff time between real WL slot and W1 slot */
2712 			if (dm->tdma_now.type == CXTDMA_OFF) {
2713 				if (ver->fcxslots == 1)
2714 					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
2715 				else if (ver->fcxslots == 7)
2716 					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
2717 				wl_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_WL]);
2718 				if (wl_slot_real > wl_slot_set) {
2719 					diff_t = wl_slot_real - wl_slot_set;
2720 					_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
2721 				}
2722 			}
2723 
2724 			/* Check diff time between real BT slot and EBT/E5G slot */
2725 			if (dm->tdma_now.type == CXTDMA_OFF &&
2726 			    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
2727 			    btc->bt_req_len[RTW89_PHY_0] != 0) {
2728 				bt_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_BT]);
2729 
2730 				if (btc->bt_req_len[RTW89_PHY_0] > bt_slot_real) {
2731 					diff_t = btc->bt_req_len[RTW89_PHY_0] - bt_slot_real;
2732 					_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
2733 				}
2734 			}
2735 
2736 			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
2737 				     le16_to_cpu(pcysta->v4.slot_cnt[CXST_W1]));
2738 			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
2739 				     le16_to_cpu(pcysta->v4.slot_cnt[CXST_B1]));
2740 			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
2741 				     le16_to_cpu(pcysta->v4.cycles));
2742 		} else if (ver->fcxcysta == 5) {
2743 			if (dm->fddt_train == BTC_FDDT_ENABLE)
2744 				break;
2745 			cnt_leak_slot = le16_to_cpu(pcysta->v5.slot_cnt[CXST_LK]);
2746 			cnt_rx_imr = le32_to_cpu(pcysta->v5.leak_slot.cnt_rximr);
2747 
2748 			/* Check Leak-AP */
2749 			if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
2750 			    dm->tdma_now.rxflctrl) {
2751 				if (le16_to_cpu(pcysta->v5.cycles) >= BTC_CYSTA_CHK_PERIOD &&
2752 				    cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
2753 					dm->leak_ap = 1;
2754 			}
2755 
2756 			/* Check diff time between real WL slot and W1 slot */
2757 			if (dm->tdma_now.type == CXTDMA_OFF) {
2758 				if (ver->fcxslots == 1)
2759 					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
2760 				else if (ver->fcxslots == 7)
2761 					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
2762 				wl_slot_real = le16_to_cpu(pcysta->v5.cycle_time.tavg[CXT_WL]);
2763 
2764 				if (wl_slot_real > wl_slot_set)
2765 					diff_t = wl_slot_real - wl_slot_set;
2766 				else
2767 					diff_t = wl_slot_set - wl_slot_real;
2768 			}
2769 			_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
2770 
2771 			/* Check diff time between real BT slot and EBT/E5G slot */
2772 			bt_slot_set = btc->bt_req_len[RTW89_PHY_0];
2773 			bt_slot_real = le16_to_cpu(pcysta->v5.cycle_time.tavg[CXT_BT]);
2774 			diff_t = 0;
2775 			if (dm->tdma_now.type == CXTDMA_OFF &&
2776 			    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
2777 			    bt_slot_set != 0) {
2778 				if (bt_slot_set > bt_slot_real)
2779 					diff_t = bt_slot_set - bt_slot_real;
2780 				else
2781 					diff_t = bt_slot_real - bt_slot_set;
2782 			}
2783 
2784 			_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
2785 			_chk_btc_err(rtwdev, BTC_DCNT_E2G_HANG,
2786 				     le16_to_cpu(pcysta->v5.slot_cnt[CXST_E2G]));
2787 			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
2788 				     le16_to_cpu(pcysta->v5.slot_cnt[CXST_W1]));
2789 			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
2790 				     le16_to_cpu(pcysta->v5.slot_cnt[CXST_B1]));
2791 			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
2792 				     le16_to_cpu(pcysta->v5.cycles));
2793 		} else if (ver->fcxcysta == 105) {
2794 			if (dm->fddt_train == BTC_FDDT_ENABLE)
2795 				break;
2796 
2797 			cnt_leak_slot = le16_to_cpu(pcysta->v105.slot_cnt[CXST_LK]);
2798 			cnt_rx_imr = le32_to_cpu(pcysta->v105.leak_slot.cnt_rximr);
2799 
2800 			/* Check Leak-AP */
2801 			if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
2802 			    dm->tdma_now.rxflctrl) {
2803 				if (le16_to_cpu(pcysta->v5.cycles) >= BTC_CYSTA_CHK_PERIOD &&
2804 				    cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
2805 					dm->leak_ap = 1;
2806 			}
2807 
2808 			/* Check diff time between real WL slot and W1 slot */
2809 			if (dm->tdma_now.type == CXTDMA_OFF) {
2810 				if (ver->fcxslots == 1)
2811 					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
2812 				else if (ver->fcxslots == 7)
2813 					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
2814 				wl_slot_real = le16_to_cpu(pcysta->v105.cycle_time.tavg[CXT_WL]);
2815 
2816 				if (wl_slot_real > wl_slot_set)
2817 					diff_t = wl_slot_real - wl_slot_set;
2818 				else
2819 					diff_t = wl_slot_set - wl_slot_real;
2820 			}
2821 			_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
2822 
2823 			/* Check diff time between real BT slot and EBT/E5G slot */
2824 			bt_slot_set = btc->bt_req_len[RTW89_PHY_0];
2825 			bt_slot_real = le16_to_cpu(pcysta->v105.cycle_time.tavg[CXT_BT]);
2826 			diff_t = 0;
2827 			if (dm->tdma_now.type == CXTDMA_OFF &&
2828 			    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
2829 			    bt_slot_set != 0) {
2830 				if (bt_slot_set > bt_slot_real)
2831 					diff_t = bt_slot_set - bt_slot_real;
2832 				else
2833 					diff_t = bt_slot_real - bt_slot_set;
2834 			}
2835 
2836 			_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
2837 			_chk_btc_err(rtwdev, BTC_DCNT_E2G_HANG,
2838 				     le16_to_cpu(pcysta->v105.slot_cnt[CXST_E2G]));
2839 			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
2840 				     le16_to_cpu(pcysta->v105.slot_cnt[CXST_W1]));
2841 			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
2842 				     le16_to_cpu(pcysta->v105.slot_cnt[CXST_B1]));
2843 			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
2844 				     le16_to_cpu(pcysta->v105.cycles));
2845 		} else if (ver->fcxcysta == 7) {
2846 			if (dm->fddt_train == BTC_FDDT_ENABLE)
2847 				break;
2848 
2849 			pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
2850 
2851 			if (dm->tdma_now.type != CXTDMA_OFF) {
2852 				/* Check diff time between real WL slot and W1 slot */
2853 				val16 = le16_to_cpu(pcysta->v7.cycle_time.tavg[CXT_WL]);
2854 				_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, val16);
2855 
2856 				/* Check Leak-AP */
2857 				val1 = le32_to_cpu(pcysta->v7.leak_slot.cnt_rximr) *
2858 				       BTC_LEAK_AP_TH;
2859 				val2 = le16_to_cpu(pcysta->v7.slot_cnt[CXST_LK]);
2860 
2861 				val16 = le16_to_cpu(pcysta->v7.cycles);
2862 				if (dm->tdma_now.rxflctrl &&
2863 				    val16 >= BTC_CYSTA_CHK_PERIOD && val1 > val2)
2864 					dm->leak_ap = 1;
2865 			} else if (dm->tdma_now.ext_ctrl == CXECTL_EXT) {
2866 				val16 = le16_to_cpu(pcysta->v7.cycle_time.tavg[CXT_BT]);
2867 				/* Check diff between real BT slot and EBT/E5G slot */
2868 				_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, val16);
2869 
2870 				/* Check bt slot length for P2P mode*/
2871 				val1 = le16_to_cpu(pcysta->v7.a2dp_ept.cnt_timeout) *
2872 				       BTC_SLOT_REQ_TH;
2873 				val2 = le16_to_cpu(pcysta->v7.a2dp_ept.cnt);
2874 
2875 				val16 = le16_to_cpu(pcysta->v7.cycles);
2876 				if (val16 >= BTC_CYSTA_CHK_PERIOD && val1 > val2)
2877 					dm->slot_req_more = 1;
2878 				else if (bt->link_info.status.map.connect == 0)
2879 					dm->slot_req_more = 0;
2880 			}
2881 
2882 			_chk_btc_err(rtwdev, BTC_DCNT_E2G_HANG,
2883 				     le16_to_cpu(pcysta->v7.slot_cnt[CXST_E2G]));
2884 			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
2885 				     le16_to_cpu(pcysta->v7.slot_cnt[CXST_W1]));
2886 			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
2887 				     le16_to_cpu(pcysta->v7.slot_cnt[CXST_B1]));
2888 
2889 			/* "BT_SLOT_FLOOD" error-check MUST before "CYCLE_HANG" */
2890 			_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_FLOOD,
2891 				     le16_to_cpu(pcysta->v7.cycles));
2892 			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
2893 				     le16_to_cpu(pcysta->v7.cycles));
2894 		} else if (ver->fcxcysta == 8) {
2895 			if (dm->fddt_train == BTC_FDDT_ENABLE)
2896 				break;
2897 
2898 			pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
2899 
2900 			if (dm->tdma_now.type != CXTDMA_OFF) {
2901 				val16 = le16_to_cpu(pcysta->v8.cycle_time.tavg[CXT_WL]);
2902 				_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, val16);
2903 
2904 				val1 = le32_to_cpu(pcysta->v8.leak_slot.cnt_rximr) *
2905 				       BTC_LEAK_AP_TH;
2906 				val2 = le16_to_cpu(pcysta->v8.slot_cnt[CXST_LK]);
2907 
2908 				val16 = le16_to_cpu(pcysta->v8.cycles);
2909 				if (dm->tdma_now.rxflctrl &&
2910 				    val16 >= BTC_CYSTA_CHK_PERIOD && val1 > val2)
2911 					dm->leak_ap = 1;
2912 			} else if (dm->tdma_now.ext_ctrl == CXECTL_EXT) {
2913 				val16 = le16_to_cpu(pcysta->v8.cycle_time.tavg[CXT_BT]);
2914 				_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, val16);
2915 
2916 				val1 = le16_to_cpu(pcysta->v8.a2dp_ept.cnt_timeout) *
2917 				       BTC_SLOT_REQ_TH;
2918 				val2 = le16_to_cpu(pcysta->v8.a2dp_ept.cnt);
2919 
2920 				val16 = le16_to_cpu(pcysta->v8.cycles);
2921 				if (val16 >= BTC_CYSTA_CHK_PERIOD && val1 > val2)
2922 					dm->slot_req_more = 1;
2923 				else if (bt->link_info.status.map.connect == 0)
2924 					dm->slot_req_more = 0;
2925 			}
2926 
2927 			_chk_btc_err(rtwdev, BTC_DCNT_E2G_HANG,
2928 				     le16_to_cpu(pcysta->v8.slot_cnt[CXST_E2G]));
2929 			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
2930 				     le16_to_cpu(pcysta->v8.slot_cnt[CXST_W1]));
2931 			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
2932 				     le16_to_cpu(pcysta->v8.slot_cnt[CXST_B1]));
2933 			_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_FLOOD,
2934 				     le16_to_cpu(pcysta->v8.cycles));
2935 			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
2936 				     le16_to_cpu(pcysta->v8.cycles));
2937 		} else {
2938 			goto err;
2939 		}
2940 		break;
2941 	case BTC_RPT_TYPE_NULLSTA:
2942 		_chk_btc_err(rtwdev, BTC_DCNT_NULL_TX_FAIL, 0);
2943 		break;
2944 	case BTC_RPT_TYPE_MREG:
2945 		if (ver->fcxmreg == 7)
2946 			break;
2947 		_get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX_MON, &val);
2948 		if (dm->wl_btg_rx == BTC_BTGCTRL_BB_GNT_FWCTRL)
2949 			dm->wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_FWCTRL;
2950 		else
2951 			dm->wl_btg_rx_rb = val;
2952 
2953 		_get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC_MON, &val);
2954 		if (dm->wl_pre_agc == BTC_PREAGC_BB_FWCTRL)
2955 			dm->wl_pre_agc_rb = BTC_PREAGC_BB_FWCTRL;
2956 		else
2957 			dm->wl_pre_agc_rb = val;
2958 		break;
2959 	case BTC_RPT_TYPE_BT_VER:
2960 	case BTC_RPT_TYPE_BT_SCAN:
2961 	case BTC_RPT_TYPE_BT_AFH:
2962 	case BTC_RPT_TYPE_BT_DEVICE:
2963 		_update_bt_report(rtwdev, rpt_type, pfinfo);
2964 		break;
2965 	}
2966 	return (rpt_len + BTC_RPT_HDR_SIZE);
2967 
2968 err:
2969 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
2970 		    "[BTC], %s(): Undefined version for type=%d\n", __func__, rpt_type);
2971 	return 0;
2972 }
2973 
2974 static void _parse_btc_report(struct rtw89_dev *rtwdev,
2975 			      struct rtw89_btc_btf_fwinfo *pfwinfo,
2976 			      u8 *pbuf, u32 buf_len)
2977 {
2978 	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
2979 	struct rtw89_btc_prpt *btc_prpt = NULL;
2980 	u32 index = 0, rpt_len = 0;
2981 
2982 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
2983 		    "[BTC], %s(): buf_len:%d\n",
2984 		    __func__, buf_len);
2985 
2986 	while (pbuf) {
2987 		btc_prpt = (struct rtw89_btc_prpt *)&pbuf[index];
2988 		if (index + 2 >= ver->info_buf)
2989 			break;
2990 		/* At least 3 bytes: type(1) & len(2) */
2991 		rpt_len = le16_to_cpu(btc_prpt->len);
2992 		if ((index + rpt_len + BTC_RPT_HDR_SIZE) > buf_len)
2993 			break;
2994 
2995 		rpt_len = _chk_btc_report(rtwdev, pfwinfo, pbuf, index);
2996 		if (!rpt_len)
2997 			break;
2998 		index += rpt_len;
2999 	}
3000 }
3001 
3002 #define BTC_TLV_HDR_LEN 2
3003 #define BTC_TLV_HDR_LEN_V7 3
3004 
3005 static void _append_tdma(struct rtw89_dev *rtwdev)
3006 {
3007 	struct rtw89_btc *btc = &rtwdev->btc;
3008 	const struct rtw89_btc_ver *ver = btc->ver;
3009 	struct rtw89_btc_dm *dm = &btc->dm;
3010 	struct rtw89_btc_btf_tlv *tlv;
3011 	struct rtw89_btc_btf_tlv_v7 *tlv_v7;
3012 	struct rtw89_btc_fbtc_tdma *v;
3013 	struct rtw89_btc_fbtc_tdma_v3 *v3;
3014 	u16 len = btc->policy_len;
3015 
3016 	if (!btc->update_policy_force &&
3017 	    !memcmp(&dm->tdma, &dm->tdma_now, sizeof(dm->tdma))) {
3018 		rtw89_debug(rtwdev,
3019 			    RTW89_DBG_BTC, "[BTC], %s(): tdma no change!\n",
3020 			    __func__);
3021 		return;
3022 	}
3023 
3024 	tlv = (struct rtw89_btc_btf_tlv *)&btc->policy[len];
3025 	tlv->type = CXPOLICY_TDMA;
3026 	if (ver->fcxtdma == 1) {
3027 		v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0];
3028 		tlv->len = sizeof(*v);
3029 		*v = dm->tdma;
3030 		btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v);
3031 	} else if (ver->fcxtdma == 4 || ver->fcxtdma == 7 || ver->fcxtdma == 8) {
3032 		tlv_v7 = (struct rtw89_btc_btf_tlv_v7 *)&btc->policy[len];
3033 		tlv_v7->len = sizeof(dm->tdma);
3034 		tlv_v7->ver = ver->fcxtdma;
3035 		tlv_v7->type = CXPOLICY_TDMA;
3036 		memcpy(tlv_v7->val, &dm->tdma, tlv_v7->len);
3037 		btc->policy_len += BTC_TLV_HDR_LEN_V7 + tlv_v7->len;
3038 	} else {
3039 		tlv->len = sizeof(*v3);
3040 		v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0];
3041 		v3->fver = ver->fcxtdma;
3042 		v3->tdma = dm->tdma;
3043 		btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3);
3044 	}
3045 
3046 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3047 		    "[BTC], %s(): type:%d, rxflctrl=%d, txflctrl=%d, bind=%d, leak_n=%d, ext_ctrl=%d\n",
3048 		    __func__, dm->tdma.type, dm->tdma.rxflctrl,
3049 		    dm->tdma.txflctrl, dm->tdma.bind, dm->tdma.leak_n,
3050 		    dm->tdma.ext_ctrl);
3051 }
3052 
3053 static void _append_slot_v1(struct rtw89_dev *rtwdev)
3054 {
3055 	struct rtw89_btc *btc = &rtwdev->btc;
3056 	struct rtw89_btc_dm *dm = &btc->dm;
3057 	struct rtw89_btc_btf_tlv *tlv = NULL;
3058 	struct btc_fbtc_1slot *v = NULL;
3059 	u16 len = 0;
3060 	u8 i, cnt = 0;
3061 
3062 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3063 		    "[BTC], %s(): A:btc->policy_len = %d\n",
3064 		    __func__, btc->policy_len);
3065 
3066 	for (i = 0; i < CXST_MAX; i++) {
3067 		if (!btc->update_policy_force &&
3068 		    !memcmp(&dm->slot.v1[i], &dm->slot_now.v1[i],
3069 			    sizeof(dm->slot.v1[i])))
3070 			continue;
3071 
3072 		len = btc->policy_len;
3073 
3074 		tlv = (struct rtw89_btc_btf_tlv *)&btc->policy[len];
3075 		v = (struct btc_fbtc_1slot *)&tlv->val[0];
3076 		tlv->type = CXPOLICY_SLOT;
3077 		tlv->len = sizeof(*v);
3078 
3079 		v->fver = btc->ver->fcxslots;
3080 		v->sid = i;
3081 		v->slot = dm->slot.v1[i];
3082 
3083 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3084 			    "[BTC], %s(): slot-%d: dur=%d, table=0x%08x, type=%d\n",
3085 			    __func__, i, dm->slot.v1[i].dur, dm->slot.v1[i].cxtbl,
3086 			    dm->slot.v1[i].cxtype);
3087 		cnt++;
3088 
3089 		btc->policy_len += BTC_TLV_HDR_LEN  + sizeof(*v);
3090 	}
3091 
3092 	if (cnt > 0)
3093 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3094 			    "[BTC], %s(): slot update (cnt=%d)!!\n",
3095 			    __func__, cnt);
3096 }
3097 
3098 static void _append_slot_v7(struct rtw89_dev *rtwdev)
3099 {
3100 	struct rtw89_btc_btf_tlv_v7 *tlv = NULL;
3101 	struct rtw89_btc *btc = &rtwdev->btc;
3102 	struct rtw89_btc_dm *dm = &btc->dm;
3103 	u8 i, cnt = 0;
3104 	u16 len;
3105 
3106 	for (i = 0; i < CXST_MAX; i++) {
3107 		if (!btc->update_policy_force &&
3108 		    !memcmp(&dm->slot.v7[i], &dm->slot_now.v7[i],
3109 			    sizeof(dm->slot.v7[i])))
3110 			continue;
3111 
3112 		len = btc->policy_len;
3113 
3114 		if (!tlv) {
3115 			if ((len + BTC_TLV_HDR_LEN_V7) > RTW89_BTC_POLICY_MAXLEN) {
3116 				rtw89_debug(rtwdev, RTW89_DBG_BTC,
3117 					    "[BTC], %s(): buff overflow!\n", __func__);
3118 				break;
3119 			}
3120 
3121 			tlv = (struct rtw89_btc_btf_tlv_v7 *)&btc->policy[len];
3122 			tlv->type = CXPOLICY_SLOT;
3123 			tlv->ver = btc->ver->fcxslots;
3124 			tlv->len = sizeof(dm->slot.v7[0]) + BTC_TLV_SLOT_ID_LEN_V7;
3125 			len += BTC_TLV_HDR_LEN_V7;
3126 		}
3127 
3128 		if ((len + (u16)tlv->len) > RTW89_BTC_POLICY_MAXLEN) {
3129 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
3130 				    "[BTC], %s(): buff overflow!\n", __func__);
3131 			break;
3132 		}
3133 
3134 		btc->policy[len] = i; /* slot-id */
3135 		memcpy(&btc->policy[len + 1], &dm->slot.v7[i],
3136 		       sizeof(dm->slot.v7[0]));
3137 		len += tlv->len;
3138 
3139 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3140 			    "[BTC], %s: policy_len=%d, slot-%d: dur=%d, type=%d, table=0x%08x\n",
3141 			    __func__, btc->policy_len, i, dm->slot.v7[i].dur,
3142 			    dm->slot.v7[i].cxtype, dm->slot.v7[i].cxtbl);
3143 		cnt++;
3144 		btc->policy_len = len; /* update total length */
3145 	}
3146 
3147 	if (cnt > 0)
3148 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3149 			    "[BTC], %s: slot update (cnt=%d, len=%d)!!\n",
3150 			    __func__, cnt, btc->policy_len);
3151 }
3152 
3153 static void _append_slot(struct rtw89_dev *rtwdev)
3154 {
3155 	struct rtw89_btc *btc = &rtwdev->btc;
3156 
3157 	if (btc->ver->fcxslots == 2 || btc->ver->fcxslots == 7)
3158 		_append_slot_v7(rtwdev);
3159 	else
3160 		_append_slot_v1(rtwdev);
3161 }
3162 
3163 static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
3164 {
3165 	struct rtw89_btc *btc = &rtwdev->btc;
3166 	const struct rtw89_btc_ver *ver = btc->ver;
3167 	u32 bit_map = 0;
3168 
3169 	switch (rpt_map) {
3170 	case RPT_EN_TDMA:
3171 		bit_map = BIT(0);
3172 		break;
3173 	case RPT_EN_CYCLE:
3174 		bit_map = BIT(1);
3175 		break;
3176 	case RPT_EN_MREG:
3177 		bit_map = BIT(2);
3178 		break;
3179 	case RPT_EN_BT_VER_INFO:
3180 		bit_map = BIT(3);
3181 		break;
3182 	case RPT_EN_BT_SCAN_INFO:
3183 		bit_map = BIT(4);
3184 		break;
3185 	case RPT_EN_BT_DEVICE_INFO:
3186 		switch (ver->frptmap) {
3187 		case 0:
3188 		case 1:
3189 		case 2:
3190 			bit_map = BIT(6);
3191 			break;
3192 		case 3:
3193 		case 4:
3194 		case 5:
3195 		case 105:
3196 			bit_map = BIT(5);
3197 			break;
3198 		default:
3199 			break;
3200 		}
3201 		break;
3202 	case RPT_EN_BT_AFH_MAP:
3203 		switch (ver->frptmap) {
3204 		case 0:
3205 		case 1:
3206 		case 2:
3207 			bit_map = BIT(5);
3208 			break;
3209 		case 3:
3210 		case 4:
3211 		case 5:
3212 		case 105:
3213 			bit_map = BIT(6);
3214 			break;
3215 		default:
3216 			break;
3217 		}
3218 		break;
3219 	case RPT_EN_BT_AFH_MAP_LE:
3220 		switch (ver->frptmap) {
3221 		case 2:
3222 			bit_map = BIT(8);
3223 			break;
3224 		case 3:
3225 		case 4:
3226 		case 5:
3227 		case 105:
3228 			bit_map = BIT(7);
3229 			break;
3230 		default:
3231 			break;
3232 		}
3233 		break;
3234 	case RPT_EN_BT_TX_PWR_LVL:
3235 		switch (ver->frptmap) {
3236 		case 0:
3237 		case 1:
3238 		case 2:
3239 		case 3:
3240 		case 105:
3241 			break;
3242 		case 4:
3243 		case 5:
3244 			bit_map = BIT(8);
3245 			break;
3246 		default:
3247 			break;
3248 		}
3249 		break;
3250 	case RPT_EN_FW_STEP_INFO:
3251 		switch (ver->frptmap) {
3252 		case 1:
3253 		case 2:
3254 			bit_map = BIT(7);
3255 			break;
3256 		case 3:
3257 		case 105:
3258 			bit_map = BIT(8);
3259 			break;
3260 		case 4:
3261 		case 5:
3262 			bit_map = BIT(9);
3263 			break;
3264 		default:
3265 			break;
3266 		}
3267 		break;
3268 	case RPT_EN_TEST:
3269 		if (ver->frptmap == 5)
3270 			bit_map = BIT(10);
3271 		else if (ver->frptmap == 105)
3272 			bit_map = BIT(9);
3273 		else
3274 			bit_map = BIT(31);
3275 		break;
3276 	case RPT_EN_WL_ALL:
3277 		switch (ver->frptmap) {
3278 		case 0:
3279 		case 1:
3280 		case 2:
3281 			bit_map = GENMASK(2, 0);
3282 			break;
3283 		case 3:
3284 		case 105:
3285 			bit_map = GENMASK(2, 0) | BIT(8);
3286 			break;
3287 		case 4:
3288 		case 5:
3289 			bit_map = GENMASK(2, 0) | BIT(9);
3290 			break;
3291 		default:
3292 			break;
3293 		}
3294 		break;
3295 	case RPT_EN_BT_ALL:
3296 		switch (ver->frptmap) {
3297 		case 0:
3298 		case 1:
3299 			bit_map = GENMASK(6, 3);
3300 			break;
3301 		case 2:
3302 			bit_map = GENMASK(6, 3) | BIT(8);
3303 			break;
3304 		case 3:
3305 		case 105:
3306 			bit_map = GENMASK(7, 3);
3307 			break;
3308 		case 4:
3309 		case 5:
3310 			bit_map = GENMASK(8, 3);
3311 			break;
3312 		default:
3313 			break;
3314 		}
3315 		break;
3316 	case RPT_EN_ALL:
3317 		switch (ver->frptmap) {
3318 		case 0:
3319 			bit_map = GENMASK(6, 0);
3320 			break;
3321 		case 1:
3322 			bit_map = GENMASK(7, 0);
3323 			break;
3324 		case 2:
3325 		case 3:
3326 			bit_map = GENMASK(8, 0);
3327 			break;
3328 		case 4:
3329 		case 5:
3330 		case 105:
3331 			bit_map = GENMASK(9, 0);
3332 			break;
3333 		default:
3334 			break;
3335 		}
3336 		break;
3337 	case RPT_EN_MONITER:
3338 		switch (ver->frptmap) {
3339 		case 0:
3340 		case 1:
3341 			bit_map = GENMASK(6, 2);
3342 			break;
3343 		case 2:
3344 			bit_map = GENMASK(6, 2) | BIT(8);
3345 			break;
3346 		case 3:
3347 		case 105:
3348 			bit_map = GENMASK(8, 2);
3349 			break;
3350 		case 4:
3351 		case 5:
3352 			bit_map = GENMASK(9, 2);
3353 			break;
3354 		default:
3355 			break;
3356 		}
3357 		break;
3358 	}
3359 
3360 	return bit_map;
3361 }
3362 
3363 static void rtw89_btc_fw_set_slots(struct rtw89_dev *rtwdev)
3364 {
3365 	struct rtw89_btc *btc = &rtwdev->btc;
3366 	const struct rtw89_btc_ver *ver = btc->ver;
3367 	struct rtw89_btc_btf_tlv_v7 *tlv_v7 = NULL;
3368 	struct rtw89_btc_btf_set_slot_table *tbl;
3369 	struct rtw89_btc_dm *dm = &btc->dm;
3370 	u16 n, len;
3371 
3372 	if (ver->fcxslots == 2 || ver->fcxslots == 7) {
3373 		len = sizeof(*tlv_v7) + sizeof(dm->slot.v7);
3374 		tlv_v7 = kmalloc(len, GFP_KERNEL);
3375 		if (!tlv_v7)
3376 			return;
3377 
3378 		tlv_v7->type = SET_SLOT_TABLE;
3379 		tlv_v7->ver = ver->fcxslots;
3380 		tlv_v7->len = ARRAY_SIZE(dm->slot.v7);
3381 		memcpy(tlv_v7->val, dm->slot.v7, sizeof(dm->slot.v7));
3382 
3383 		_send_fw_cmd(rtwdev, BTFC_SET, SET_SLOT_TABLE, (u8 *)tlv_v7, len);
3384 
3385 		kfree(tlv_v7);
3386 	} else {
3387 		n = struct_size(tbl, tbls, CXST_MAX);
3388 		tbl = kmalloc(n, GFP_KERNEL);
3389 		if (!tbl)
3390 			return;
3391 
3392 		tbl->fver = BTF_SET_SLOT_TABLE_VER;
3393 		tbl->tbl_num = CXST_MAX;
3394 		memcpy(tbl->tbls, dm->slot.v1, flex_array_size(tbl, tbls, CXST_MAX));
3395 
3396 		_send_fw_cmd(rtwdev, BTFC_SET, SET_SLOT_TABLE, tbl, n);
3397 
3398 		kfree(tbl);
3399 	}
3400 }
3401 
3402 static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev,
3403 				bool force_exec, u32 rpt_map)
3404 {
3405 	struct rtw89_btc *btc = &rtwdev->btc;
3406 	struct rtw89_btc_btf_fwinfo *fwinfo = &btc->fwinfo;
3407 	union rtw89_fbtc_rtp_ctrl r;
3408 	int ret;
3409 	u32 i;
3410 
3411 	if (!force_exec && rpt_map == fwinfo->rpt_en_map)
3412 		return;
3413 
3414 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): rpt_map=%x\n",
3415 		    __func__, fwinfo->rpt_en_map);
3416 
3417 	if (btc->ver->fcxbtcrpt == 7 ||
3418 	    btc->ver->fcxbtcrpt == 8 ||
3419 	    btc->ver->fcxbtcrpt == 9 ||
3420 	    btc->ver->fcxbtcrpt == 11 ||
3421 	    btc->ver->fcxbtcrpt == 205) {
3422 		r.v8.type = SET_REPORT_EN;
3423 		if (btc->ver->fcxbtcrpt == 205)
3424 			r.v8.fver = 5;
3425 		else
3426 			r.v8.fver = btc->ver->fcxbtcrpt;
3427 		r.v8.len = sizeof(r.v8.map);
3428 		r.v8.map = cpu_to_le32(rpt_map);
3429 		ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r.v8,
3430 				   sizeof(r.v8));
3431 	} else {
3432 		if (btc->ver->fcxbtcrpt == 105)
3433 			r.v1.fver = 5;
3434 		else
3435 			r.v1.fver = btc->ver->fcxbtcrpt;
3436 
3437 		for (i = 0; i < RPT_EN_MONITER; i++) {
3438 			r.v1.enable = cpu_to_le32(i);
3439 			if (rpt_map & BIT(i))
3440 				r.v1.para = cpu_to_le32(1);
3441 			else
3442 				r.v1.para = 0;
3443 
3444 			ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN,
3445 					   &r.v1, sizeof(r.v1));
3446 		}
3447 	}
3448 
3449 	if (!ret)
3450 		fwinfo->rpt_en_map = rpt_map;
3451 }
3452 
3453 static void btc_fw_set_monreg(struct rtw89_dev *rtwdev)
3454 {
3455 	const struct rtw89_chip_info *chip = rtwdev->chip;
3456 	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
3457 	struct rtw89_btc_btf_set_mon_reg_v1 *v1 = NULL;
3458 	struct rtw89_btc_btf_set_mon_reg_v7 *v7 = NULL;
3459 	u8 i, n, ulen, cxmreg_max;
3460 	u16 sz = 0;
3461 
3462 	n = chip->mon_reg_num;
3463 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3464 		    "[BTC], %s(): mon_reg_num=%d\n", __func__, n);
3465 
3466 	if (ver->fcxmreg == 1)
3467 		cxmreg_max = CXMREG_MAX;
3468 	else
3469 		cxmreg_max = CXMREG_MAX_V2;
3470 
3471 	if (n > cxmreg_max) {
3472 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3473 			    "[BTC], %s(): mon reg count %d > %d\n",
3474 			    __func__, n, cxmreg_max);
3475 		return;
3476 	}
3477 
3478 	ulen = sizeof(struct rtw89_btc_fbtc_mreg);
3479 
3480 	if (ver->fcxmreg == 7) {
3481 		sz = struct_size(v7, regs, n);
3482 		v7 = kmalloc(sz, GFP_KERNEL);
3483 		if (!v7)
3484 			return;
3485 		v7->type = RPT_EN_MREG;
3486 		v7->fver = ver->fcxmreg;
3487 		v7->len = n;
3488 		for (i = 0; i < n; i++) {
3489 			v7->regs[i].type = chip->mon_reg[i].type;
3490 			v7->regs[i].bytes = chip->mon_reg[i].bytes;
3491 			v7->regs[i].offset = chip->mon_reg[i].offset;
3492 		}
3493 
3494 		_send_fw_cmd(rtwdev, BTFC_SET, SET_MREG_TABLE, v7, sz);
3495 		kfree(v7);
3496 	} else {
3497 		sz = struct_size(v1, regs, n);
3498 		v1 = kmalloc(sz, GFP_KERNEL);
3499 		if (!v1)
3500 			return;
3501 		v1->fver = ver->fcxmreg;
3502 		v1->reg_num = n;
3503 		memcpy(v1->regs, chip->mon_reg, flex_array_size(v1, regs, n));
3504 
3505 		_send_fw_cmd(rtwdev, BTFC_SET, SET_MREG_TABLE, v1, sz);
3506 		kfree(v1);
3507 	}
3508 
3509 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3510 		    "[BTC], %s(): sz=%d ulen=%d n=%d\n",
3511 		    __func__, sz, ulen, n);
3512 }
3513 
3514 static void _update_dm_step(struct rtw89_dev *rtwdev,
3515 			    enum btc_reason_and_action reason_or_action)
3516 {
3517 	struct rtw89_btc *btc = &rtwdev->btc;
3518 	struct rtw89_btc_dm *dm = &btc->dm;
3519 
3520 	/* use ring-structure to store dm step */
3521 	dm->dm_step.step[dm->dm_step.step_pos] = reason_or_action;
3522 	dm->dm_step.step_pos++;
3523 
3524 	if (dm->dm_step.step_pos >= ARRAY_SIZE(dm->dm_step.step)) {
3525 		dm->dm_step.step_pos = 0;
3526 		dm->dm_step.step_ov = true;
3527 	}
3528 }
3529 
3530 static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
3531 			   enum btc_reason_and_action action)
3532 {
3533 	struct rtw89_btc *btc = &rtwdev->btc;
3534 	struct rtw89_btc_dm *dm = &btc->dm;
3535 	int ret;
3536 
3537 	dm->run_action = action;
3538 
3539 	_update_dm_step(rtwdev, action | BTC_ACT_EXT_BIT);
3540 	_update_dm_step(rtwdev, policy_type | BTC_POLICY_EXT_BIT);
3541 
3542 	btc->policy_len = 0;
3543 	btc->policy_type = policy_type;
3544 
3545 	_append_tdma(rtwdev);
3546 	_append_slot(rtwdev);
3547 
3548 	if (btc->policy_len == 0 || btc->policy_len > RTW89_BTC_POLICY_MAXLEN)
3549 		return;
3550 
3551 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3552 		    "[BTC], %s(): action = %d -> policy type/len: 0x%04x/%d\n",
3553 		    __func__, action, policy_type, btc->policy_len);
3554 
3555 	if (dm->tdma.rxflctrl == CXFLC_NULLP ||
3556 	    dm->tdma.rxflctrl == CXFLC_QOSNULL)
3557 		btc->btc_ctrl_lps = 1;
3558 	else
3559 		btc->btc_ctrl_lps = dm->lps_ctrl_scbd;
3560 
3561 	if (btc->btc_ctrl_lps == 1)
3562 		rtw89_set_coex_ctrl_lps(rtwdev, btc->btc_ctrl_lps);
3563 
3564 	ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_CX_POLICY,
3565 			   btc->policy, btc->policy_len);
3566 	if (!ret) {
3567 		memcpy(&dm->tdma_now, &dm->tdma, sizeof(dm->tdma_now));
3568 		if (btc->ver->fcxslots == 2 || btc->ver->fcxslots == 7)
3569 			memcpy(&dm->slot_now.v7, &dm->slot.v7, sizeof(dm->slot_now.v7));
3570 		else
3571 			memcpy(&dm->slot_now.v1, &dm->slot.v1, sizeof(dm->slot_now.v1));
3572 	}
3573 
3574 	if (btc->update_policy_force)
3575 		btc->update_policy_force = false;
3576 
3577 	if (btc->btc_ctrl_lps == 0)
3578 		rtw89_set_coex_ctrl_lps(rtwdev, btc->btc_ctrl_lps);
3579 }
3580 
3581 static u8 _get_gpiosig_for_ver(struct rtw89_dev *rtwdev, u8 sig_v8)
3582 {
3583 	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
3584 
3585 	/* v8: gpio_ver >= 8, directly use v8 signal ID */
3586 	if (ver->fcxgpiodbg >= 8)
3587 		return sig_v8;
3588 
3589 	/* v7: gpio_ver < 8, convert v8 signal ID to v7 signal ID */
3590 	if (sig_v8 <= BTC_DBG_GNT_WL) {
3591 		return sig_v8;
3592 	} else if (sig_v8 <= BTC_DBG_GNT_WL1) {
3593 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3594 			    "[BTC], %s(): sig %d not supported in v7\n",
3595 			    __func__, sig_v8);
3596 		return BTC_DBG_NUM;
3597 	} else if (sig_v8 >= BTC_DBG_NUM) {
3598 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3599 			    "[BTC], %s(): sig %d not available\n",
3600 			    __func__, sig_v8);
3601 		return BTC_DBG_NUM;
3602 	} else {
3603 		return sig_v8 - 2;
3604 	}
3605 }
3606 
3607 static u32 _convert_gpio_enmap_to_ver(struct rtw89_dev *rtwdev, u32 en_map_v8)
3608 {
3609 	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
3610 	u32 en_map_v7 = 0;
3611 	u32 bit;
3612 
3613 	/* v8: gpio_ver >= 8, directly use v8 en_map */
3614 	if (ver->fcxgpiodbg >= 8)
3615 		return en_map_v8;
3616 
3617 	/* v7: gpio_ver < 8, convert v8 en_map bitmap to v7 en_map bitmap */
3618 	/* bit 0-1: GNT_BT, GNT_WL - same position in both versions */
3619 	en_map_v7 |= en_map_v8 & GENMASK(1, 0);
3620 
3621 	/* bit 2-3: GNT_BT1, GNT_WL1 - not supported in v7, skip these bits */
3622 
3623 	/* bit 4-31: shift right by 2 positions (become bit 2-29 in v7) */
3624 	for (bit = BTC_DBG_BCN_EARLY; bit < BTC_DBG_NUM; bit++) {
3625 		if (en_map_v8 & BIT(bit))
3626 			en_map_v7 |= BIT(bit - 2);
3627 	}
3628 
3629 	return en_map_v7;
3630 }
3631 
3632 static u32 _convert_gpio_enmap_from_ver(struct rtw89_dev *rtwdev, u32 en_map)
3633 {
3634 	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
3635 	u32 en_map_v8 = 0;
3636 	u32 bit;
3637 
3638 	if (ver->fcxgpiodbg >= 8)
3639 		return en_map;
3640 
3641 	/* bit 0-1: GNT_BT, GNT_WL - same position in both versions */
3642 	en_map_v8 |= en_map & GENMASK(1, 0);
3643 
3644 	/* bit 2-29: shift left by 2 positions (become bit 4-31 in v8) */
3645 	for (bit = BTC_DBG_GNT_BT1; bit < BTC_DBG_NUM - 2; bit++) {
3646 		if (en_map & BIT(bit))
3647 			en_map_v8 |= BIT(bit + 2);
3648 	}
3649 
3650 	return en_map_v8;
3651 }
3652 
3653 static void _fw_set_gpio(struct rtw89_dev *rtwdev, u8 type, u32 val)
3654 {
3655 	struct rtw89_btc *btc = &rtwdev->btc;
3656 	struct rtw89_fbtc_h2c_set_gpio *gpio = &btc->gpio;
3657 	const struct rtw89_btc_ver *ver = btc->ver;
3658 	struct rtw89_fbtc_h2c_set_gpio_2b l2_h2c;
3659 	struct rtw89_fbtc_h2c_set_gpio_4b l4_h2c;
3660 	u8 gpio_ver = ver->fcxgpiodbg;
3661 	u8 buf[sizeof(l4_h2c)];
3662 	u8 len;
3663 
3664 	if (gpio_ver < 8 && type > CXDGPIO_MUX_MAP)
3665 		return;
3666 
3667 	if (type >= CXDGPIO_MAX)
3668 		return;
3669 
3670 	switch (type) {
3671 	case CXDGPIO_EN_MAP: /* GPIO debug signal en-map 0~31 */
3672 		val = _convert_gpio_enmap_to_ver(rtwdev, val);
3673 		gpio->en_map.data.type = CXDGPIO_EN_MAP;
3674 		gpio->en_map.data.fver = gpio_ver;
3675 		gpio->en_map.data.dlen = CXDGPIO_SET_L4;
3676 		gpio->en_map.data.en_map = val;
3677 		l4_h2c = gpio->en_map.fmt;
3678 		put_unaligned_le32(val, (u32 *)l4_h2c.data);
3679 		memcpy(buf, &l4_h2c, sizeof(l4_h2c));
3680 		len = sizeof(l4_h2c);
3681 		break;
3682 	case CXDGPIO_MUX_MAP: /* GPIO dbg: Signal to GPIO Mux */
3683 		gpio->mux.data.type = CXDGPIO_MUX_MAP;
3684 		gpio->mux.data.fver = gpio_ver;
3685 		gpio->mux.data.dlen = CXDGPIO_SET_L2;
3686 		gpio->mux.data.sig = _get_gpiosig_for_ver(rtwdev,
3687 							  FIELD_GET(GENMASK(7, 0), val));
3688 		if (gpio->mux.data.sig >= BTC_DBG_NUM)
3689 			return;
3690 		gpio->mux.data.gpio = FIELD_GET(GENMASK(15, 8), val);
3691 		l2_h2c = gpio->mux.fmt;
3692 		memcpy(buf, &l2_h2c, sizeof(l2_h2c));
3693 		len = sizeof(l2_h2c);
3694 		break;
3695 	case CXDGPIO_EXT_HPTA: /* GPIO config for Ext HW-PTA */
3696 		gpio->ext_pta.data.type = CXDGPIO_EXT_HPTA;
3697 		gpio->ext_pta.data.fver = gpio_ver;
3698 		gpio->ext_pta.data.dlen = CXDGPIO_SET_L2;
3699 		gpio->ext_pta.data.map_low = FIELD_GET(GENMASK(7, 0), val);
3700 		gpio->ext_pta.data.map_high = FIELD_GET(GENMASK(15, 8), val);
3701 		l2_h2c = gpio->ext_pta.fmt;
3702 		memcpy(buf, &l2_h2c, sizeof(l2_h2c));
3703 		len = sizeof(l2_h2c);
3704 		break;
3705 	case CXDGPIO_EXT_HMBX: /* GPIO config for Ext HW-mailbox */
3706 		gpio->ext_mb.data.type = CXDGPIO_EXT_HMBX;
3707 		gpio->ext_mb.data.fver = gpio_ver;
3708 		gpio->ext_mb.data.dlen = CXDGPIO_SET_L2;
3709 		gpio->ext_mb.data.map_low = FIELD_GET(GENMASK(7, 0), val);
3710 		gpio->ext_mb.data.map_high = FIELD_GET(GENMASK(15, 8), val);
3711 		l2_h2c = gpio->ext_mb.fmt;
3712 		memcpy(buf, &l2_h2c, sizeof(l2_h2c));
3713 		len = sizeof(l2_h2c);
3714 		break;
3715 	case CXDGPIO_EXT_SWOUT: /* GPIO config for Ext SW output (wlan_act) */
3716 		gpio->ext_swout.data.type = CXDGPIO_EXT_SWOUT;
3717 		gpio->ext_swout.data.fver = gpio_ver;
3718 		gpio->ext_swout.data.dlen = CXDGPIO_SET_L2;
3719 		gpio->ext_swout.data.map_low = FIELD_GET(GENMASK(7, 0), val);
3720 		gpio->ext_swout.data.map_high = FIELD_GET(GENMASK(15, 8), val);
3721 		l2_h2c = gpio->ext_swout.fmt;
3722 		memcpy(buf, &l2_h2c, sizeof(l2_h2c));
3723 		len = sizeof(l2_h2c);
3724 		break;
3725 	case CXDGPIO_EXT_SWIN: /* GPIO config for Ext SW input control */
3726 		gpio->ext_swin.data.type = CXDGPIO_EXT_SWIN;
3727 		gpio->ext_swin.data.fver = gpio_ver;
3728 		gpio->ext_swin.data.dlen = CXDGPIO_SET_L4;
3729 		gpio->ext_swin.data.in_map_low = FIELD_GET(GENMASK(7, 0), val);
3730 		gpio->ext_swin.data.in_map_high = FIELD_GET(GENMASK(15, 8), val);
3731 		gpio->ext_swin.data.int_map_low = FIELD_GET(GENMASK(23, 16), val);
3732 		gpio->ext_swin.data.int_map_high = FIELD_GET(GENMASK(31, 24), val);
3733 		l4_h2c = gpio->ext_swin.fmt;
3734 		put_unaligned_le32(val, (u32 *)l4_h2c.data);
3735 		memcpy(buf, &l4_h2c, sizeof(l4_h2c));
3736 		len = sizeof(l4_h2c);
3737 		break;
3738 	default:
3739 		return;
3740 	}
3741 
3742 	_send_fw_cmd(rtwdev, BTFC_SET, SET_GPIO_DBG, buf, len);
3743 }
3744 
3745 static void _set_ext_interface(struct rtw89_dev *rtwdev)
3746 {
3747 	struct rtw89_btc *btc = &rtwdev->btc;
3748 	struct rtw89_btc_cx *cx = &btc->cx;
3749 	u8 bt1_sw_type = BTC_SWITCH_INTERNAL;
3750 	u32 val;
3751 
3752 	if (btc->ver->fcxgpiodbg < 7)
3753 		return;
3754 
3755 	/* if BT1+WL-S0, route DBG_GNT_BT1 to control SPDT */
3756 	if ((rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) &&
3757 	    btc->ver->fcxinit >= 10) {
3758 		if (btc->ver->fcxinit >= 10)
3759 			bt1_sw_type = btc->mdinfo.bt1_sw_type;
3760 		else
3761 			return;
3762 
3763 		if (bt1_sw_type > BTC_SWITCH_INTERNAL) {
3764 			_fw_set_gpio(rtwdev, CXDGPIO_EN_MAP,
3765 				     BIT(BTC_DBG_GNT_BT1));
3766 
3767 			val = (bt1_sw_type << 8) + BTC_DBG_GNT_BT1;
3768 			_fw_set_gpio(rtwdev, CXDGPIO_MUX_MAP, val);
3769 		}
3770 	}
3771 
3772 	/* set GPIO as Ext-PTA interface wire */
3773 	if (cx->bt_ext.hw_coex & BTC_EXTSOC_INTF_PTA)
3774 		_fw_set_gpio(rtwdev, CXDGPIO_EXT_HPTA, cx->bt_ext.hpta_cfg);
3775 
3776 	/* set GPIO as Ext-mailbox interface wire */
3777 	if (cx->bt_ext.hw_coex & BTC_EXTSOC_INTF_MBX)
3778 		_fw_set_gpio(rtwdev, CXDGPIO_EXT_HMBX, cx->bt_ext.hmbx_cfg);
3779 
3780 	/* set GPIO as Ext-SWIO interface wire */
3781 	if (cx->bt_ext.hw_coex & BTC_EXTSOC_INTF_SWIO) {
3782 		_fw_set_gpio(rtwdev, CXDGPIO_EXT_SWOUT, cx->bt_ext.swout_cfg);
3783 		_fw_set_gpio(rtwdev, CXDGPIO_EXT_SWIN, cx->bt_ext.swin_cfg);
3784 	}
3785 }
3786 
3787 static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
3788 {
3789 	struct rtw89_btc *btc = &rtwdev->btc;
3790 	const struct rtw89_btc_ver *ver = btc->ver;
3791 
3792 	switch (index) {
3793 	case CXDRVINFO_INIT:
3794 		if (ver->fcxinit == 7 || ver->fcxinit == 107)
3795 			rtw89_fw_h2c_cxdrv_init_v7(rtwdev, index);
3796 		else if (ver->fcxinit == 10)
3797 			rtw89_fw_h2c_cxdrv_init_v10(rtwdev, index);
3798 		else if (ver->fcxinit == 11)
3799 			rtw89_fw_h2c_cxdrv_init_v11(rtwdev, index);
3800 		else
3801 			rtw89_fw_h2c_cxdrv_init(rtwdev, index);
3802 		break;
3803 	case CXDRVINFO_ROLE:
3804 		if (ver->fwlrole == 0)
3805 			rtw89_fw_h2c_cxdrv_role(rtwdev, index);
3806 		else if (ver->fwlrole == 1)
3807 			rtw89_fw_h2c_cxdrv_role_v1(rtwdev, index);
3808 		else if (ver->fwlrole == 101)
3809 			rtw89_fw_h2c_cxdrv_role_v101(rtwdev, index);
3810 		else if (ver->fwlrole == 2)
3811 			rtw89_fw_h2c_cxdrv_role_v2(rtwdev, index);
3812 		else if (ver->fwlrole == 7)
3813 			rtw89_fw_h2c_cxdrv_role_v7(rtwdev, index);
3814 		else if (ver->fwlrole == 8)
3815 			rtw89_fw_h2c_cxdrv_role_v8(rtwdev, index);
3816 		else if (ver->fwlrole == 10)
3817 			rtw89_fw_h2c_cxdrv_role_v10(rtwdev, index);
3818 		else if (ver->fwlrole == 11)
3819 			rtw89_fw_h2c_cxdrv_role_v11(rtwdev, index);
3820 		break;
3821 	case CXDRVINFO_CTRL:
3822 		if (ver->drvinfo_ver != 0)
3823 			index = 2;
3824 
3825 		if (ver->fcxctrl == 7)
3826 			rtw89_fw_h2c_cxdrv_ctrl_v7(rtwdev, index);
3827 		else if (ver->fcxctrl == 9)
3828 			rtw89_fw_h2c_cxdrv_ctrl_v9(rtwdev, index);
3829 		else
3830 			rtw89_fw_h2c_cxdrv_ctrl(rtwdev, index);
3831 		break;
3832 	case CXDRVINFO_TRX:
3833 		if (ver->drvinfo_ver > 1)
3834 			index = 3;
3835 
3836 		if (ver->fcxtrx == 0)
3837 			return;
3838 
3839 		if (ver->fcxtrx == 7)
3840 			rtw89_fw_h2c_cxdrv_trx_v7(rtwdev, index);
3841 		else if (ver->fcxtrx == 9)
3842 			rtw89_fw_h2c_cxdrv_trx_v9(rtwdev, index);
3843 		else if (ver->fcxtrx == 107)
3844 			rtw89_fw_h2c_cxdrv_trx_v107(rtwdev, index);
3845 		break;
3846 	case CXDRVINFO_RFK:
3847 		if (ver->drvinfo_ver != 0)
3848 			return;
3849 
3850 		rtw89_fw_h2c_cxdrv_rfk(rtwdev, index);
3851 		break;
3852 	case CXDRVINFO_TXPWR:
3853 		if (ver->drvinfo_ver == 3 || ver->drvinfo_ver == 103)
3854 			index = 4;
3855 
3856 		if (ver->fcxtxpwr == 1)
3857 			rtw89_fw_h2c_cxtxpwr_v9(rtwdev, index, 1);
3858 		else if (ver->fcxtrx == 7 || ver->fcxtrx == 107)
3859 			rtw89_fw_h2c_cxtxpwr_v7(rtwdev, index);
3860 		else if (ver->fcxtrx == 9)
3861 			rtw89_fw_h2c_cxtxpwr_v9(rtwdev, index, 9);
3862 		break;
3863 	case CXDRVINFO_FDDT:
3864 		if (ver->drvinfo_ver == 3 || ver->drvinfo_ver == 103)
3865 			index = 5;
3866 		else
3867 			return;
3868 
3869 		break;
3870 	case CXDRVINFO_MLO:
3871 		if (!ver->fcxmlo || ver->drvinfo_ver == 103)
3872 			return;
3873 
3874 		if (ver->drvinfo_ver == 3)
3875 			index = 6;
3876 		else
3877 			return;
3878 
3879 		if (ver->fcxmlo == 2)
3880 			rtw89_fw_h2c_cxdrv_mlo_v2(rtwdev, index);
3881 
3882 		break;
3883 	case CXDRVINFO_OSI:
3884 		if (!ver->fcxosi || ver->drvinfo_ver == 103)
3885 			return;
3886 
3887 		if (ver->drvinfo_ver == 3)
3888 			index = 7;
3889 		else
3890 			return;
3891 
3892 		if (ver->fcxosi == 1)
3893 			rtw89_fw_h2c_cxdrv_osi_info(rtwdev, index);
3894 		else if (ver->fcxosi == 6)
3895 			rtw89_fw_h2c_cxdrv_osi_info_v6(rtwdev, index);
3896 		else if (ver->fcxosi == 7)
3897 			rtw89_fw_h2c_cxdrv_osi_info_v7(rtwdev, index);
3898 		else
3899 			return;
3900 		break;
3901 	default:
3902 		break;
3903 	}
3904 }
3905 
3906 static
3907 void btc_fw_event(struct rtw89_dev *rtwdev, u8 evt_id, void *data, u32 len)
3908 {
3909 	struct rtw89_btc *btc = &rtwdev->btc;
3910 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
3911 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
3912 	u8 i;
3913 
3914 	_parse_btc_report(rtwdev, pfwinfo, data, len);
3915 
3916 	if (!rtwdev->chip->scbd)
3917 		return;
3918 
3919 	if (!btc->dm.scbd_b2w_update)
3920 		return; /* skip if init or no-update */
3921 
3922 	for (i = BTC_BT_1ST; i <= BTC_BT_2ND; i++) {
3923 		bt = (i == BTC_BT_1ST) ? &btc->cx.bt0 : &btc->cx.bt1;
3924 
3925 		if (bt->scbd_c2h != bt->scbd_rb) {
3926 			/* if btx b2w scbd non-sync */
3927 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
3928 				    "[BTC], %s() bt%d:c2h->0x%08x, rb->0x%08x\n",
3929 				    __func__, i, bt->scbd_c2h, bt->scbd_rb);
3930 			bt->scbd_c2h = bt->scbd_rb;
3931 			_update_bt_scbd(rtwdev, i, true);
3932 			btc->dm.scbd_b2w_update = false;
3933 		}
3934 	}
3935 
3936 	if (!btc->dm.scbd_b2w_update)
3937 		_run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
3938 	else
3939 		btc->dm.scbd_b2w_update = 0;
3940 }
3941 
3942 static void _set_gnt(struct rtw89_dev *rtwdev, u8 phy_map,
3943 		     u8 wl_state, u8 bt_state, u8 wlact_state)
3944 {
3945 	struct rtw89_btc *btc = &rtwdev->btc;
3946 	struct rtw89_btc_dm *dm = &btc->dm;
3947 	struct rtw89_btc_fbtc_outsrc_set_info *o = &dm->ost_info;
3948 	struct rtw89_mac_ax_wl_act *wlact_set;
3949 	struct rtw89_mac_ax_coex_gnt mg;
3950 	u8 i;
3951 
3952 	if (phy_map > BTC_PHY_ALL)
3953 		return;
3954 
3955 	for (i = 0; i < RTW89_PHY_NUM; i++) {
3956 		if (!(phy_map & BIT(i)))
3957 			continue;
3958 
3959 		switch (wl_state) {
3960 		case BTC_GNT_HW:
3961 			dm->gnt_set[i].gnt_wl_sw_en = 0;
3962 			dm->gnt_set[i].gnt_wl = 0;
3963 			break;
3964 		case BTC_GNT_SW_LO:
3965 			dm->gnt_set[i].gnt_wl_sw_en = 1;
3966 			dm->gnt_set[i].gnt_wl = 0;
3967 			break;
3968 		case BTC_GNT_SW_HI:
3969 			dm->gnt_set[i].gnt_wl_sw_en = 1;
3970 			dm->gnt_set[i].gnt_wl = 1;
3971 			break;
3972 		case BTC_GNT_SET_SKIP:
3973 		default:
3974 			break;
3975 		}
3976 
3977 		switch (bt_state) {
3978 		case BTC_GNT_HW:
3979 			dm->gnt_set[i].gnt_bt0_sw_en = 0;
3980 			dm->gnt_set[i].gnt_bt0 = 0;
3981 			dm->gnt_set[i].gnt_bt1_sw_en = 0;
3982 			dm->gnt_set[i].gnt_bt1 = 0;
3983 			dm->gnt_set[i].gnt_zb_sw_en = 0;
3984 			dm->gnt_set[i].gnt_zb = 0;
3985 			break;
3986 		case BTC_GNT_SW_LO:
3987 			dm->gnt_set[i].gnt_bt0_sw_en = 1;
3988 			dm->gnt_set[i].gnt_bt0 = 0;
3989 			dm->gnt_set[i].gnt_bt1_sw_en = 1;
3990 			dm->gnt_set[i].gnt_bt1 = 0;
3991 			dm->gnt_set[i].gnt_zb_sw_en = 1;
3992 			dm->gnt_set[i].gnt_zb = 0;
3993 			break;
3994 		case BTC_GNT_SW_HI:
3995 			dm->gnt_set[i].gnt_bt0_sw_en = 1;
3996 			dm->gnt_set[i].gnt_bt0 = 1;
3997 			dm->gnt_set[i].gnt_bt1_sw_en = 1;
3998 			dm->gnt_set[i].gnt_bt1 = 1;
3999 			dm->gnt_set[i].gnt_zb_sw_en = 1;
4000 			dm->gnt_set[i].gnt_zb = 1;
4001 			break;
4002 		case BTC_GNT_SET_SKIP:
4003 		default:
4004 			break;
4005 		}
4006 	}
4007 
4008 	for (i = 0; i < BTC_ALL_BT_EZL; i++) {
4009 		if (!(rtwdev->chip->para_ver & BTC_FEAT_WLAN_ACT_MUX))
4010 			break;
4011 
4012 		switch (wlact_state) {
4013 		case BTC_WLACT_HW:
4014 			dm->wlact_set[i].wlan_act_en = 0;
4015 			dm->wlact_set[i].wlan_act = 0;
4016 			break;
4017 		case BTC_WLACT_SW_LO:
4018 			dm->wlact_set[i].wlan_act_en = 1;
4019 			dm->wlact_set[i].wlan_act = 0;
4020 			break;
4021 		case BTC_WLACT_SW_HI:
4022 			dm->wlact_set[i].wlan_act_en = 1;
4023 			dm->wlact_set[i].wlan_act = 1;
4024 			break;
4025 		default:
4026 			break;
4027 		}
4028 
4029 		if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
4030 			break;
4031 	}
4032 
4033 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4034 		    "[BTC], %s(): phy_map=0x%x, gnt_wl:%d, gnt_bt:%d, wl_act:%d\n",
4035 		    __func__, phy_map, wl_state, bt_state, wlact_state);
4036 
4037 	if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO) {
4038 		if (o->rf_band[BTC_RF_S0] == 1 && o->rf_band[BTC_RF_S1] == 0)
4039 			o->rf_gbt_source = BTC_RF_S1;
4040 		else
4041 			o->rf_gbt_source = BTC_RF_S0;
4042 
4043 		memcpy(o->wlact_set, dm->wlact_set, sizeof(o->wlact_set));
4044 
4045 		if (btc->ver->fcxosi == 6 || btc->ver->fcxosi == 7) {
4046 			memcpy(o->gnt_set_be, dm->gnt_set, sizeof(o->gnt_set_be));
4047 			return;
4048 		} else if (btc->ver->fcxosi == 1) {
4049 			for (i = 0; i < RTW89_PHY_NUM; i++) { /* gnt[MAC0/MAC1] */
4050 				mg.band[i].gnt_bt_sw_en = dm->gnt_set[i].gnt_bt0_sw_en;
4051 				mg.band[i].gnt_bt = dm->gnt_set[i].gnt_bt0;
4052 				mg.band[i].gnt_wl_sw_en = dm->gnt_set[i].gnt_wl_sw_en;
4053 				mg.band[i].gnt_wl = dm->gnt_set[i].gnt_wl;
4054 				memcpy(o->gnt_set, mg.band, sizeof(o->gnt_set));
4055 			}
4056 			return;
4057 		}
4058 	}
4059 
4060 	for (i = 0; i < RTW89_PHY_NUM; i++) { /* gnt[MAC0/MAC1] */
4061 		mg.band[i].gnt_bt_sw_en = dm->gnt_set[i].gnt_bt0_sw_en;
4062 		mg.band[i].gnt_bt = dm->gnt_set[i].gnt_bt0;
4063 		mg.band[i].gnt_wl_sw_en = dm->gnt_set[i].gnt_wl_sw_en;
4064 		mg.band[i].gnt_wl = dm->gnt_set[i].gnt_wl;
4065 	}
4066 	for (i = 0; i < BTC_ALL_BT; i++) { /* wlact[BT0/BT1] */
4067 		wlact_set = &dm->wlact_set[i];
4068 		mg.bt[i].wlan_act_en = wlact_set->wlan_act_en;
4069 		mg.bt[i].wlan_act = wlact_set->wlan_act;
4070 	}
4071 
4072 	rtw89_chip_mac_cfg_gnt(rtwdev, &mg);
4073 }
4074 
4075 #define BTC_TDMA_WLROLE_MAX 3
4076 
4077 static void _set_bt_ignore_wlan_act(struct rtw89_dev *rtwdev, u8 enable)
4078 {
4079 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4080 		    "[BTC], %s(): set bt %s wlan_act\n", __func__,
4081 		    enable ? "ignore" : "do not ignore");
4082 
4083 	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_IGNORE_WLAN_ACT, &enable, 1);
4084 }
4085 
4086 #define WL_TX_POWER_NO_BTC_CTRL	GENMASK(31, 0)
4087 #define WL_TX_POWER_ALL_TIME GENMASK(15, 0)
4088 #define WL_TX_POWER_WITH_BT GENMASK(31, 16)
4089 #define WL_TX_POWER_INT_PART GENMASK(8, 2)
4090 #define WL_TX_POWER_FRA_PART GENMASK(1, 0)
4091 #define B_BTC_WL_TX_POWER_SIGN BIT(7)
4092 #define B_TSSI_WL_TX_POWER_SIGN BIT(8)
4093 #define SET_RF_PARA_AX_LEN 1
4094 
4095 static void _set_wl_tx_power(struct rtw89_dev *rtwdev, u32 level, u8 phy_map)
4096 {
4097 	const struct rtw89_chip_info *chip = rtwdev->chip;
4098 	struct rtw89_btc *btc = &rtwdev->btc;
4099 	const struct rtw89_btc_ver *ver = btc->ver;
4100 	struct rtw89_btc_dm *dm = &btc->dm;
4101 	bool level_chg = false;
4102 	u32 pwr_val;
4103 
4104 	if (phy_map & BIT(RTW89_PHY_0))
4105 		level_chg = !(dm->rf_trx_para.wl_tx_power[RTW89_PHY_0] == level);
4106 
4107 	if (phy_map & BIT(RTW89_PHY_1))
4108 		level_chg |= !(dm->rf_trx_para.wl_tx_power[RTW89_PHY_1] == level);
4109 
4110 	if (!level_chg && !btc->cli_h2c_cmd)
4111 		return;
4112 
4113 	if (phy_map & BIT(RTW89_PHY_0))
4114 		dm->rf_trx_para.wl_tx_power[RTW89_PHY_0] = level;
4115 
4116 	if (phy_map & BIT(RTW89_PHY_1))
4117 		dm->rf_trx_para.wl_tx_power[RTW89_PHY_1] = level;
4118 
4119 	dm->wl_tx_pwr_phy_map = phy_map;
4120 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4121 		    "[BTC], %s(): phy_map=0x%x, wl_tx_pwr-> phy0=%d, phy1=%d\n",
4122 		    __func__, phy_map,
4123 		    dm->rf_trx_para.wl_tx_power[RTW89_PHY_0],
4124 		    dm->rf_trx_para.wl_tx_power[RTW89_PHY_1]);
4125 
4126 	if ((ver->fcxtrx == 7 && chip->chip_id == RTL8922A) ||
4127 	    ver->fcxtrx == 107) {
4128 		_fw_set_drv_info(rtwdev, CXDRVINFO_TXPWR);
4129 	} else if (ver->fcxtrx == 9) {
4130 		_fw_set_drv_info(rtwdev, CXDRVINFO_TXPWR);
4131 	} else {
4132 		if (level == RTW89_BTC_WL_DEF_TX_PWR) {
4133 			pwr_val = WL_TX_POWER_NO_BTC_CTRL;
4134 		} else { /* only apply "force tx power" */
4135 			pwr_val = FIELD_PREP(WL_TX_POWER_INT_PART, level);
4136 			if (pwr_val > RTW89_BTC_WL_DEF_TX_PWR)
4137 				pwr_val = RTW89_BTC_WL_DEF_TX_PWR;
4138 
4139 			if (level & B_BTC_WL_TX_POWER_SIGN)
4140 				pwr_val |= B_TSSI_WL_TX_POWER_SIGN;
4141 			pwr_val |= WL_TX_POWER_WITH_BT;
4142 		}
4143 		chip->ops->btc_set_wl_txpwr_ctrl(rtwdev, pwr_val);
4144 	}
4145 }
4146 
4147 static void _set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level, u8 phy_map)
4148 {
4149 	const struct rtw89_chip_info *chip = rtwdev->chip;
4150 	struct rtw89_btc *btc = &rtwdev->btc;
4151 	struct rtw89_btc_dm *dm = &btc->dm;
4152 	bool level_chg = false;
4153 
4154 	if (phy_map & BIT(RTW89_PHY_0))
4155 		level_chg = !(dm->rf_trx_para.wl_rx_gain[RTW89_PHY_0] == level);
4156 
4157 	if (phy_map & BIT(RTW89_PHY_1))
4158 		level_chg |= !(dm->rf_trx_para.wl_rx_gain[RTW89_PHY_1] == level);
4159 
4160 	if (!level_chg && !btc->cli_h2c_cmd)
4161 		return;
4162 
4163 	if (phy_map & BIT(RTW89_PHY_0))
4164 		dm->rf_trx_para.wl_rx_gain[RTW89_PHY_0] = level;
4165 
4166 	if (phy_map & BIT(RTW89_PHY_1))
4167 		dm->rf_trx_para.wl_rx_gain[RTW89_PHY_1] = level;
4168 
4169 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4170 		    "[BTC], %s(): phy_map=0x%x, wl_rx_gain-> phy0=%d, phy1=%d\n",
4171 		    __func__, phy_map,
4172 		    dm->rf_trx_para.wl_rx_gain[RTW89_PHY_0],
4173 		    dm->rf_trx_para.wl_rx_gain[RTW89_PHY_1]);
4174 
4175 	chip->ops->btc_set_wl_rx_gain(rtwdev, level);
4176 }
4177 
4178 static void _set_bt_tx_power(struct rtw89_dev *rtwdev, bool force_exec, u8 bid,
4179 			     u8 rf_band, u8 level)
4180 {
4181 	struct rtw89_btc *btc = &rtwdev->btc;
4182 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
4183 	u8 h2c_func = SET_BT_TX_PWR;
4184 	u8 i, id_start, id_stop;
4185 	u8 buf[2] = {};
4186 	u8 len = sizeof(*buf);
4187 
4188 	if (bt->bcnt[BTC_BCNT_INFOUPDATE] == 0)
4189 		return;
4190 
4191 	if (bt->rf_para.tx_pwr_freerun == level)
4192 		return;
4193 
4194 	if (bid == BTC_ALL_BT) {
4195 		id_start = BTC_BT_1ST;
4196 		id_stop = BTC_BT_2ND;
4197 	} else {
4198 		id_start = bid;
4199 		id_stop = bid;
4200 	}
4201 
4202 	for (i = id_start; i <= id_stop; i++) {
4203 		if (i == BTC_BT_2ND) {
4204 			if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
4205 				continue;
4206 
4207 			bt = &btc->cx.bt1;
4208 			h2c_func |= BT_H2C_FUNC_BT2ND;
4209 		}
4210 
4211 		buf[0] = (s8)(-level);
4212 		buf[1] = rf_band;  /* bit-map: bit1->5GHz/6Ghz, bit0->2.4GHz */
4213 
4214 		if (!force_exec && !btc->cli_h2c_cmd) {
4215 			if (rf_band == BIT(RTW89_BAND_2G) &&
4216 			    bt->tx_power_now == level)
4217 				continue;
4218 			else if (rf_band != BIT(RTW89_BAND_2G) &&
4219 				 bt->tx_power_now_6g == level)
4220 				continue;
4221 		}
4222 
4223 		if (rtwdev->chip->chip_gen == RTW89_CHIP_AX)
4224 			len = SET_RF_PARA_AX_LEN;
4225 
4226 		if (!_send_fw_cmd(rtwdev, BTFC_SET, h2c_func, buf, len)) {
4227 			btc->dm.rf_trx_para.bt_tx_power[i] = level;
4228 			if (rf_band == BIT(RTW89_BAND_2G))
4229 				bt->tx_power_now = level;
4230 			else
4231 				bt->tx_power_now_6g = level;
4232 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
4233 				    "[BTC], %s(): bt%d_tx_power_level = %d\n",
4234 				    __func__, i, level);
4235 		}
4236 	}
4237 }
4238 
4239 #define BTC_BT_RX_NORMAL_LVL 7
4240 static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, bool force_exec, u8 bid,
4241 			    u8 rf_band, u8 level)
4242 {
4243 	struct rtw89_btc *btc = &rtwdev->btc;
4244 	struct rtw89_btc_cx *cx = &btc->cx;
4245 	struct rtw89_btc_bt_info *bt = &cx->bt0;
4246 	u8 h2c_func = SET_BT_LNA_CONSTRAIN;
4247 	u8 i, id_start, id_stop;
4248 	bool state = false;
4249 	u32 scbd_bit = 0;
4250 	u8 buf[2] = {};
4251 	u8 len = sizeof(*buf);
4252 
4253 	if (bt->bcnt[BTC_BCNT_INFOUPDATE] == 0 || !rf_band)
4254 		return;
4255 
4256 	if (bt->rf_para.rx_gain_freerun == level ||
4257 	    level > BTC_BT_RX_NORMAL_LVL || !rtwdev->chip->scbd ||
4258 	    bid > BTC_ALL_BT)
4259 		return;
4260 
4261 	if (bid == BTC_ALL_BT) {
4262 		id_start = BTC_BT_1ST;
4263 		id_stop = BTC_BT_2ND;
4264 	} else {
4265 		id_start = bid;
4266 		id_stop = bid;
4267 	}
4268 
4269 	if (rf_band == BIT(RTW89_BAND_2G))
4270 		scbd_bit |= BTC_WSCB_RXGAIN;
4271 	else
4272 		scbd_bit |= BTC_WSCB_RXGAIN_56G;
4273 
4274 	for (i = id_start; i <= id_stop; i++) {
4275 		if (i == BTC_BT_2ND) {
4276 			if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
4277 				continue;
4278 
4279 			bt = &cx->bt1;
4280 			h2c_func |= BT_H2C_FUNC_BT2ND;
4281 		}
4282 
4283 		/* return if same setup */
4284 		if (!force_exec && !btc->cli_h2c_cmd) {
4285 			if (rf_band == BIT(RTW89_BAND_2G) &&
4286 			    bt->lna_constrain == level)
4287 				continue;
4288 			else if (rf_band != BIT(RTW89_BAND_2G) &&
4289 				 bt->lna_constrain_6g == level)
4290 				continue;
4291 		}
4292 
4293 		buf[0] = level;
4294 		buf[1] = rf_band;
4295 
4296 		if (rtwdev->chip->chip_gen == RTW89_CHIP_AX)
4297 			len = SET_RF_PARA_AX_LEN;
4298 
4299 		if (_send_fw_cmd(rtwdev, BTFC_SET, h2c_func, buf, len)) {
4300 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
4301 				    "[BTC], %s(): bt%d_rx_gain_level = %d\n",
4302 				    __func__, i, level);
4303 		}
4304 
4305 		btc->dm.rf_trx_para.bt_rx_gain[i] = level;
4306 
4307 		if (buf[0] != BTC_BT_RX_NORMAL_LVL)
4308 			state = true;
4309 
4310 		_write_scbd(rtwdev, bid, scbd_bit, state);
4311 	}
4312 }
4313 
4314 static void _set_bt_corx_table(struct rtw89_dev *rtwdev, bool en)
4315 {
4316 	struct rtw89_btc *btc = &rtwdev->btc;
4317 	struct rtw89_btc_cx *cx = &btc->cx;
4318 	struct rtw89_btc_bt_info *bt = &cx->bt0;
4319 	struct rtw89_btc_dm *dm = &btc->dm;
4320 	bool is_24g, is_56g, en_24g, en_56g;
4321 	u8 i;
4322 
4323 	/*
4324 	 * true: bt use Hi-LNA rx gain table (f/e/3/2) in -3x~-9xdBm for co-rx
4325 	 * false: bt use original rx gain table (f/b/7/3/2)
4326 	 */
4327 
4328 	if (btc->dm.fdd_bind.bt_sel == BIT(BTC_BT_EXT))
4329 		return;
4330 
4331 	for (i = BTC_BT_1ST; i <= BTC_BT_2ND; i++) {
4332 		if (i == BTC_BT_2ND) {
4333 			if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
4334 				continue;
4335 			bt = &cx->bt1;
4336 		}
4337 
4338 		is_24g = (dm->corx_map[BTC_RF_S0][i] ||
4339 			  dm->corx_map[BTC_RF_S1][i]) & BIT(RTW89_BAND_2G);
4340 		is_56g = (dm->corx_map[BTC_RF_S0][i] ||
4341 			  dm->corx_map[BTC_RF_S1][i]) & BIT(RTW89_BAND_5G);
4342 
4343 		/*
4344 		 * Request Hi-LNA only when that band is co-rx and enabled.
4345 		 * Evaluate each band bit independently against the BT-mirrored
4346 		 * state so the request can still be cleared once a CO-RX band
4347 		 * disappears (e.g. 2.4 GHz disconnect), avoiding a latched
4348 		 * Hi-LNA request.
4349 		 */
4350 		en_24g = is_24g && en;
4351 		en_56g = is_56g && en;
4352 
4353 		if (en_24g != (!!bt->hi_lna_rx))
4354 			_write_scbd(rtwdev, i, BTC_WSCB_BT_HILNA, en_24g);
4355 
4356 		if (en_56g != (!!bt->hi_lna_rx_6g))
4357 			_write_scbd(rtwdev, i, BTC_WSCB_BT_HILNA_56G, en_56g);
4358 	}
4359 }
4360 
4361 static void _set_rf_trx_para_v9(struct rtw89_dev *rtwdev)
4362 {
4363 	struct rtw89_btc *btc = &rtwdev->btc;
4364 	struct rtw89_btc_cx *cx = &btc->cx;
4365 	struct rtw89_btc_wl_smap *wl_smap = &cx->wl.status.map;
4366 	struct rtw89_btc_dm *dm = &btc->dm;
4367 	bool bt_2r = false;
4368 	u8 wl_stb_chg = 0;
4369 
4370 	if (wl_smap->rf_off || wl_smap->lps == BTC_LPS_RF_OFF)
4371 		return;
4372 
4373 	/* must call after _set_halbb_btg_ctrl() */
4374 	if (dm->tdd_bind.wl_link_mode != BTC_WLINK_NOLINK) {
4375 		wl_stb_chg = 1;
4376 		if (dm->wl_btg_rx)
4377 			bt_2r = true;
4378 	}
4379 
4380 	_set_bt_corx_table(rtwdev, bt_2r);
4381 
4382 	if (wl_stb_chg != dm->wl_stb_chg) {
4383 		dm->wl_stb_chg = wl_stb_chg;
4384 		dm->ost_info.wl_btg_standby_chg = wl_stb_chg;
4385 		rtwdev->chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg);
4386 	}
4387 }
4388 
4389 static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
4390 {
4391 	const struct rtw89_chip_info *chip = rtwdev->chip;
4392 	struct rtw89_btc *btc = &rtwdev->btc;
4393 	const struct rtw89_btc_ver *ver = btc->ver;
4394 	struct rtw89_btc_dm *dm = &btc->dm;
4395 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4396 	struct rtw89_btc_wl_role_info *r = &wl->role_info;
4397 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
4398 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
4399 	struct rtw89_btc_wl_smap *wl_smap = &wl->status.map;
4400 	struct rtw89_btc_rf_trx_para_v9 para;
4401 	u8 bmode = dm->tdd_bind.wl_link_mode;
4402 	u8 rf_band = dm->tdd_bind.rf_band;
4403 	u8 i, ul_para_num, dl_para_num;
4404 	u8 mode = BTC_WLINK_NOLINK;
4405 	u8 bid = BTC_BT_1ST, lv;
4406 	u32 wl_stb_chg;
4407 
4408 	if (ver->fcxtrx == 9) {
4409 		/* Early v9 need to assign UL/DL RF para at driver */
4410 		if (chip->rf_para_ulink_v9) {
4411 			ul_para_num = chip->rf_para_ulink_num_v9;
4412 			dl_para_num = chip->rf_para_dlink_num_v9;
4413 		} else {
4414 			_set_rf_trx_para_v9(rtwdev);
4415 			return;
4416 		}
4417 	} else if ((ver->fcxtrx == 0 || ver->fcxtrx == 7 || ver->fcxtrx == 107) &&
4418 		   chip->rf_para_ulink_v0) {
4419 		ul_para_num = chip->rf_para_ulink_num_v0;
4420 		dl_para_num = chip->rf_para_dlink_num_v0;
4421 	} else {
4422 		rtw89_warn(rtwdev, "[BTC]%s(), No rf_para for version %d\n",
4423 			   __func__, ver->fcxtrx);
4424 		goto next;
4425 	}
4426 
4427 	if (bmode == BTC_WLINK_NOLINK) {
4428 		return;
4429 	} else if (rf_band == BIT(RTW89_BAND_5G)) {
4430 		mode = BTC_WLINK_V0_5G;
4431 	} else if (rf_band == BIT(RTW89_BAND_2G) && bmode == BTC_WLINK_STA) {
4432 		mode = BTC_WLINK_V0_2G_STA;
4433 	}
4434 
4435 	/* decide trx_para_level */
4436 	if (btc->ant_type == BTC_ANT_SHARED) {
4437 		/* fix LNA2 + TIA gain not change by GNT_BT */
4438 		if ((btc->dm.wl_btg_rx && b->link_cnt.now != 0) ||
4439 		    dm->bt_only == 1)
4440 			dm->trx_para_level = 1; /* for better BT ACI issue */
4441 		else
4442 			dm->trx_para_level = 0;
4443 	} else { /* non-shared antenna  */
4444 		dm->trx_para_level = 5;
4445 		/* modify trx_para if WK 2.4G-STA-DL + bt link */
4446 		if (b->link_cnt.now != 0 &&
4447 		    mode == BTC_WLINK_V0_2G_STA &&
4448 		    wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) { /* uplink */
4449 			if (wl->rssi_level == 4 && bt->rssi_level > 2)
4450 				dm->trx_para_level = 6;
4451 			else if (wl->rssi_level == 3 && bt->rssi_level > 3)
4452 				dm->trx_para_level = 7;
4453 		}
4454 	}
4455 
4456 	lv = dm->trx_para_level;
4457 	if (lv >= ul_para_num ||
4458 	    lv >= dl_para_num) {
4459 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4460 			    "[BTC], %s(): invalid level_id: %d\n",
4461 			    __func__, lv);
4462 		return;
4463 	}
4464 
4465 	if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
4466 		if (ver->fcxtrx == 9) {
4467 			para = chip->rf_para_ulink_v9[lv];
4468 		} else {
4469 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++) {
4470 				para.wl_tx_power[i] = chip->rf_para_ulink_v0[lv].wl_tx_power;
4471 				para.wl_rx_gain[i] = chip->rf_para_ulink_v0[lv].wl_rx_gain;
4472 			}
4473 			for (i = BTC_BT_1ST; i < BTC_ALL_BT; i++) {
4474 				para.bt_tx_power[i] = chip->rf_para_ulink_v0[lv].bt_tx_power;
4475 				para.bt_rx_gain[i] = chip->rf_para_ulink_v0[lv].bt_rx_gain;
4476 			}
4477 		}
4478 	} else {
4479 		if (ver->fcxtrx == 9) {
4480 			para = chip->rf_para_dlink_v9[lv];
4481 		} else {
4482 			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++) {
4483 				para.wl_tx_power[i] = chip->rf_para_dlink_v0[lv].wl_tx_power;
4484 				para.wl_rx_gain[i] = chip->rf_para_dlink_v0[lv].wl_rx_gain;
4485 			}
4486 			for (i = BTC_BT_1ST; i < BTC_ALL_BT; i++) {
4487 				para.bt_tx_power[i] = chip->rf_para_dlink_v0[lv].bt_tx_power;
4488 				para.bt_rx_gain[i] = chip->rf_para_dlink_v0[lv].bt_rx_gain;
4489 			}
4490 		}
4491 	}
4492 
4493 	if (dm->fddt_train) {
4494 		_set_wl_rx_gain(rtwdev, 1, RTW89_PHY_0);
4495 		_write_scbd(rtwdev, bid, BTC_WSCB_RXGAIN, true);
4496 	} else {
4497 		_set_wl_tx_power(rtwdev, para.wl_tx_power[RTW89_PHY_0], RTW89_PHY_0);
4498 		_set_wl_rx_gain(rtwdev, para.wl_rx_gain[RTW89_PHY_0], RTW89_PHY_0);
4499 		_set_bt_tx_power(rtwdev, true, bid, rf_band, para.bt_tx_power[BTC_BT_1ST]);
4500 		_set_bt_rx_gain(rtwdev, true, bid, rf_band, para.bt_rx_gain[BTC_BT_1ST]);
4501 	}
4502 
4503 next:
4504 	if (!bt->enable.now || dm->wl_only || wl_smap->rf_off ||
4505 	    wl_smap->lps == BTC_LPS_RF_OFF || mode == BTC_WLINK_V0_5G ||
4506 	    (rtwdev->dbcc_en && r->dbcc_2g_phy != RTW89_PHY_1))
4507 		wl_stb_chg = 0;
4508 	else
4509 		wl_stb_chg = 1;
4510 
4511 	if (wl_stb_chg != dm->wl_stb_chg) {
4512 		dm->wl_stb_chg = wl_stb_chg;
4513 		chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg);
4514 	}
4515 }
4516 
4517 static void _update_btc_state_map(struct rtw89_dev *rtwdev)
4518 {
4519 	struct rtw89_btc *btc = &rtwdev->btc;
4520 	struct rtw89_btc_cx *cx = &btc->cx;
4521 	struct rtw89_btc_wl_info *wl = &cx->wl;
4522 	struct rtw89_btc_bt_info *bt = &cx->bt0;
4523 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
4524 
4525 	if (wl->status.map.dhcp || wl->status.map._4way ||
4526 	    wl->status.map.roaming || wl->status.map.transacting ||
4527 	    wl->status.map.handshake) {
4528 		cx->state_map = BTC_WLINKING;
4529 	} else if (wl->status.map.scan) { /* wl scan */
4530 		if (bt_linfo->status.map.inq_pag)
4531 			cx->state_map = BTC_WSCAN_BSCAN;
4532 		else
4533 			cx->state_map = BTC_WSCAN_BNOSCAN;
4534 	} else if (wl->status.map.busy) { /* only busy */
4535 		if (bt_linfo->status.map.inq_pag)
4536 			cx->state_map = BTC_WBUSY_BSCAN;
4537 		else
4538 			cx->state_map = BTC_WBUSY_BNOSCAN;
4539 	} else { /* wl idle */
4540 		cx->state_map = BTC_WIDLE;
4541 	}
4542 }
4543 
4544 static u8 _get_wl_guard_bw(struct rtw89_dev *rtwdev, u8 index)
4545 {
4546 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4547 	u8 guard_ch = rtwdev->chip->afh_guard_ch;
4548 	u8 bw = 0;
4549 
4550 	/* default AFH channel sapn = center-ch +- 6MHz  */
4551 	switch (index) {
4552 	case RTW89_CHANNEL_WIDTH_20:
4553 		if (dm->freerun || dm->fddt_train)
4554 			bw = 48;
4555 		else
4556 			bw = 20 + guard_ch * 2;
4557 		break;
4558 	case RTW89_CHANNEL_WIDTH_40:
4559 		bw = 40 + guard_ch * 2;
4560 		break;
4561 	case RTW89_CHANNEL_WIDTH_80:
4562 		bw = 80 + guard_ch * 2;
4563 		break;
4564 	case RTW89_CHANNEL_WIDTH_160:
4565 	case RTW89_CHANNEL_WIDTH_80_80:
4566 		bw = 160 + guard_ch * 2;
4567 		break;
4568 	case RTW89_CHANNEL_WIDTH_320:
4569 		bw = 320 + guard_ch * 2;
4570 		break;
4571 	case RTW89_CHANNEL_WIDTH_5:
4572 		bw = 5 + guard_ch * 2;
4573 		break;
4574 	case RTW89_CHANNEL_WIDTH_10:
4575 		bw = 10 + guard_ch * 2;
4576 		break;
4577 	default:
4578 		bw = 0;
4579 		break;
4580 	}
4581 
4582 	return bw;
4583 }
4584 
4585 static void _set_wl_ch_map(struct rtw89_dev *rtwdev)
4586 {
4587 	struct rtw89_btc *btc = &rtwdev->btc;
4588 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4589 	struct rtw89_btc_wl_afh_info *afh;
4590 	u16 ch_start, ch_end, i;
4591 	u8 b_group, b_pos; /* byte-group, bit-position */
4592 	u8 hwb;
4593 
4594 	if (wl->afh_info[RTW89_MAC_0][RTW89_BAND_2G].en &&
4595 	    wl->afh_info[RTW89_MAC_1][RTW89_BAND_2G].en) {
4596 		/* select wilder bw if 1+1 */
4597 		if (wl->afh_info[RTW89_MAC_1][RTW89_BAND_2G].bw >
4598 		    wl->afh_info[RTW89_MAC_0][RTW89_BAND_2G].bw)
4599 			hwb = RTW89_MAC_1;
4600 		else
4601 			hwb = RTW89_MAC_0;
4602 	} else if (wl->afh_info[RTW89_MAC_1][RTW89_BAND_2G].en) {
4603 		hwb = RTW89_MAC_1;
4604 	} else {
4605 		hwb = RTW89_MAC_0;
4606 	}
4607 
4608 	afh = &wl->afh_info[hwb][RTW89_BAND_2G];
4609 
4610 	/* focus on WL 2.4GHz link */
4611 	if (!afh->en || afh->band != RTW89_BAND_2G)
4612 		return;
4613 
4614 	memset(wl->ch_map, 0x0, sizeof(wl->ch_map));
4615 	memset(wl->ch_map_le, 0x0, sizeof(wl->ch_map_le));
4616 
4617 	ch_start = afh->ch * 5 + 2407 - afh->bw / 2;
4618 	ch_end = ch_start + afh->bw;
4619 
4620 	for (i = ch_start; i < ch_end; i++) {
4621 		if (i < 2402 || i > 2480)
4622 			continue;
4623 		b_group = (i - 2402) / 8;
4624 		b_pos = 7 - ((i - 2402) % 8);
4625 		wl->ch_map[b_group] |= BIT(b_pos);
4626 
4627 		if (i % 2)  /* BLE ch = even-freq (ex:2402,2404) */
4628 			continue;
4629 
4630 		b_group = (i - 2402) / 16;
4631 		b_pos = 7 - (((i - 2402) / 2) % 8);
4632 		wl->ch_map_le[b_group] |= BIT(b_pos);
4633 	}
4634 }
4635 
4636 static u8 _get_w2b_fbd_ch(struct rtw89_dev *rtwdev,
4637 			  u8 bt_fb_band, u32 wl_vco_freq,
4638 			  u32 *ch_lo_bound, u32 *ch_up_bound)
4639 {
4640 	u32 ch_lo, ch_pup, ch_min, ch_max;
4641 	u8 out_of_range = 0;
4642 	s32 val_lo, val_up;
4643 	u32 vco_lo_in_KHz; /* VCO pulling lower bound */
4644 	u32 vco_up_in_KHz; /* VCO pulling Upper bound */
4645 	u32 freq_start;
4646 
4647 	vco_lo_in_KHz = wl_vco_freq - BTC_VCO_GUARD_W2B * 1000; /* KHz */
4648 	vco_up_in_KHz = wl_vco_freq + BTC_VCO_GUARD_W2B * 1000;
4649 
4650 	switch (bt_fb_band) {
4651 	default:
4652 	case BTC_BT_B2G: /* BT 2GHz forbiddened Channel */
4653 		val_lo = vco_lo_in_KHz * BTC_LO_2G_DNM / BTC_LO_2G_NMR;
4654 		val_up = vco_up_in_KHz * BTC_LO_2G_DNM / BTC_LO_2G_NMR;
4655 		freq_start = BTC_FREQ_B2G * 1000; /* KHz */
4656 		ch_min = BTC_CH_B2G_MIN;
4657 		ch_max = BTC_CH_B2G_MAX;
4658 		break;
4659 	case BTC_BT_B5G: /* BT 5/6GHz forbiddened Channel */
4660 		val_lo = vco_lo_in_KHz * BTC_LO_6G_DNM / BTC_LO_6G_NMR;
4661 		val_up = vco_up_in_KHz * BTC_LO_6G_DNM / BTC_LO_6G_NMR;
4662 		freq_start = BTC_FREQ_B6G * 1000; /* KHz */
4663 		ch_min = BTC_CH_B5G_MIN;
4664 		ch_max = BTC_CH_B5G_MAX;
4665 		break;
4666 	}
4667 
4668 	/* Search forbiddened Channel (un-process range)*/
4669 	ch_lo = (val_lo - freq_start) / 1000;
4670 	if ((val_lo - freq_start) % 1000 != 0) /* Round-UP */
4671 		ch_lo++;
4672 
4673 	ch_pup = (val_up - freq_start) / 1000; /* Round-down */
4674 
4675 	/* Search forbiddened Channel */
4676 	if (ch_lo > ch_max || ch_pup < ch_min) { /* out-of-range -> NA */
4677 		out_of_range = 1;
4678 		*ch_lo_bound = 0;
4679 		*ch_up_bound = 0;
4680 	}
4681 
4682 	if (ch_lo < ch_min)
4683 		*ch_lo_bound = ch_min;
4684 	else if (ch_lo <= ch_max)
4685 		*ch_lo_bound = ch_lo;
4686 
4687 	if (ch_pup > ch_max)
4688 		*ch_up_bound = ch_max;
4689 	else if (ch_pup >= ch_min)
4690 		*ch_up_bound = ch_pup;
4691 
4692 	if (bt_fb_band == BTC_BT_B5G) { /* BT ch is 8MHz-spacing for 5/6GHz */
4693 		*ch_lo_bound = *ch_lo_bound / 8; /* low-bound -> Round-down */
4694 
4695 		if (*ch_up_bound % 8 != 0) /* Up-bound -> cover wider range */
4696 			*ch_up_bound = *ch_up_bound / 8 + 1;
4697 		else
4698 			*ch_up_bound = *ch_up_bound / 8;
4699 	}
4700 
4701 	return out_of_range;
4702 }
4703 
4704 static void _set_wl_ch_info(struct rtw89_dev *rtwdev)
4705 {
4706 	static const u8 path_hwb[BTC_RF_NUM] = {RTW89_PHY_0, RTW89_PHY_1};
4707 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4708 	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
4709 	struct rtw89_btc_wl_info *wl = &cx->wl;
4710 	u32 vco_freq, ch_lo = 0, ch_up = 0;
4711 	u16 rf_band, freq, f_diff;
4712 	u8 i, j, ch;
4713 
4714 	if (!(rtwdev->chip->para_ver & BTC_FEAT_MULTI_PTA)) /* only new-PTA require setup */
4715 		return;
4716 
4717 	for (i = RTW89_PHY_0; i <= RTW89_PHY_1; i++) {
4718 		if (wl->mlo_info.wmode[i] == RTW89_MR_WMODE_NONE) { /* no-connect */
4719 			dm->ost_info.rf_center_freq[i] = 0;
4720 			dm->ost_info.fbd_group_en[i][0] = 0;
4721 			dm->ost_info.fbd_group_en[i][1] = 0;
4722 			dm->ost_info.fbd_group_bound[i][0] = 0;
4723 			dm->ost_info.fbd_group_bound[i][1] = 0;
4724 			continue;
4725 		}
4726 
4727 		ch = wl->rf_ch_info[i].center_ch;
4728 		switch (wl->rf_ch_info[i].band) {
4729 		case RTW89_BAND_2G:
4730 		default:
4731 			rf_band = 0;
4732 			if (ch == 14)
4733 				freq = BTC_FREQ_W2G_CH14;
4734 			else
4735 				freq = BTC_FREQ_W2G + (ch - 1) * 5;
4736 			vco_freq = freq * 1000 * BTC_LO_2G_NMR / BTC_LO_2G_DNM;
4737 			break;
4738 		case RTW89_BAND_5G:
4739 			rf_band = BIT(15);
4740 			freq = BTC_FREQ_W5G + (ch - 1) * 5;
4741 			vco_freq = freq * 1000 * BTC_LO_5G_NMR / BTC_LO_5G_DNM;
4742 			break;
4743 		case RTW89_BAND_6G:
4744 			rf_band = BIT(15);
4745 			freq = BTC_FREQ_W6G + (ch - 1) * 5;
4746 			vco_freq = freq * 1000 * BTC_LO_6G_NMR / BTC_LO_6G_DNM;
4747 			break;
4748 		}
4749 
4750 		dm->ost_info.rf_center_freq[i] = rf_band + freq;
4751 
4752 		for (j = BTC_BT_B2G; j <= BTC_BT_B5G; j++) {
4753 			/* no WL->BT forbidden channel */
4754 			if (_get_w2b_fbd_ch(rtwdev, j, vco_freq, &ch_lo, &ch_up)) {
4755 				dm->ost_info.fbd_group_en[i][j] = j << 1;
4756 				dm->ost_info.fbd_group_bound[i][j] = 0;
4757 				continue;
4758 			}
4759 
4760 			dm->ost_info.fbd_group_en[i][j] = (j << 1) + 0x1;
4761 			dm->ost_info.fbd_group_bound[i][j] = (ch_up << 8) + ch_lo;
4762 		}
4763 	}
4764 
4765 	for (i = BTC_RF_S0; i <= BTC_RF_S1; i++) {
4766 		for (j = BTC_BT_1ST; j <= BTC_BT_EXT; j++) {
4767 			/*
4768 			 * If WL & BT share same ANT/Path, set freq-diff > 2GHz,
4769 			 * because TDD will always run in 5/6GHz band.
4770 			 * Otherwise, the frq-diff thres is decided by the RF
4771 			 * out-of-channel rejection capability.
4772 			 */
4773 			if (dm->ant_xmap[i][j])
4774 				f_diff = 0x7ff; /* 2047MHz */
4775 			else
4776 				f_diff = rtwdev->chip->fdd_iso_freq;
4777 
4778 			dm->ost_info.freq_diff_thres[path_hwb[i]][j] = f_diff;
4779 		}
4780 	}
4781 }
4782 
4783 static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
4784 {
4785 	struct rtw89_btc *btc = &rtwdev->btc;
4786 	struct rtw89_btc_cx *cx = &btc->cx;
4787 	struct rtw89_btc_wl_info *wl = &cx->wl;
4788 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
4789 	struct rtw89_btc_wl_rlink *rlink;
4790 	u8 h2c_func, hwb, bt_link_chg;
4791 	u8 i, j, sz, bw;
4792 	u8 buf[4];
4793 
4794 	if (btc->manual_ctrl || wl->status.map.rf_off ||
4795 	    (wl->status.val & btc_scanning_map.val))
4796 		return;
4797 
4798 	memset(wl->afh_info, 0, sizeof(wl->afh_info));
4799 
4800 	for (j = RTW89_MAC_0; j < RTW89_MAC_NUM; j++) {
4801 		/* skip HW-Band if no fdd/fdd bind */
4802 		if ((!(btc->dm.tdd_bind.wl_hwb_sel & BIT(j))) &&
4803 		    (!(btc->dm.fdd_bind.wl_hwb_sel & BIT(j))))
4804 			continue;
4805 
4806 		for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) {
4807 			rlink = &wl_rinfo->rlink[i][j];
4808 
4809 			/* Skip no-active case */
4810 			if (!rlink->connected || !rlink->active ||
4811 			    rlink->rf_band >= RTW89_BAND_NUM)
4812 				continue;
4813 
4814 			/* In addition to AP/P2P, skip if same-rf-band*/
4815 			if (wl->afh_info[j][rlink->rf_band].en &&
4816 			    (rlink->role != RTW89_WIFI_ROLE_AP &&
4817 			     rlink->role != RTW89_WIFI_ROLE_P2P_GO &&
4818 			     rlink->role != RTW89_WIFI_ROLE_P2P_CLIENT))
4819 				continue;
4820 
4821 			bw = _get_wl_guard_bw(rtwdev, rlink->bw);
4822 			wl->afh_info[j][rlink->rf_band].en = 1;
4823 			wl->afh_info[j][rlink->rf_band].ch = rlink->ch;
4824 			wl->afh_info[j][rlink->rf_band].bw = bw;
4825 			wl->afh_info[j][rlink->rf_band].band = rlink->rf_band;
4826 		}
4827 	}
4828 
4829 	for (j = RTW89_BAND_2G; j < RTW89_BAND_NUM; j++) {
4830 		/* skip non-2.4GHz if BT is 2.4GHz only*/
4831 		if (!(rtwdev->chip->para_ver &  BTC_FEAT_BT_6G)) {
4832 			if (j != RTW89_BAND_2G)
4833 				continue;
4834 			sz = 3;
4835 		} else {
4836 			sz = 4;
4837 		}
4838 
4839 		if (wl->afh_info[RTW89_MAC_0][j].en &&
4840 		    wl->afh_info[RTW89_MAC_1][j].en) {
4841 			/* select wilder bw if 1+1 */
4842 			if (wl->afh_info[RTW89_MAC_1][j].bw >
4843 			    wl->afh_info[RTW89_MAC_0][j].bw)
4844 				hwb = RTW89_MAC_1;
4845 			else
4846 				hwb = RTW89_MAC_0;
4847 		} else if (wl->afh_info[RTW89_MAC_1][j].en) {
4848 			hwb = RTW89_MAC_1;
4849 		} else {
4850 			hwb = RTW89_MAC_0;
4851 		}
4852 
4853 		if (j == RTW89_BAND_2G) {
4854 			if (cx->bt0.link_info.link_cnt.chg ||
4855 			    cx->bt1.link_info.link_cnt.chg)
4856 				bt_link_chg = 1;
4857 			else
4858 				bt_link_chg = 0;
4859 		} else {
4860 			if (cx->bt0.link_info_56g.link_cnt.chg ||
4861 			    cx->bt1.link_info_56g.link_cnt.chg)
4862 				bt_link_chg = 1;
4863 			else
4864 				bt_link_chg = 0;
4865 		}
4866 
4867 		/* return if no-afh-info-change/no wl-bt link change */
4868 		if (!memcmp(&wl->afh_info_last[hwb][j],
4869 			    &wl->afh_info[hwb][j],
4870 			    sizeof(struct rtw89_btc_wl_afh_info)) &&
4871 			    !bt_link_chg &&
4872 			    !wl->link_mode_chg)
4873 			continue;
4874 
4875 		memcpy(&wl->afh_info_last[hwb][j],
4876 		       &wl->afh_info[hwb][j],
4877 		       sizeof(struct rtw89_btc_wl_afh_info));
4878 
4879 		buf[0] = wl->afh_info[hwb][j].en;
4880 		buf[1] = wl->afh_info[hwb][j].ch;
4881 		buf[2] = wl->afh_info[hwb][j].bw;
4882 		buf[3] = wl->afh_info[hwb][j].band;
4883 
4884 		h2c_func = SET_BT_WL_CH_INFO;
4885 		if (cx->bt0.enable.now)
4886 			_send_fw_cmd(rtwdev, BTFC_SET, h2c_func, buf, sz);
4887 
4888 		/* send mailbox to 2nd-BT if exist */
4889 		if (cx->bt1.enable.now) {
4890 			h2c_func |= BT_H2C_FUNC_BT2ND;
4891 			_send_fw_cmd(rtwdev, BTFC_SET, h2c_func, buf, sz);
4892 		}
4893 
4894 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4895 			    "[BTC], %s(): en=%d, ch=%d, bw=%d, rf_band=%d\n",
4896 			    __func__, buf[0], buf[1], buf[2], buf[3]);
4897 
4898 		wl->wcnt[BTC_WCNT_CH_UPDATE]++;
4899 
4900 		/* ToDo: Remove if BT update new-define to support 6GHz */
4901 		if (j == RTW89_BAND_2G)
4902 			break;
4903 	}
4904 
4905 	/* for AFH map display in coex log */
4906 	_set_wl_ch_map(rtwdev);
4907 
4908 	/* set HWB center-ch/forbidden group to ost_info for CR setup in FW */
4909 	_set_wl_ch_info(rtwdev);
4910 }
4911 
4912 static bool _check_freerun(struct rtw89_dev *rtwdev)
4913 {
4914 	struct rtw89_btc *btc = &rtwdev->btc;
4915 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4916 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
4917 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
4918 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
4919 	struct rtw89_btc_bt_hid_desc *hid = &bt_linfo->hid_desc;
4920 	struct rtw89_btc_module *md = &btc->mdinfo;
4921 
4922 	if (btc->ant_type == BTC_ANT_SHARED) {
4923 		btc->dm.trx_para_level = 0;
4924 		return false;
4925 	}
4926 
4927 	/* The below is dedicated antenna case */
4928 	if (wl_rinfo->connect_cnt > BTC_TDMA_WLROLE_MAX) {
4929 		btc->dm.trx_para_level = 5;
4930 		return true;
4931 	}
4932 
4933 	if (bt_linfo->link_cnt.now == 0) {
4934 		btc->dm.trx_para_level = 5;
4935 		return true;
4936 	}
4937 
4938 	if (hid->pair_cnt > BTC_TDMA_BTHID_MAX) {
4939 		btc->dm.trx_para_level = 5;
4940 		return true;
4941 	}
4942 
4943 	/* TODO get isolation by BT psd */
4944 	if (md->ant.isolation >= BTC_FREERUN_ANTISO_MIN) {
4945 		btc->dm.trx_para_level = 5;
4946 		return true;
4947 	}
4948 
4949 	if (!wl->status.map.busy) {/* wl idle -> freerun */
4950 		btc->dm.trx_para_level = 5;
4951 		return true;
4952 	} else if (wl->rssi_level > 1) {/* WL rssi < 50% (-60dBm) */
4953 		btc->dm.trx_para_level = 0;
4954 		return false;
4955 	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
4956 		if (wl->rssi_level == 0 && bt_linfo->rssi > 31) {
4957 			btc->dm.trx_para_level = 6;
4958 			return true;
4959 		} else if (wl->rssi_level == 1 && bt_linfo->rssi > 36) {
4960 			btc->dm.trx_para_level = 7;
4961 			return true;
4962 		}
4963 		btc->dm.trx_para_level = 0;
4964 		return false;
4965 	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL)) {
4966 		if (bt_linfo->rssi > 28) {
4967 			btc->dm.trx_para_level = 6;
4968 			return true;
4969 		}
4970 	}
4971 
4972 	btc->dm.trx_para_level = 0;
4973 	return false;
4974 }
4975 
4976 #define _tdma_set_flctrl(btc, flc) ({(btc)->dm.tdma.rxflctrl = flc; })
4977 #define _tdma_set_flctrl_role(btc, role) ({(btc)->dm.tdma.rxflctrl_role = role; })
4978 #define _tdma_set_rxflctrl(btc, rxflc) ({(btc)->dm.tdma.rxflctrl = rxflc; })
4979 #define _tdma_set_txflctrl(btc, txflc) ({(btc)->dm.tdma.txflctrl = txflc; })
4980 #define _tdma_set_lek(btc, lek) ({(btc)->dm.tdma.leak_n = lek; })
4981 
4982 struct btc_btinfo_lb2 {
4983 	u8 connect: 1;
4984 	u8 sco_busy: 1;
4985 	u8 inq_pag: 1;
4986 	u8 acl_busy: 1;
4987 	u8 hfp: 1;
4988 	u8 hid: 1;
4989 	u8 a2dp: 1;
4990 	u8 pan: 1;
4991 };
4992 
4993 struct btc_btinfo_lb3 {
4994 	u8 retry: 4;
4995 	u8 cqddr: 1;
4996 	u8 inq: 1;
4997 	u8 mesh_busy: 1;
4998 	u8 pag: 1;
4999 };
5000 
5001 struct btc_btinfo_hb0 {
5002 	s8 rssi;
5003 };
5004 
5005 struct btc_btinfo_hb1 {
5006 	u8 ble_connect: 1;
5007 	u8 reinit: 1;
5008 	u8 relink: 1;
5009 	u8 igno_wl: 1;
5010 	u8 voice: 1;
5011 	u8 ble_scan: 1;
5012 	u8 role_sw: 1;
5013 	u8 multi_link: 1;
5014 };
5015 
5016 struct btc_btinfo_hb2 {
5017 	u8 pan_active: 1;
5018 	u8 afh_update: 1;
5019 	u8 a2dp_active: 1;
5020 	u8 slave: 1;
5021 	u8 hid_slot: 2;
5022 	u8 hid_cnt: 2;
5023 };
5024 
5025 struct btc_btinfo_hb3 {
5026 	u8 a2dp_bitpool: 6;
5027 	u8 tx_3m: 1;
5028 	u8 a2dp_sink: 1;
5029 };
5030 
5031 union btc_btinfo {
5032 	u8 val;
5033 	struct btc_btinfo_lb2 lb2;
5034 	struct btc_btinfo_lb3 lb3;
5035 	struct btc_btinfo_hb0 hb0;
5036 	struct btc_btinfo_hb1 hb1;
5037 	struct btc_btinfo_hb2 hb2;
5038 	struct btc_btinfo_hb3 hb3;
5039 };
5040 
5041 static void _set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
5042 			enum btc_reason_and_action action)
5043 {
5044 	const struct rtw89_chip_info *chip = rtwdev->chip;
5045 
5046 	chip->ops->btc_set_policy(rtwdev, policy_type);
5047 	_fw_set_policy(rtwdev, policy_type, action);
5048 }
5049 
5050 static void _set_tdma_bind(struct rtw89_dev *rtwdev, bool tdma_on)
5051 {
5052 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
5053 	struct rtw89_btc_bind_info *bind;
5054 	u8 null_role = RTW89_WIFI_ROLE_STATION;
5055 	u8 bt_sel;
5056 
5057 	if (dm->tdd_en)
5058 		bind = &dm->tdd_bind; /* tdd = 1 && fdd = 0 or 1 */
5059 	else
5060 		bind = &dm->fdd_bind; /* tdd = 0 && fdd = 1 */
5061 
5062 	if (bind->bt_sel >= (BIT(BTC_BT_1ST) | BIT(BTC_BT_2ND)))
5063 		bt_sel = BTC_ALL_BT;
5064 	else if (bind->bt_sel == BIT(BTC_BT_2ND))
5065 		bt_sel = BTC_BT_2ND;
5066 	else
5067 		bt_sel = BTC_BT_1ST;
5068 
5069 	/* notify BT TDMA on/off by scoreboard for ACL/Scan schedule */
5070 	_write_scbd(rtwdev, bt_sel, BTC_WSCB_TDMA, tdma_on);
5071 
5072 	/*
5073 	 * set hwb/bt bind to TDMA policy parameter
5074 	 * FW-BTC will setup related hwbx vs. BTx coex tables by slot toggle
5075 	 * ex: HWb0 + BT0 + BT1, HWB0-BT0/HWB0-BT1 coex by WL/BT slot toggle
5076 	 */
5077 	dm->tdma.bind = ((bind->bt_sel & 0xf) << 4) + (bind->wl_hwb_sel & 0x3);
5078 	if (dm->tdd_en)
5079 		dm->tdma.bind |= BIT(2);
5080 	if (dm->fdd_en)
5081 		dm->tdma.bind |= BIT(3);
5082 	if (rtwdev->btc.ver->fcxtdma != 8)
5083 		dm->tdma.bind |= 0;
5084 
5085 	/* set Null-tx role for 2 HW-BAND TDMA (MLMR) */
5086 	if (!dm->eslot_ctrl.en && dm->tdma.rxflctrl &&
5087 	    (bind->wl_hwb_sel == (BIT(RTW89_PHY_1) | BIT(RTW89_PHY_0)))) {
5088 		null_role = (null_role << 4) + null_role;
5089 		_tdma_set_flctrl_role(&rtwdev->btc, null_role);
5090 	}
5091 }
5092 
5093 #define BTC_B1_MAX 250 /* unit ms */
5094 void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
5095 {
5096 	struct rtw89_btc *btc = &rtwdev->btc;
5097 	struct rtw89_btc_dm *dm = &btc->dm;
5098 	struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
5099 	u8 type;
5100 	u32 tbl_w1, tbl_b1, tbl_b4;
5101 	bool tdma_on = false;
5102 
5103 	if (btc->ant_type == BTC_ANT_SHARED) {
5104 		if (btc->cx.wl.status.map._4way)
5105 			tbl_w1 = cxtbl[1];
5106 		else
5107 			tbl_w1 = cxtbl[8];
5108 		tbl_b1 = cxtbl[3];
5109 		tbl_b4 = cxtbl[3];
5110 	} else {
5111 		tbl_w1 = cxtbl[16];
5112 		tbl_b1 = cxtbl[17];
5113 		tbl_b4 = cxtbl[17];
5114 	}
5115 
5116 	type = (u8)((policy_type & BTC_CXP_MASK) >> 8);
5117 	btc->bt_req_en = false;
5118 
5119 	switch (type) {
5120 	case BTC_CXP_USERDEF0:
5121 		*t = t_def[CXTD_OFF];
5122 		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
5123 			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
5124 		_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
5125 		btc->update_policy_force = true;
5126 		break;
5127 	case BTC_CXP_OFF: /* TDMA off */
5128 		tdma_on = false;
5129 		*t = t_def[CXTD_OFF];
5130 		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
5131 			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
5132 
5133 		switch (policy_type) {
5134 		case BTC_CXP_OFF_BT:
5135 			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
5136 			break;
5137 		case BTC_CXP_OFF_WL:
5138 			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
5139 			break;
5140 		case BTC_CXP_OFF_EQ0:
5141 			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
5142 			break;
5143 		case BTC_CXP_OFF_EQ1:
5144 			_slot_set_tbl(btc, CXST_OFF, cxtbl[16]);
5145 			break;
5146 		case BTC_CXP_OFF_EQ2:
5147 			_slot_set_tbl(btc, CXST_OFF, cxtbl[17]);
5148 			break;
5149 		case BTC_CXP_OFF_EQ3:
5150 			_slot_set_tbl(btc, CXST_OFF, cxtbl[18]);
5151 			break;
5152 		case BTC_CXP_OFF_BWB0:
5153 			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
5154 			break;
5155 		case BTC_CXP_OFF_BWB1:
5156 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
5157 			break;
5158 		case BTC_CXP_OFF_BWB3:
5159 			_slot_set_tbl(btc, CXST_OFF, cxtbl[6]);
5160 			break;
5161 		}
5162 		break;
5163 	case BTC_CXP_OFFB: /* TDMA off + beacon protect */
5164 		tdma_on = false;
5165 		*t = t_def[CXTD_OFF_B2];
5166 		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
5167 			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
5168 		_slot_set(btc, CXST_B2, 10, cxtbl[1], SLOT_ISO);
5169 
5170 		switch (policy_type) {
5171 		case BTC_CXP_OFFB_BWB0:
5172 			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
5173 			break;
5174 		case BTC_CXP_OFFB_BWB1:
5175 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
5176 			break;
5177 		case BTC_CXP_OFFB_BWB2:
5178 			_slot_set_tbl(btc, CXST_OFF, cxtbl[7]);
5179 			break;
5180 		case BTC_CXP_OFFB_BWB3:
5181 			_slot_set_tbl(btc, CXST_OFF, cxtbl[6]);
5182 			break;
5183 		case BTC_CXP_OFFB_BWB4:
5184 			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
5185 			break;
5186 		}
5187 		break;
5188 	case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
5189 		btc->bt_req_en = true;
5190 		tdma_on = true;
5191 		*t = t_def[CXTD_OFF_EXT];
5192 		switch (policy_type) {
5193 		case BTC_CXP_OFFE_DEF:
5194 			_slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur,
5195 				     s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype);
5196 			_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
5197 				     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
5198 			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
5199 				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
5200 			_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
5201 				     s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
5202 			break;
5203 		case BTC_CXP_OFFE_DEF2:
5204 			_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
5205 			_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
5206 				     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
5207 			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
5208 				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
5209 			_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
5210 				     s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
5211 			break;
5212 		}
5213 		break;
5214 	case BTC_CXP_FIX: /* TDMA Fix-Slot */
5215 		tdma_on = true;
5216 		*t = t_def[CXTD_FIX];
5217 		switch (policy_type) {
5218 		case BTC_CXP_FIX_TD3030:
5219 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5220 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
5221 			break;
5222 		case BTC_CXP_FIX_TD5050:
5223 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
5224 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
5225 			break;
5226 		case BTC_CXP_FIX_TD2030:
5227 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5228 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
5229 			break;
5230 		case BTC_CXP_FIX_TD4010:
5231 			_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
5232 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
5233 			break;
5234 		case BTC_CXP_FIX_TD4010ISO:
5235 			_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
5236 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
5237 			break;
5238 		case BTC_CXP_FIX_TD4010ISO_DL:
5239 			_slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO);
5240 			_slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO);
5241 			break;
5242 		case BTC_CXP_FIX_TD4010ISO_UL:
5243 			_slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO);
5244 			_slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX);
5245 			break;
5246 		case BTC_CXP_FIX_TD7010:
5247 			_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
5248 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
5249 			break;
5250 		case BTC_CXP_FIX_TD2060:
5251 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5252 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
5253 			break;
5254 		case BTC_CXP_FIX_TD3060:
5255 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5256 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
5257 			break;
5258 		case BTC_CXP_FIX_TD2080:
5259 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5260 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
5261 			break;
5262 		case BTC_CXP_FIX_TDW1B1: /* W1:B1 = user-define */
5263 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5264 				  tbl_w1, SLOT_ISO);
5265 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5266 				  tbl_b1, SLOT_MIX);
5267 			break;
5268 		}
5269 		break;
5270 	case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
5271 		tdma_on = true;
5272 		*t = t_def[CXTD_PFIX];
5273 		if (btc->cx.wl.role_info.role_map[RTW89_MAC_0] & BIT(RTW89_WIFI_ROLE_AP))
5274 			_tdma_set_flctrl(btc, CXFLC_QOSNULL);
5275 
5276 		switch (policy_type) {
5277 		case BTC_CXP_PFIX_TD3030:
5278 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5279 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
5280 			break;
5281 		case BTC_CXP_PFIX_TD5050:
5282 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
5283 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
5284 			break;
5285 		case BTC_CXP_PFIX_TD2030:
5286 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5287 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
5288 			break;
5289 		case BTC_CXP_PFIX_TD2060:
5290 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5291 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
5292 			break;
5293 		case BTC_CXP_PFIX_TD3070:
5294 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5295 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
5296 			break;
5297 		case BTC_CXP_PFIX_TD2080:
5298 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5299 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
5300 			break;
5301 		}
5302 		break;
5303 	case BTC_CXP_AUTO: /* TDMA Auto-Slot */
5304 		tdma_on = true;
5305 		*t = t_def[CXTD_AUTO];
5306 		switch (policy_type) {
5307 		case BTC_CXP_AUTO_TD50B1:
5308 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
5309 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5310 			break;
5311 		case BTC_CXP_AUTO_TD60B1:
5312 			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
5313 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5314 			break;
5315 		case BTC_CXP_AUTO_TD20B1:
5316 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5317 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5318 			break;
5319 		case BTC_CXP_AUTO_TDW1B1: /* W1:B1 = user-define */
5320 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5321 				  tbl_w1, SLOT_ISO);
5322 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5323 				  tbl_b1, SLOT_MIX);
5324 			break;
5325 		}
5326 		break;
5327 	case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
5328 		tdma_on = true;
5329 		*t = t_def[CXTD_PAUTO];
5330 		switch (policy_type) {
5331 		case BTC_CXP_PAUTO_TD50B1:
5332 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
5333 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5334 			break;
5335 		case BTC_CXP_PAUTO_TD60B1:
5336 			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
5337 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5338 			break;
5339 		case BTC_CXP_PAUTO_TD20B1:
5340 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5341 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5342 			break;
5343 		case BTC_CXP_PAUTO_TDW1B1:
5344 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5345 				  tbl_w1, SLOT_ISO);
5346 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5347 				  tbl_b1, SLOT_MIX);
5348 			break;
5349 		}
5350 		break;
5351 	case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
5352 		tdma_on = true;
5353 		*t = t_def[CXTD_AUTO2];
5354 		switch (policy_type) {
5355 		case BTC_CXP_AUTO2_TD3050:
5356 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5357 			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
5358 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5359 			break;
5360 		case BTC_CXP_AUTO2_TD3070:
5361 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5362 			_slot_set(btc, CXST_B4, 70, tbl_b4, SLOT_MIX);
5363 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5364 			break;
5365 		case BTC_CXP_AUTO2_TD5050:
5366 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
5367 			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
5368 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5369 			break;
5370 		case BTC_CXP_AUTO2_TD6060:
5371 			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
5372 			_slot_set(btc, CXST_B4, 60, tbl_b4, SLOT_MIX);
5373 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5374 			break;
5375 		case BTC_CXP_AUTO2_TD2080:
5376 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5377 			_slot_set(btc, CXST_B4, 80, tbl_b4, SLOT_MIX);
5378 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5379 			break;
5380 		case BTC_CXP_AUTO2_TDW1B4: /* W1:B1 = user-define */
5381 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5382 				  tbl_w1, SLOT_ISO);
5383 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
5384 				  tbl_b4, SLOT_MIX);
5385 			break;
5386 		}
5387 		break;
5388 	case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
5389 		tdma_on = true;
5390 		*t = t_def[CXTD_PAUTO2];
5391 		switch (policy_type) {
5392 		case BTC_CXP_PAUTO2_TD3050:
5393 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5394 			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
5395 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5396 			break;
5397 		case BTC_CXP_PAUTO2_TD3070:
5398 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5399 			_slot_set(btc, CXST_B4, 70, tbl_b4, SLOT_MIX);
5400 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5401 			break;
5402 		case BTC_CXP_PAUTO2_TD5050:
5403 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
5404 			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
5405 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5406 			break;
5407 		case BTC_CXP_PAUTO2_TD6060:
5408 			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
5409 			_slot_set(btc, CXST_B4, 60, tbl_b4, SLOT_MIX);
5410 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5411 			break;
5412 		case BTC_CXP_PAUTO2_TD2080:
5413 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5414 			_slot_set(btc, CXST_B4, 80, tbl_b4, SLOT_MIX);
5415 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5416 			break;
5417 		case BTC_CXP_PAUTO2_TDW1B4: /* W1:B1 = user-define */
5418 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5419 				  tbl_w1, SLOT_ISO);
5420 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
5421 				  tbl_b4, SLOT_MIX);
5422 			break;
5423 		}
5424 		break;
5425 	}
5426 	_set_tdma_bind(rtwdev, tdma_on);
5427 }
5428 EXPORT_SYMBOL(rtw89_btc_set_policy);
5429 
5430 void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
5431 {
5432 	struct rtw89_btc *btc = &rtwdev->btc;
5433 	struct rtw89_btc_dm *dm = &btc->dm;
5434 	struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
5435 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
5436 	struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt0.link_info.hid_desc;
5437 	struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt0.link_info.hfp_desc;
5438 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5439 	u8 type, null_role;
5440 	u32 tbl_w1, tbl_b1, tbl_b4;
5441 	bool tdma_on = false;
5442 	u16 dur_1 = 0, dur_2;
5443 
5444 	if (wl->status.map.lps) {
5445 		_slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur,
5446 			     s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype);
5447 		_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
5448 			     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
5449 		_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
5450 			     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
5451 	}
5452 
5453 	type = FIELD_GET(BTC_CXP_MASK, policy_type);
5454 
5455 	if (btc->ant_type == BTC_ANT_SHARED) {
5456 		if (btc->cx.wl.status.map._4way)
5457 			tbl_w1 = cxtbl[1];
5458 		else if (hid->exist && hid->type == BTC_HID_218)
5459 			tbl_w1 = cxtbl[7]; /* Ack/BA no break bt Hi-Pri-rx */
5460 		else
5461 			tbl_w1 = cxtbl[8];
5462 
5463 		if (dm->leak_ap &&
5464 		    (type == BTC_CXP_PFIX || type == BTC_CXP_PAUTO2)) {
5465 			tbl_b1 = cxtbl[3];
5466 			tbl_b4 = cxtbl[3];
5467 		} else if (hid->exist && hid->type == BTC_HID_218) {
5468 			tbl_b1 = cxtbl[4]; /* Ack/BA no break bt Hi-Pri-rx */
5469 			tbl_b4 = cxtbl[4];
5470 		} else {
5471 			tbl_b1 = cxtbl[2];
5472 			tbl_b4 = cxtbl[2];
5473 		}
5474 	} else {
5475 		tbl_b1 = cxtbl[17];
5476 		tbl_b4 = cxtbl[17];
5477 
5478 		if (wl->bg_mode[RTW89_MAC_0])
5479 			tbl_w1 = cxtbl[8];
5480 		else if ((wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) &&
5481 			 hid->exist)
5482 			tbl_w1 = cxtbl[19];
5483 		else
5484 			tbl_w1 = cxtbl[16];
5485 	}
5486 
5487 	switch (type) {
5488 	case BTC_CXP_USERDEF0:
5489 		btc->update_policy_force = true;
5490 		*t = t_def[CXTD_OFF];
5491 		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
5492 			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
5493 		_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
5494 		break;
5495 	case BTC_CXP_OFF: /* TDMA off */
5496 		tdma_on = false;
5497 		*t = t_def[CXTD_OFF];
5498 		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
5499 			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
5500 
5501 		switch (policy_type) {
5502 		case BTC_CXP_OFF_BT:
5503 			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
5504 			break;
5505 		case BTC_CXP_OFF_WL:
5506 			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
5507 			break;
5508 		case BTC_CXP_OFF_WL2:
5509 			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
5510 			_slot_set_type(btc, CXST_OFF, SLOT_ISO);
5511 			break;
5512 		case BTC_CXP_OFF_EQ0:
5513 			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
5514 			_slot_set_type(btc, CXST_OFF, SLOT_ISO);
5515 			break;
5516 		case BTC_CXP_OFF_EQ1:
5517 			_slot_set_tbl(btc, CXST_OFF, cxtbl[16]);
5518 			break;
5519 		case BTC_CXP_OFF_EQ2:
5520 			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
5521 			break;
5522 		case BTC_CXP_OFF_EQ3:
5523 			_slot_set_tbl(btc, CXST_OFF, cxtbl[24]);
5524 			break;
5525 		case BTC_CXP_OFF_EQ4:
5526 			_slot_set_tbl(btc, CXST_OFF, cxtbl[26]);
5527 			break;
5528 		case BTC_CXP_OFF_EQ5:
5529 			_slot_set_tbl(btc, CXST_OFF, cxtbl[27]);
5530 			break;
5531 		case BTC_CXP_OFF_BWB0:
5532 			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
5533 			break;
5534 		case BTC_CXP_OFF_BWB1:
5535 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
5536 			break;
5537 		case BTC_CXP_OFF_BWB2:
5538 			_slot_set_tbl(btc, CXST_OFF, cxtbl[7]);
5539 			break;
5540 		case BTC_CXP_OFF_BWB3:
5541 			_slot_set_tbl(btc, CXST_OFF, cxtbl[6]);
5542 			break;
5543 		default:
5544 			break;
5545 		}
5546 		break;
5547 	case BTC_CXP_OFFB: /* TDMA off + beacon protect */
5548 		tdma_on = false;
5549 		*t = t_def[CXTD_OFF_B2];
5550 		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
5551 			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
5552 		_slot_set(btc, CXST_B2, 10, cxtbl[1], SLOT_ISO);
5553 
5554 		switch (policy_type) {
5555 		case BTC_CXP_OFFB_BWB0:
5556 			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
5557 			break;
5558 		case BTC_CXP_OFFB_BWB1:
5559 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
5560 			break;
5561 		case BTC_CXP_OFFB_BWB2:
5562 			_slot_set_tbl(btc, CXST_OFF, cxtbl[7]);
5563 			break;
5564 		case BTC_CXP_OFFB_BWB3:
5565 			_slot_set_tbl(btc, CXST_OFF, cxtbl[6]);
5566 			break;
5567 		case BTC_CXP_OFFB_BWB4:
5568 			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
5569 			break;
5570 		}
5571 		break;
5572 	case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
5573 		tdma_on = true;
5574 		*t = t_def[CXTD_OFF_EXT];
5575 
5576 		/* To avoid wl-s0 tx break by hid/hfp tx */
5577 		if (hid->exist || hfp->exist)
5578 			tbl_w1 = cxtbl[16];
5579 
5580 		if (dm->eslot_ctrl.en) {
5581 			null_role = u8_encode_bits(dm->eslot_ctrl.nulltx_role1, 0x0f) |
5582 				    u8_encode_bits(dm->eslot_ctrl.nulltx_role2, 0xf0);
5583 			_tdma_set_flctrl_role(btc, null_role);
5584 			_tdma_set_rxflctrl(btc, 1);
5585 			_tdma_set_txflctrl(btc, 1);
5586 			/* Set Null-Tx time-tick by E2G duration */
5587 			dm->eslot_ctrl.nulltx_pre_time = 5; /* TODO: BIS COEX */
5588 			dur_1 = dm->eslot_ctrl.nulltx_pre_time;
5589 		}
5590 
5591 		dur_2 = dm->e2g_slot_limit;
5592 
5593 		switch (policy_type) {
5594 		case BTC_CXP_OFFE_2GBWISOB: /* for normal-case */
5595 			_slot_set(btc, CXST_E2G, dur_1, tbl_w1, SLOT_ISO);
5596 			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
5597 				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
5598 			_slot_set_dur(btc, CXST_EBT, dur_2);
5599 			break;
5600 		case BTC_CXP_OFFE_2GISOB: /* for bt no-link */
5601 			_slot_set(btc, CXST_E2G, dur_1, cxtbl[1], SLOT_ISO);
5602 			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
5603 				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
5604 			_slot_set_dur(btc, CXST_EBT, dur_2);
5605 			break;
5606 		case BTC_CXP_OFFE_DEF:
5607 			_slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur,
5608 				     s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype);
5609 			_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
5610 				     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
5611 			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
5612 				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
5613 			_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
5614 				     s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
5615 			_slot_set_dur(btc, CXST_EBT, dur_2);
5616 			break;
5617 		case BTC_CXP_OFFE_DEF2:
5618 			_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
5619 			_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
5620 				     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
5621 			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
5622 				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
5623 			_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
5624 				     s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
5625 			_slot_set_dur(btc, CXST_EBT, dur_2);
5626 			break;
5627 		case BTC_CXP_OFFE_2GBWMIXB:
5628 			if (a2dp->exist)
5629 				_slot_set(btc, CXST_E2G, dur_1, cxtbl[2], SLOT_MIX);
5630 			else
5631 				_slot_set(btc, CXST_E2G, dur_1, tbl_w1, SLOT_MIX);
5632 			_slot_set_le(btc, CXST_EBT, cpu_to_le16(40),
5633 				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
5634 			_slot_set_dur(btc, CXST_EBT, dur_2);
5635 			break;
5636 		case BTC_CXP_OFFE_WL: /* for 4-way */
5637 			_slot_set(btc, CXST_E2G, dur_1, cxtbl[1], SLOT_MIX);
5638 			_slot_set(btc, CXST_EBT, dur_1, cxtbl[1], SLOT_MIX);
5639 			break;
5640 		default:
5641 			break;
5642 		}
5643 		_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
5644 			     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
5645 		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
5646 			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
5647 		break;
5648 	case BTC_CXP_FIX: /* TDMA Fix-Slot */
5649 		tdma_on = true;
5650 		*t = t_def[CXTD_FIX];
5651 
5652 		switch (policy_type) {
5653 		case BTC_CXP_FIX_TD3030:
5654 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5655 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
5656 			break;
5657 		case BTC_CXP_FIX_TD5050:
5658 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
5659 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
5660 			break;
5661 		case BTC_CXP_FIX_TD2030:
5662 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5663 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
5664 			break;
5665 		case BTC_CXP_FIX_TD4010:
5666 			_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
5667 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
5668 			break;
5669 		case BTC_CXP_FIX_TD4010ISO:
5670 			_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
5671 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
5672 			break;
5673 		case BTC_CXP_FIX_TD4010ISO_DL:
5674 			_slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO);
5675 			_slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO);
5676 			break;
5677 		case BTC_CXP_FIX_TD4010ISO_UL:
5678 			_slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO);
5679 			_slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX);
5680 			break;
5681 		case BTC_CXP_FIX_TD7010:
5682 			_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
5683 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
5684 			break;
5685 		case BTC_CXP_FIX_TD2060:
5686 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5687 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
5688 			break;
5689 		case BTC_CXP_FIX_TD3060:
5690 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5691 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
5692 			break;
5693 		case BTC_CXP_FIX_TD2080:
5694 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5695 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
5696 			break;
5697 		case BTC_CXP_FIX_TDW1B1: /* W1:B1 = user-define */
5698 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5699 				  tbl_w1, SLOT_ISO);
5700 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5701 				  tbl_b1, SLOT_MIX);
5702 			break;
5703 		default:
5704 			break;
5705 		}
5706 		break;
5707 	case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
5708 		tdma_on = true;
5709 		*t = t_def[CXTD_PFIX];
5710 
5711 		switch (policy_type) {
5712 		case BTC_CXP_PFIX_TD3030:
5713 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5714 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
5715 			break;
5716 		case BTC_CXP_PFIX_TD5050:
5717 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
5718 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
5719 			break;
5720 		case BTC_CXP_PFIX_TD2030:
5721 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5722 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
5723 			break;
5724 		case BTC_CXP_PFIX_TD2060:
5725 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5726 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
5727 			break;
5728 		case BTC_CXP_PFIX_TD3070:
5729 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
5730 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
5731 			break;
5732 		case BTC_CXP_PFIX_TD2080:
5733 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
5734 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
5735 			break;
5736 		case BTC_CXP_PFIX_TDW1B1: /* W1:B1 = user-define */
5737 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5738 				  tbl_w1, SLOT_ISO);
5739 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5740 				  tbl_b1, SLOT_MIX);
5741 			break;
5742 		default:
5743 			break;
5744 		}
5745 		break;
5746 	case BTC_CXP_AUTO: /* TDMA Auto-Slot */
5747 		tdma_on = true;
5748 		*t = t_def[CXTD_AUTO];
5749 
5750 		switch (policy_type) {
5751 		case BTC_CXP_AUTO_TD50B1:
5752 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
5753 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5754 			break;
5755 		case BTC_CXP_AUTO_TD60B1:
5756 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
5757 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5758 			break;
5759 		case BTC_CXP_AUTO_TD20B1:
5760 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
5761 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5762 			break;
5763 		case BTC_CXP_AUTO_TDW1B1: /* W1:B1 = user-define */
5764 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5765 				  tbl_w1, SLOT_ISO);
5766 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5767 				  tbl_b1, SLOT_MIX);
5768 			break;
5769 		default:
5770 			break;
5771 		}
5772 		break;
5773 	case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
5774 		tdma_on = true;
5775 		*t = t_def[CXTD_PAUTO];
5776 
5777 		switch (policy_type) {
5778 		case BTC_CXP_PAUTO_TD50B1:
5779 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
5780 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5781 			break;
5782 		case BTC_CXP_PAUTO_TD60B1:
5783 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
5784 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5785 			break;
5786 		case BTC_CXP_PAUTO_TD20B1:
5787 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
5788 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5789 			break;
5790 		case BTC_CXP_PAUTO_TDW1B1:
5791 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5792 				  tbl_w1, SLOT_ISO);
5793 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5794 				  tbl_b1, SLOT_MIX);
5795 			break;
5796 		default:
5797 			break;
5798 		}
5799 		break;
5800 	case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
5801 		tdma_on = true;
5802 		*t = t_def[CXTD_AUTO2];
5803 
5804 		switch (policy_type) {
5805 		case BTC_CXP_AUTO2_TD3050:
5806 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
5807 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5808 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
5809 			break;
5810 		case BTC_CXP_AUTO2_TD3070:
5811 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
5812 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5813 			_slot_set(btc, CXST_B4,  70, tbl_b4, SLOT_MIX);
5814 			break;
5815 		case BTC_CXP_AUTO2_TD5050:
5816 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
5817 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5818 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
5819 			break;
5820 		case BTC_CXP_AUTO2_TD6060:
5821 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
5822 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5823 			_slot_set(btc, CXST_B4,  60, tbl_b4, SLOT_MIX);
5824 			break;
5825 		case BTC_CXP_AUTO2_TD2080:
5826 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
5827 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5828 			_slot_set(btc, CXST_B4,  80, tbl_b4, SLOT_MIX);
5829 			break;
5830 		case BTC_CXP_AUTO2_TDW1B4: /* W1:B1 = user-define */
5831 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5832 				  tbl_w1, SLOT_ISO);
5833 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5834 				  tbl_b1, SLOT_MIX);
5835 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
5836 				  tbl_b4, SLOT_MIX);
5837 			break;
5838 		default:
5839 			break;
5840 		}
5841 		break;
5842 	case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
5843 		tdma_on = true;
5844 		*t = t_def[CXTD_PAUTO2];
5845 
5846 		switch (policy_type) {
5847 		case BTC_CXP_PAUTO2_TD3050:
5848 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
5849 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5850 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
5851 			break;
5852 		case BTC_CXP_PAUTO2_TD3070:
5853 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
5854 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5855 			_slot_set(btc, CXST_B4,  70, tbl_b4, SLOT_MIX);
5856 			break;
5857 		case BTC_CXP_PAUTO2_TD5050:
5858 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
5859 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5860 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
5861 			break;
5862 		case BTC_CXP_PAUTO2_TD6060:
5863 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
5864 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5865 			_slot_set(btc, CXST_B4,  60, tbl_b4, SLOT_MIX);
5866 			break;
5867 		case BTC_CXP_PAUTO2_TD2080:
5868 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
5869 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
5870 			_slot_set(btc, CXST_B4,  80, tbl_b4, SLOT_MIX);
5871 			break;
5872 		case BTC_CXP_PAUTO2_TDW1B4: /* W1:B1 = user-define */
5873 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
5874 				  tbl_w1, SLOT_ISO);
5875 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
5876 				  tbl_b1, SLOT_MIX);
5877 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
5878 				  tbl_b4, SLOT_MIX);
5879 			break;
5880 		default:
5881 			break;
5882 		}
5883 		break;
5884 	}
5885 
5886 	/* enter leak_slot after each null-1 */
5887 	if (dm->leak_ap && dm->tdma.leak_n > 1)
5888 		_tdma_set_lek(btc, 1);
5889 
5890 	if (dm->tdma_instant_excute ||
5891 	    dm->error.map.tdma_no_sync ||
5892 	    dm->error.map.slot_no_sync ||
5893 	    dm->lps_ctrl_change) {
5894 		btc->dm.tdma.option_ctrl |= BIT(0);
5895 		btc->update_policy_force = true;
5896 	}
5897 
5898 	if (btc->cli_h2c_cmd)
5899 		btc->update_policy_force = true;
5900 
5901 	_set_tdma_bind(rtwdev, tdma_on);
5902 }
5903 EXPORT_SYMBOL(rtw89_btc_set_policy_v1);
5904 
5905 static void _set_bt_plut(struct rtw89_dev *rtwdev, u8 phy_map,
5906 			 u8 tx_val, u8 rx_val)
5907 {
5908 	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
5909 	struct rtw89_mac_ax_plt plt;
5910 
5911 	plt.tx = tx_val;
5912 	plt.rx = rx_val;
5913 
5914 	if (rtwdev->btc.ver->fwlrole == 8) {
5915 		plt.band = wl->pta_req_mac;
5916 		if (wl->bt_polut_type[plt.band] == tx_val)
5917 			return;
5918 
5919 		wl->bt_polut_type[plt.band] = tx_val;
5920 		rtw89_mac_cfg_plt(rtwdev, &plt);
5921 	} else {
5922 		plt.band = RTW89_MAC_0;
5923 
5924 		if (phy_map & BTC_PHY_0)
5925 			rtw89_mac_cfg_plt(rtwdev, &plt);
5926 
5927 		if (!rtwdev->dbcc_en)
5928 			return;
5929 
5930 		plt.band = RTW89_MAC_1;
5931 		if (phy_map & BTC_PHY_1)
5932 			rtw89_mac_cfg_plt(rtwdev, &plt);
5933 	}
5934 }
5935 
5936 static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec,
5937 		     u8 phy_map, u8 type)
5938 {
5939 	struct rtw89_btc *btc = &rtwdev->btc;
5940 	struct rtw89_btc_cx *cx = &btc->cx;
5941 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5942 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
5943 	u32 ant_path_type = rtw89_get_antpath_type(phy_map, type);
5944 	struct rtw89_btc_dm *dm = &btc->dm;
5945 	u8 gwl = BTC_GNT_HW, gwl0, gwl1, gbt;
5946 	bool cx_ctrl;
5947 
5948 	if (btc->cli_h2c_cmd || wl_rinfo->dbcc_chg ||
5949 	    dm->run_reason == BTC_RSN_NTFY_POWEROFF ||
5950 	    dm->run_reason == BTC_RSN_NTFY_RADIO_STATE ||
5951 	    dm->run_reason == BTC_RSN_CMD_SET_COEX)
5952 		force_exec = FC_EXEC;
5953 
5954 	if (wl_rinfo->link_mode[RTW89_MAC_0] != BTC_WLINK_DB_MCC &&
5955 	    btc->dm.wl_btg_rx == 2)
5956 		force_exec = FC_EXEC;
5957 
5958 	if (!force_exec && ant_path_type == dm->set_ant_path) {
5959 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5960 			    "[BTC], %s(): return by no change!!\n",
5961 			     __func__);
5962 		return;
5963 	} else if (btc->dm.run_reason != BTC_RSN_NTFY_WL_RFK &&
5964 		   wl->rfk_info.state != BTC_WRFK_STOP) {
5965 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5966 			    "[BTC], %s(): return by wl rfk!!\n", __func__);
5967 		return;
5968 	}
5969 
5970 	dm->set_ant_path = ant_path_type;
5971 
5972 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5973 		    "[BTC], %s(): path=0x%x, set_type=0x%x\n",
5974 		    __func__, phy_map, dm->set_ant_path & 0xff);
5975 
5976 	switch (type) {
5977 	case BTC_ANT_WPOWERON:
5978 		cx_ctrl = BTC_CTRL_BY_BT;
5979 		break;
5980 	case BTC_ANT_WINIT:
5981 		cx_ctrl = BTC_CTRL_BY_WL;
5982 		/* To avoid BT MP driver case (bt_enable but no mailbox) */
5983 		if ((cx->bt0.enable.now && cx->bt0.run_patch_code) ||
5984 		    (cx->bt1.enable.now && cx->bt1.run_patch_code))
5985 			_set_gnt(rtwdev, BTC_PHY_ALL, BTC_GNT_SW_LO, BTC_GNT_SW_HI,
5986 				 BTC_WLACT_SW_LO);
5987 		else
5988 			_set_gnt(rtwdev, BTC_PHY_ALL, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
5989 				 BTC_WLACT_SW_HI);
5990 		break;
5991 	case BTC_ANT_WONLY:
5992 		cx_ctrl = BTC_CTRL_BY_WL;
5993 		_set_gnt(rtwdev, BTC_PHY_ALL, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
5994 			 BTC_WLACT_SW_HI);
5995 		break;
5996 	case BTC_ANT_WOFF:
5997 		cx_ctrl = BTC_CTRL_BY_BT;
5998 		_set_gnt(rtwdev, BTC_PHY_ALL, BTC_GNT_SW_LO, BTC_GNT_SW_HI,
5999 			 BTC_WLACT_SW_LO);
6000 		break;
6001 	case BTC_ANT_PTA:
6002 	default:
6003 		cx_ctrl = BTC_CTRL_BY_WL;
6004 		gbt = BTC_GNT_HW;
6005 		if ((rtwdev->chip->para_ver & BTC_FEAT_MULTI_PTA) ||
6006 		    !wl_rinfo->dbcc_en) {
6007 			gwl = BTC_GNT_HW;
6008 			_set_gnt(rtwdev, BTC_PHY_ALL, gwl, gbt, BTC_WLACT_HW);
6009 		} else {
6010 			/* for DBCC Only-1-PTA */
6011 			if (wl_rinfo->dbcc_2g_phy == RTW89_PHY_0) {
6012 				gwl0 = BTC_GNT_HW;
6013 				gwl1 = BTC_GNT_SW_HI;
6014 			} else {
6015 				gwl0 = BTC_GNT_SW_HI;
6016 				gwl1 = BTC_GNT_HW;
6017 			}
6018 			_set_gnt(rtwdev, BTC_PHY_0, gwl0, gbt, BTC_WLACT_HW);
6019 			_set_gnt(rtwdev, BTC_PHY_1, gwl1, gbt, BTC_WLACT_HW);
6020 		}
6021 		break;
6022 	case BTC_ANT_FDD:
6023 		cx_ctrl = BTC_CTRL_BY_WL;
6024 		_set_gnt(rtwdev, BTC_PHY_ALL, BTC_GNT_SW_HI, BTC_GNT_HW,
6025 			 BTC_WLACT_HW);
6026 		break;
6027 	case BTC_ANT_FREERUN:
6028 		cx_ctrl = BTC_CTRL_BY_WL;
6029 		_set_gnt(rtwdev, BTC_PHY_ALL, BTC_GNT_SW_HI, BTC_GNT_SW_HI,
6030 			 BTC_WLACT_SW_LO);
6031 		break;
6032 	case BTC_ANT_WRFK:
6033 		cx_ctrl = BTC_CTRL_BY_WL;
6034 		_set_gnt(rtwdev, BTC_PHY_ALL, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
6035 			 BTC_WLACT_HW);
6036 		break;
6037 	case BTC_ANT_WRFK2:
6038 		cx_ctrl = BTC_CTRL_BY_WL;
6039 		_set_gnt(rtwdev, BTC_PHY_ALL, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
6040 			 BTC_WLACT_SW_HI); /* no BT-Tx */
6041 		break;
6042 	}
6043 
6044 	rtw89_chip_cfg_ctrl_path(rtwdev, cx_ctrl);
6045 	_set_bt_plut(rtwdev, phy_map, BTC_PLT_GNT_WL, BTC_PLT_GNT_WL);
6046 }
6047 
6048 static void _action_wl_only(struct rtw89_dev *rtwdev)
6049 {
6050 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
6051 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_ONLY);
6052 }
6053 
6054 static void _action_wl_init(struct rtw89_dev *rtwdev)
6055 {
6056 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
6057 
6058 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WINIT);
6059 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_INIT);
6060 }
6061 
6062 static void _action_wl_off(struct rtw89_dev *rtwdev, u8 mode)
6063 {
6064 	struct rtw89_btc *btc = &rtwdev->btc;
6065 	struct rtw89_btc_dm *dm = &btc->dm;
6066 	struct rtw89_btc_cx *cx = &btc->cx;
6067 	struct rtw89_btc_wl_info *wl = &cx->wl;
6068 
6069 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
6070 
6071 	if (wl->status.map.rf_off || btc->dm.bt_only)
6072 		_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_WOFF);
6073 	else if (wl->status.map.lps == BTC_LPS_RF_ON ||
6074 		 cx->bt0.whql_test || cx->bt1.whql_test)
6075 		_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_PTA);
6076 
6077 	if (dm->out_of_band)
6078 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OFF);
6079 	else if (cx->bt0.whql_test || cx->bt1.whql_test)
6080 		_set_policy(rtwdev, BTC_CXP_OFFB_BWB4, BTC_ACT_WL_OFF);
6081 	else
6082 		_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
6083 }
6084 
6085 static void _action_freerun(struct rtw89_dev *rtwdev)
6086 {
6087 	struct rtw89_btc *btc = &rtwdev->btc;
6088 
6089 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
6090 
6091 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_FREERUN);
6092 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_FREERUN);
6093 
6094 	btc->dm.freerun = true;
6095 }
6096 
6097 static void _action_bt_whql(struct rtw89_dev *rtwdev)
6098 {
6099 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
6100 
6101 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6102 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_WHQL);
6103 }
6104 
6105 static void _action_bt_off(struct rtw89_dev *rtwdev)
6106 {
6107 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
6108 
6109 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
6110 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_OFF);
6111 }
6112 
6113 static void _action_bt_idle(struct rtw89_dev *rtwdev)
6114 {
6115 	struct rtw89_btc *btc = &rtwdev->btc;
6116 	struct rtw89_btc_bt_link_info *b = &btc->cx.bt0.link_info;
6117 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6118 
6119 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6120 
6121 	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
6122 		switch (btc->cx.state_map) {
6123 		case BTC_WBUSY_BNOSCAN: /*wl-busy + bt idle*/
6124 		case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */
6125 			if (b->status.map.connect)
6126 				_set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_IDLE);
6127 			else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL))
6128 				_set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_DL, BTC_ACT_BT_IDLE);
6129 			else
6130 				_set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_UL, BTC_ACT_BT_IDLE);
6131 			break;
6132 		case BTC_WBUSY_BSCAN: /*wl-busy + bt-inq */
6133 			_set_policy(rtwdev, BTC_CXP_PFIX_TD5050,
6134 				    BTC_ACT_BT_IDLE);
6135 			break;
6136 		case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq */
6137 			_set_policy(rtwdev, BTC_CXP_FIX_TD5050,
6138 				    BTC_ACT_BT_IDLE);
6139 			break;
6140 		case BTC_WLINKING: /* wl-connecting + bt-inq or bt-idle */
6141 			_set_policy(rtwdev, BTC_CXP_FIX_TD7010,
6142 				    BTC_ACT_BT_IDLE);
6143 			break;
6144 		case BTC_WIDLE:  /* wl-idle + bt-idle */
6145 			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_IDLE);
6146 			break;
6147 		}
6148 	} else { /* dedicated-antenna */
6149 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_BT_IDLE);
6150 	}
6151 }
6152 
6153 static void _action_bt_hfp(struct rtw89_dev *rtwdev)
6154 {
6155 	struct rtw89_btc *btc = &rtwdev->btc;
6156 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6157 
6158 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6159 
6160 	if (btc->ant_type == BTC_ANT_SHARED) {
6161 		if (btc->cx.wl.status.map._4way) {
6162 			_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_BT_HFP);
6163 		} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
6164 			btc->cx.bt0.scan_rx_low_pri = true;
6165 			_set_policy(rtwdev, BTC_CXP_OFF_BWB2, BTC_ACT_BT_HFP);
6166 		} else {
6167 			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP);
6168 		}
6169 	} else {
6170 		if (wl->bg_mode[RTW89_MAC_0])
6171 			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP);
6172 		else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
6173 			_set_policy(rtwdev, BTC_CXP_OFF_EQ5, BTC_ACT_BT_HFP);
6174 		else
6175 			_set_policy(rtwdev, BTC_CXP_OFF_EQ2, BTC_ACT_BT_HFP);
6176 	}
6177 }
6178 
6179 static void _action_bt_hid(struct rtw89_dev *rtwdev)
6180 {
6181 	const struct rtw89_chip_info *chip = rtwdev->chip;
6182 	struct rtw89_btc *btc = &rtwdev->btc;
6183 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6184 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
6185 	struct rtw89_btc_bt_hid_desc *hid = &bt->link_info.hid_desc;
6186 	u16 policy_type = BTC_CXP_OFF_BT;
6187 
6188 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6189 
6190 	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
6191 		if (wl->status.map._4way) {
6192 			policy_type = BTC_CXP_OFF_WL;
6193 		} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
6194 			btc->cx.bt0.scan_rx_low_pri = true;
6195 			if (hid->type & BTC_HID_BLE)
6196 				policy_type = BTC_CXP_OFF_BWB0;
6197 			else
6198 				policy_type = BTC_CXP_OFF_BWB2;
6199 		} else if (hid->type == BTC_HID_218) {
6200 			bt->scan_rx_low_pri = true;
6201 			policy_type = BTC_CXP_OFF_BWB2;
6202 		} else if (chip->para_ver == 0x1) {
6203 			policy_type = BTC_CXP_OFF_BWB3;
6204 		} else {
6205 			policy_type = BTC_CXP_OFF_BWB1;
6206 		}
6207 	} else { /* dedicated-antenna */
6208 		if (wl->bg_mode[RTW89_MAC_0])
6209 			policy_type = BTC_CXP_OFF_BWB1;
6210 		else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
6211 			policy_type = BTC_CXP_OFF_EQ4;
6212 		else
6213 			policy_type = BTC_CXP_OFF_EQ3;
6214 	}
6215 
6216 	_set_policy(rtwdev, policy_type, BTC_ACT_BT_HID);
6217 }
6218 
6219 static void _action_bt_a2dp(struct rtw89_dev *rtwdev)
6220 {
6221 	struct rtw89_btc *btc = &rtwdev->btc;
6222 	struct rtw89_btc_dm *dm = &btc->dm;
6223 
6224 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6225 
6226 	dm->slot_dur[CXST_W1] = 20;
6227 	dm->slot_dur[CXST_B1] = BTC_B1_MAX;
6228 
6229 	switch (btc->cx.state_map) {
6230 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP */
6231 		_set_policy(rtwdev, BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP);
6232 		break;
6233 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP */
6234 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3050, BTC_ACT_BT_A2DP);
6235 		break;
6236 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP */
6237 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP);
6238 		break;
6239 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP */
6240 	case BTC_WLINKING: /* wl-connecting + bt-A2DP */
6241 		if (btc->cx.wl.rfk_info.con_rfk)
6242 			_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DP);
6243 		else
6244 			_set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1, BTC_ACT_BT_A2DP);
6245 		break;
6246 	case BTC_WIDLE:  /* wl-idle + bt-A2DP */
6247 		_set_policy(rtwdev, BTC_CXP_AUTO_TD20B1, BTC_ACT_BT_A2DP);
6248 		break;
6249 	}
6250 }
6251 
6252 static void _action_bt_a2dpsink(struct rtw89_dev *rtwdev)
6253 {
6254 	struct rtw89_btc *btc = &rtwdev->btc;
6255 
6256 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6257 
6258 	switch (btc->cx.state_map) {
6259 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2dp_Sink */
6260 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2030, BTC_ACT_BT_A2DPSINK);
6261 		break;
6262 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2dp_Sink */
6263 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2060, BTC_ACT_BT_A2DPSINK);
6264 		break;
6265 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2dp_Sink */
6266 		_set_policy(rtwdev, BTC_CXP_FIX_TD2030, BTC_ACT_BT_A2DPSINK);
6267 		break;
6268 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2dp_Sink */
6269 		_set_policy(rtwdev, BTC_CXP_FIX_TD2060, BTC_ACT_BT_A2DPSINK);
6270 		break;
6271 	case BTC_WLINKING: /* wl-connecting + bt-A2dp_Sink */
6272 		if (btc->cx.wl.rfk_info.con_rfk)
6273 			_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DPSINK);
6274 		else
6275 			_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_A2DPSINK);
6276 		break;
6277 	case BTC_WIDLE: /* wl-idle + bt-A2dp_Sink */
6278 		_set_policy(rtwdev, BTC_CXP_FIX_TD2080, BTC_ACT_BT_A2DPSINK);
6279 		break;
6280 	}
6281 }
6282 
6283 static void _action_bt_pan(struct rtw89_dev *rtwdev)
6284 {
6285 	struct rtw89_btc *btc = &rtwdev->btc;
6286 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt0.link_info;
6287 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
6288 	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
6289 
6290 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6291 
6292 	switch (btc->cx.state_map) {
6293 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN */
6294 		if (a2dp.active || !pan.exist) {
6295 			btc->dm.slot_dur[CXST_W1] = 80;
6296 			btc->dm.slot_dur[CXST_B1] = 20;
6297 			_set_policy(rtwdev, BTC_CXP_PFIX_TDW1B1, BTC_ACT_BT_PAN);
6298 		} else {
6299 			_set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN);
6300 		}
6301 		break;
6302 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN */
6303 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN);
6304 		break;
6305 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-PAN */
6306 		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_PAN);
6307 		break;
6308 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-PAN */
6309 		_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN);
6310 		break;
6311 	case BTC_WLINKING: /* wl-connecting + bt-PAN */
6312 		_set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO, BTC_ACT_BT_PAN);
6313 		break;
6314 	case BTC_WIDLE: /* wl-idle + bt-pan */
6315 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN);
6316 		break;
6317 	}
6318 }
6319 
6320 static void _action_bt_a2dp_hid(struct rtw89_dev *rtwdev)
6321 {
6322 	struct rtw89_btc *btc = &rtwdev->btc;
6323 	struct rtw89_btc_dm *dm = &btc->dm;
6324 
6325 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6326 
6327 	dm->slot_dur[CXST_W1] = 20;
6328 	dm->slot_dur[CXST_B1] = BTC_B1_MAX;
6329 
6330 	switch (btc->cx.state_map) {
6331 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+HID */
6332 	case BTC_WIDLE:  /* wl-idle + bt-A2DP */
6333 		_set_policy(rtwdev, BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
6334 		break;
6335 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+HID */
6336 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_HID);
6337 		break;
6338 
6339 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+HID */
6340 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP_HID);
6341 		break;
6342 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+HID */
6343 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+HID */
6344 		if (btc->cx.wl.rfk_info.con_rfk)
6345 			_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DP_HID);
6346 		else
6347 			_set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
6348 		break;
6349 	}
6350 }
6351 
6352 static void _action_bt_a2dp_pan(struct rtw89_dev *rtwdev)
6353 {
6354 	struct rtw89_btc *btc = &rtwdev->btc;
6355 
6356 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6357 
6358 	switch (btc->cx.state_map) {
6359 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+PAN */
6360 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
6361 		break;
6362 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+PAN */
6363 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
6364 		break;
6365 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+PAN */
6366 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD5050, BTC_ACT_BT_A2DP_PAN);
6367 		break;
6368 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+PAN */
6369 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
6370 		break;
6371 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+PAN */
6372 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP_PAN);
6373 		break;
6374 	case BTC_WIDLE:  /* wl-idle + bt-A2DP+PAN */
6375 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD2080, BTC_ACT_BT_A2DP_PAN);
6376 		break;
6377 	}
6378 }
6379 
6380 static void _action_bt_pan_hid(struct rtw89_dev *rtwdev)
6381 {
6382 	struct rtw89_btc *btc = &rtwdev->btc;
6383 
6384 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6385 
6386 	switch (btc->cx.state_map) {
6387 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN+HID */
6388 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3030, BTC_ACT_BT_PAN_HID);
6389 		break;
6390 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN+HID */
6391 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN_HID);
6392 		break;
6393 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-PAN+HID */
6394 		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_PAN_HID);
6395 		break;
6396 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-PAN+HID */
6397 		_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN_HID);
6398 		break;
6399 	case BTC_WLINKING: /* wl-connecting + bt-PAN+HID */
6400 		_set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_PAN_HID);
6401 		break;
6402 	case BTC_WIDLE: /* wl-idle + bt-PAN+HID */
6403 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN_HID);
6404 		break;
6405 	}
6406 }
6407 
6408 static void _action_bt_bis(struct rtw89_dev *rtwdev)
6409 {
6410 	struct rtw89_btc *btc = &rtwdev->btc;
6411 	struct rtw89_btc_dm *dm = &btc->dm;
6412 	u16 policy_type;
6413 
6414 	if (dm->bis_tdma)
6415 		policy_type = BTC_CXP_OFFE_2GBWISOB;
6416 	else
6417 		policy_type = BTC_CXP_OFF_EQ0;
6418 
6419 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_PTA);
6420 	_set_policy(rtwdev, policy_type, BTC_ACT_BT_BIS);
6421 }
6422 
6423 static void _action_bt_cis(struct rtw89_dev *rtwdev)
6424 {
6425 	struct rtw89_btc *btc = &rtwdev->btc;
6426 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt0.link_info;
6427 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6428 	struct rtw89_btc_dm *dm = &btc->dm;
6429 	u16 policy_type;
6430 
6431 	if (bt_linfo->a2dp_desc.active) {
6432 		dm->slot_dur[CXST_W1] = 80;
6433 		dm->slot_dur[CXST_B1] = 20;
6434 		policy_type = BTC_CXP_PFIX_TDW1B1;
6435 	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
6436 		policy_type = BTC_CXP_OFF_BWB0;
6437 	} else {
6438 		policy_type = BTC_CXP_OFF_BWB1;
6439 	}
6440 
6441 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_PTA);
6442 	_set_policy(rtwdev, policy_type, BTC_ACT_BT_CIS);
6443 }
6444 
6445 static void _action_bt_a2dp_pan_hid(struct rtw89_dev *rtwdev)
6446 {
6447 	struct rtw89_btc *btc = &rtwdev->btc;
6448 
6449 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6450 
6451 	switch (btc->cx.state_map) {
6452 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+PAN+HID */
6453 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070,
6454 			    BTC_ACT_BT_A2DP_PAN_HID);
6455 		break;
6456 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+PAN+HID */
6457 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070,
6458 			    BTC_ACT_BT_A2DP_PAN_HID);
6459 		break;
6460 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+PAN+HID */
6461 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3070,
6462 			    BTC_ACT_BT_A2DP_PAN_HID);
6463 		break;
6464 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+PAN+HID */
6465 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+PAN+HID */
6466 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050,
6467 			    BTC_ACT_BT_A2DP_PAN_HID);
6468 		break;
6469 	case BTC_WIDLE:  /* wl-idle + bt-A2DP+PAN+HID */
6470 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD2080,
6471 			    BTC_ACT_BT_A2DP_PAN_HID);
6472 		break;
6473 	}
6474 }
6475 
6476 static void _action_wl_5g(struct rtw89_dev *rtwdev)
6477 {
6478 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_FDD);
6479 	_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_5G);
6480 }
6481 
6482 static void _action_wl_other(struct rtw89_dev *rtwdev)
6483 {
6484 	struct rtw89_btc *btc = &rtwdev->btc;
6485 
6486 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6487 
6488 	if (btc->ant_type == BTC_ANT_SHARED)
6489 		_set_policy(rtwdev, BTC_CXP_OFFB_BWB0, BTC_ACT_WL_OTHER);
6490 	else
6491 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OTHER);
6492 }
6493 
6494 static void _action_wl_nc(struct rtw89_dev *rtwdev)
6495 {
6496 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
6497 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_NC);
6498 }
6499 
6500 static void _action_wl_rfk(struct rtw89_dev *rtwdev)
6501 {
6502 	struct rtw89_btc *btc = &rtwdev->btc;
6503 	struct rtw89_btc_wl_rfk_info rfk = btc->cx.wl.rfk_info;
6504 
6505 	if (rfk.state != BTC_WRFK_START)
6506 		return;
6507 
6508 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): band = %d\n",
6509 		    __func__, rfk.band);
6510 
6511 	btc->dm.tdma_instant_excute = 1;
6512 
6513 	if (rfk.state == BTC_WRFK_ONESHOT_START ||
6514 	    btc->ant_type == BTC_ANT_SHARED) {
6515 		_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK2);
6516 		_set_policy(rtwdev, BTC_CXP_OFF_WL2, BTC_ACT_WL_RFK);
6517 	} else {
6518 		_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK);
6519 		_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK);
6520 	}
6521 }
6522 
6523 static void _set_btg_ctrl(struct rtw89_dev *rtwdev)
6524 {
6525 	struct rtw89_btc *btc = &rtwdev->btc;
6526 	struct rtw89_btc_dm *dm = &btc->dm;
6527 	struct rtw89_btc_fbtc_outsrc_set_info *o_info = &dm->ost_info;
6528 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6529 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
6530 	const struct rtw89_chip_info *chip = rtwdev->chip;
6531 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
6532 	u32 is_btg = BTC_BTGCTRL_DISABLE;
6533 
6534 	if (btc->manual_ctrl)
6535 		return;
6536 
6537 	/* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */
6538 	if (btc->ant_type == BTC_ANT_SHARED) {
6539 		if (!(bt->run_patch_code && bt->enable.now))
6540 			is_btg = BTC_BTGCTRL_DISABLE;
6541 		else if (wl->rf_band_map[RTW89_MAC_0] & BIT(RTW89_BAND_2G) ||
6542 			 wl->rf_band_map[RTW89_MAC_1] & BIT(RTW89_BAND_2G))
6543 			is_btg = BTC_BTGCTRL_ENABLE;
6544 		else
6545 			is_btg = BTC_BTGCTRL_DISABLE;
6546 
6547 		/* bb call ctrl_btg() in WL FW by slot */
6548 		if (!btc->ver->fcxosi &&
6549 		    wl_rinfo->link_mode[RTW89_MAC_0] == BTC_WLINK_DB_MCC)
6550 			is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL;
6551 	}
6552 
6553 	if (is_btg == dm->wl_btg_rx)
6554 		return;
6555 	else
6556 		dm->wl_btg_rx = is_btg;
6557 
6558 	/* skip setup if btg_ctrl set by wl fw */
6559 	if (!btc->ver->fcxosi && is_btg > BTC_BTGCTRL_ENABLE)
6560 		return;
6561 
6562 	/* Below flow is for BTC_FEAT_NEW_BBAPI_FLOW = 1 */
6563 	if (o_info->rf_band[BTC_RF_S0] != o_info->rf_band[BTC_RF_S1]) {/* 1+1 */
6564 		if (o_info->rf_band[BTC_RF_S0]) /* Non-2G */
6565 			o_info->btg_rx[BTC_RF_S0] = BTC_BTGCTRL_DISABLE;
6566 		else
6567 			o_info->btg_rx[BTC_RF_S0] = is_btg;
6568 
6569 		if (o_info->rf_band[BTC_RF_S1]) /* Non-2G */
6570 			o_info->btg_rx[BTC_RF_S1] = BTC_BTGCTRL_DISABLE;
6571 		else
6572 			o_info->btg_rx[BTC_RF_S1] = is_btg;
6573 	} else { /* 2+0 or 0+2 */
6574 		o_info->btg_rx[BTC_RF_S0] = is_btg;
6575 		o_info->btg_rx[BTC_RF_S1] = is_btg;
6576 	}
6577 
6578 	if (btc->ver->fcxosi)
6579 		return;
6580 
6581 	chip->ops->ctrl_btg_bt_rx(rtwdev, o_info->btg_rx[BTC_RF_S0],
6582 				  RTW89_PHY_0);
6583 	if (chip->chip_id != RTL8922A)
6584 		return;
6585 
6586 	chip->ops->ctrl_btg_bt_rx(rtwdev, o_info->btg_rx[BTC_RF_S1],
6587 				  RTW89_PHY_1);
6588 }
6589 
6590 static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev)
6591 {
6592 	struct rtw89_btc *btc = &rtwdev->btc;
6593 	struct rtw89_btc_fbtc_outsrc_set_info *o_info = &btc->dm.ost_info;
6594 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt0.link_info;
6595 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6596 	struct rtw89_btc_wl_role_info *rinfo = &wl->role_info;
6597 	const struct rtw89_chip_info *chip = rtwdev->chip;
6598 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
6599 	struct rtw89_btc_dm *dm = &btc->dm;
6600 	u8 is_preagc, val;
6601 
6602 	if (btc->manual_ctrl)
6603 		return;
6604 
6605 	if (!(bt->run_patch_code && bt->enable.now)) {
6606 		is_preagc = BTC_PREAGC_DISABLE;
6607 	} else if (dm->tdd_bind.rf_band == BIT(RTW89_BAND_5G)) {
6608 		is_preagc = BTC_PREAGC_DISABLE;
6609 	} else if (rinfo->link_mode[RTW89_MAC_0] == BTC_WLINK_NOLINK ||
6610 		 btc->cx.bt0.link_info.link_cnt.now == 0) {
6611 		is_preagc = BTC_PREAGC_DISABLE;
6612 	} else if (dm->tdma_now.type != CXTDMA_OFF &&
6613 		 !bt_linfo->hfp_desc.exist &&
6614 		 !bt_linfo->hid_desc.exist &&
6615 		 dm->fddt_train == BTC_FDDT_DISABLE) {
6616 		is_preagc = BTC_PREAGC_DISABLE;
6617 	} else if (rinfo->dbcc_en && (rinfo->dbcc_2g_phy != RTW89_PHY_1)) {
6618 		is_preagc = BTC_PREAGC_DISABLE;
6619 	} else if (btc->ant_type == BTC_ANT_SHARED) {
6620 		is_preagc = BTC_PREAGC_DISABLE;
6621 	} else {
6622 		is_preagc = BTC_PREAGC_ENABLE;
6623 	}
6624 
6625 	if (!btc->ver->fcxosi && rinfo->link_mode[RTW89_MAC_0] == BTC_WLINK_DB_MCC)
6626 		is_preagc = BTC_PREAGC_BB_FWCTRL;
6627 
6628 	if (dm->wl_pre_agc_rb != dm->wl_pre_agc &&
6629 	    dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND) {
6630 		_get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC, &val);
6631 		dm->wl_pre_agc_rb = val;
6632 	}
6633 
6634 	if ((wl->coex_mode == BTC_MODE_NORMAL &&
6635 	     (dm->run_reason == BTC_RSN_NTFY_INIT ||
6636 	      dm->run_reason == BTC_RSN_NTFY_SWBAND ||
6637 	      dm->wl_pre_agc_rb != dm->wl_pre_agc)) ||
6638 	    is_preagc != dm->wl_pre_agc) {
6639 		dm->wl_pre_agc = is_preagc;
6640 
6641 		if (!btc->ver->fcxosi && is_preagc > BTC_PREAGC_ENABLE)
6642 			return;
6643 
6644 		if (o_info->rf_band[BTC_RF_S0] != o_info->rf_band[BTC_RF_S1]) {/* 1+1 */
6645 			if (o_info->rf_band[BTC_RF_S0]) /* Non-2G */
6646 				o_info->nbtg_tx[BTC_RF_S0] = BTC_PREAGC_DISABLE;
6647 			else
6648 				o_info->nbtg_tx[BTC_RF_S0] = is_preagc;
6649 
6650 			if (o_info->rf_band[BTC_RF_S1]) /* Non-2G */
6651 				o_info->nbtg_tx[BTC_RF_S1] = BTC_PREAGC_DISABLE;
6652 			else
6653 				o_info->nbtg_tx[BTC_RF_S1] = is_preagc;
6654 
6655 		} else { /* 2+0 or 0+2 */
6656 			o_info->nbtg_tx[BTC_RF_S0] = is_preagc;
6657 			o_info->nbtg_tx[BTC_RF_S1] = is_preagc;
6658 		}
6659 
6660 		if (btc->ver->fcxosi)
6661 			return;
6662 
6663 		chip->ops->ctrl_nbtg_bt_tx(rtwdev, o_info->nbtg_tx[BTC_RF_S0],
6664 					   RTW89_PHY_0);
6665 		if (chip->chip_id != RTL8922A)
6666 			return;
6667 		chip->ops->ctrl_nbtg_bt_tx(rtwdev, o_info->nbtg_tx[BTC_RF_S1],
6668 					   RTW89_PHY_1);
6669 	}
6670 }
6671 
6672 struct rtw89_txtime_data {
6673 	struct rtw89_dev *rtwdev;
6674 	int type;
6675 	u32 tx_time;
6676 	u8 tx_retry;
6677 	u16 enable;
6678 	bool reenable;
6679 };
6680 
6681 static void __rtw89_tx_time_iter(struct rtw89_vif_link *rtwvif_link,
6682 				 struct rtw89_sta_link *rtwsta_link,
6683 				 struct rtw89_txtime_data *iter_data)
6684 {
6685 	struct rtw89_dev *rtwdev = iter_data->rtwdev;
6686 	struct rtw89_btc *btc = &rtwdev->btc;
6687 	struct rtw89_btc_cx *cx = &btc->cx;
6688 	struct rtw89_btc_wl_info *wl = &cx->wl;
6689 	struct rtw89_btc_wl_link_info *plink = NULL;
6690 	u8 port = rtwvif_link->port;
6691 	u32 tx_time = iter_data->tx_time;
6692 	u8 tx_retry = iter_data->tx_retry;
6693 	u16 enable = iter_data->enable;
6694 	bool reenable = iter_data->reenable;
6695 
6696 	plink = &wl->rlink_info[port][rtwsta_link->link_id];
6697 
6698 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
6699 		    "[BTC], %s(): port = %d\n", __func__, port);
6700 
6701 	if (!plink->connected) {
6702 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6703 			    "[BTC], %s(): connected = %d\n",
6704 			    __func__, plink->connected);
6705 		return;
6706 	}
6707 
6708 	/* backup the original tx time before tx-limit on */
6709 	if (reenable) {
6710 		rtw89_mac_get_tx_time(rtwdev, rtwsta_link, &plink->tx_time);
6711 		rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta_link, &plink->tx_retry);
6712 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6713 			    "[BTC], %s(): reenable, tx_time=%d tx_retry= %d\n",
6714 			    __func__, plink->tx_time, plink->tx_retry);
6715 	}
6716 
6717 	/* restore the original tx time if no tx-limit */
6718 	if (!enable) {
6719 		rtw89_mac_set_tx_time(rtwdev, rtwsta_link, true, plink->tx_time);
6720 		rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, true,
6721 					     plink->tx_retry);
6722 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6723 			    "[BTC], %s(): restore, tx_time=%d tx_retry= %d\n",
6724 			    __func__, plink->tx_time, plink->tx_retry);
6725 
6726 	} else {
6727 		rtw89_mac_set_tx_time(rtwdev, rtwsta_link, false, tx_time);
6728 		rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, tx_retry);
6729 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6730 			    "[BTC], %s(): set, tx_time=%d tx_retry= %d\n",
6731 			    __func__, tx_time, tx_retry);
6732 	}
6733 }
6734 
6735 static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
6736 {
6737 	struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
6738 	struct rtw89_txtime_data *iter_data =
6739 				(struct rtw89_txtime_data *)data;
6740 	struct rtw89_vif_link *rtwvif_link;
6741 	struct rtw89_sta_link *rtwsta_link;
6742 	unsigned int link_id;
6743 
6744 	rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
6745 		rtwvif_link = rtwsta_link->rtwvif_link;
6746 		__rtw89_tx_time_iter(rtwvif_link, rtwsta_link, iter_data);
6747 	}
6748 }
6749 
6750 static void _set_wl_tx_limit(struct rtw89_dev *rtwdev)
6751 {
6752 	struct rtw89_btc *btc = &rtwdev->btc;
6753 	struct rtw89_btc_cx *cx = &btc->cx;
6754 	struct rtw89_btc_dm *dm = &btc->dm;
6755 	struct rtw89_btc_wl_info *wl = &cx->wl;
6756 	struct rtw89_btc_bt_info *bt = &cx->bt0;
6757 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
6758 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
6759 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
6760 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
6761 	struct rtw89_txtime_data data = {.rtwdev = rtwdev};
6762 	bool reenable = false;
6763 	u8 tx_retry;
6764 	u32 tx_time;
6765 	u16 enable;
6766 
6767 	if (btc->manual_ctrl)
6768 		return;
6769 
6770 	if (btc->dm.freerun || btc->ctrl.igno_bt || b->link_cnt.now == 0 ||
6771 	    dm->tdd_bind.rf_band == BIT(RTW89_BAND_5G) ||
6772 	    wl_rinfo->link_mode[RTW89_MAC_0] == BTC_WLINK_NOLINK) {
6773 		enable = 0;
6774 		tx_time = BTC_MAX_TX_TIME_DEF;
6775 		tx_retry = BTC_MAX_TX_RETRY_DEF;
6776 	} else if ((hfp->exist && hid->exist) || hid->pair_cnt > 1) {
6777 		enable = 1;
6778 		tx_time = BTC_MAX_TX_TIME_L2;
6779 		tx_retry = BTC_MAX_TX_RETRY_L1;
6780 	} else if (hfp->exist || hid->exist) {
6781 		enable = 1;
6782 		tx_time = BTC_MAX_TX_TIME_L3;
6783 		tx_retry = BTC_MAX_TX_RETRY_L1;
6784 	} else {
6785 		enable = 0;
6786 		tx_time = BTC_MAX_TX_TIME_DEF;
6787 		tx_retry = BTC_MAX_TX_RETRY_DEF;
6788 	}
6789 
6790 	if (dm->wl_tx_limit.enable == enable &&
6791 	    dm->wl_tx_limit.tx_time == tx_time &&
6792 	    dm->wl_tx_limit.tx_retry == tx_retry)
6793 		return;
6794 
6795 	if (!dm->wl_tx_limit.enable && enable)
6796 		reenable = true;
6797 
6798 	dm->wl_tx_limit.enable = enable;
6799 	dm->wl_tx_limit.tx_time = tx_time;
6800 	dm->wl_tx_limit.tx_retry = tx_retry;
6801 
6802 	data.enable = enable;
6803 	data.tx_time = tx_time;
6804 	data.tx_retry = tx_retry;
6805 	data.reenable = reenable;
6806 
6807 	ieee80211_iterate_stations_atomic(rtwdev->hw,
6808 					  rtw89_tx_time_iter,
6809 					  &data);
6810 }
6811 
6812 static void _set_phl_bt_slot_req(struct rtw89_dev *rtwdev)
6813 {
6814 	struct rtw89_btc *btc = &rtwdev->btc;
6815 	struct rtw89_btc_cx *cx = &btc->cx;
6816 	struct rtw89_btc_wl_info *wl = &cx->wl;
6817 	struct rtw89_btc_dm *dm = &btc->dm;
6818 	u8 len = 0;
6819 	u8 i;
6820 
6821 	/* don't change bt slot req state during RFK for p2p/mcc case */
6822 	if (dm->run_reason == BTC_RSN_NTFY_WL_RFK ||
6823 	    wl->status.map.transacting)
6824 		return;
6825 
6826 	/* enable bt-slot req if ext-slot-control */
6827 	if (dm->tdma_now.type == CXTDMA_OFF &&
6828 	    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
6829 	    dm->tdd_bind.bt_sel != 0) {
6830 		if (btc->cx.wl.status.val & btc_scanning_map.val)
6831 			btc->bt_req_en = false;
6832 		else
6833 			btc->bt_req_en = true;
6834 	} else {
6835 		btc->bt_req_en = false;
6836 	}
6837 
6838 	if (dm->slot_req_more) {
6839 		len = BTC_BSLOT_A2DP_HID;
6840 	} else {
6841 		if (dm->tdd_bind.bt_link_weight >= BTC_BSLOT_A2DP_HID)
6842 			len = BTC_BSLOT_A2DP_HID;
6843 		else if (dm->tdd_bind.bt_link_weight <= BTC_BSLOT_IDLE)
6844 			len = BTC_BSLOT_IDLE;
6845 		else
6846 			len = dm->tdd_bind.bt_link_weight;
6847 	}
6848 
6849 	if (dm->tdd_bind.rf_band == BIT(RTW89_BAND_5G))
6850 		len = 100 - len;
6851 
6852 	if (!btc->bt_req_en)
6853 		len = 0;
6854 
6855 	for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++) {
6856 		if (!(dm->tdd_bind.wl_hwb_sel & BIT(i)))
6857 			continue;
6858 
6859 		if (len == btc->bt_req_len[i])
6860 			continue;
6861 
6862 		btc->bt_req_len[i] = len;
6863 
6864 		rtw89_core_ntfy_btc_event(rtwdev,
6865 					  RTW89_BTC_HMSG_SET_BT_REQ_SLOT, i);
6866 
6867 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6868 			    "[BTC], %s(): HWB%d bt_req_len = %d\n",
6869 			    __func__, i, btc->bt_req_len[i]);
6870 	}
6871 }
6872 
6873 static void _set_bt_rx_agc(struct rtw89_dev *rtwdev)
6874 {
6875 	struct rtw89_btc *btc = &rtwdev->btc;
6876 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6877 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
6878 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
6879 	bool bt_hi_lna_rx = false;
6880 
6881 	if (wl_rinfo->link_mode[RTW89_MAC_0] != BTC_WLINK_NOLINK && btc->dm.wl_btg_rx)
6882 		bt_hi_lna_rx = true;
6883 
6884 	if (bt_hi_lna_rx == bt->hi_lna_rx)
6885 		return;
6886 
6887 	_write_scbd(rtwdev, BTC_BT_1ST, BTC_WSCB_BT_HILNA, bt_hi_lna_rx);
6888 }
6889 
6890 static void _set_bt_rx_scan_pri(struct rtw89_dev *rtwdev)
6891 {
6892 	struct rtw89_btc *btc = &rtwdev->btc;
6893 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
6894 
6895 	_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_RXSCAN_PRI,
6896 		    (bool)(!!bt->scan_rx_low_pri));
6897 }
6898 
6899 static void _wl_req_mac(struct rtw89_dev *rtwdev, u8 mac)
6900 {
6901 	struct rtw89_btc *btc = &rtwdev->btc;
6902 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6903 	struct rtw89_btc_dm *dm = &btc->dm;
6904 	u32 add;
6905 
6906 	if (mac == wl->pta_req_mac)
6907 		return;
6908 
6909 	dm->ost_info.pta_req_hw_band = mac;
6910 	wl->pta_req_mac = mac;
6911 	wl->pta_reg_mac_chg = true;
6912 
6913 	if (btc->ver->fcxosi)
6914 		return;
6915 
6916 	if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
6917 		add = R_BE_BTC_CFG;
6918 	else
6919 		add = R_AX_BTC_CFG;
6920 
6921 	if (mac == RTW89_MAC_0)
6922 		rtw89_write32_clr(rtwdev, add, B_AX_WL_SRC);
6923 	else
6924 		rtw89_write32_set(rtwdev, add, B_AX_WL_SRC);
6925 }
6926 
6927 static void _update_zb_coex_tbl(struct rtw89_dev *rtwdev)
6928 {
6929 	struct rtw89_btc *btc = &rtwdev->btc;
6930 	u32 zb_tbl0 = 0xda5a5a5a, zb_tbl1 = 0xda5a5a5a;
6931 	u8 link_mode_chg = btc->cx.wl.link_mode_chg;
6932 	u8 mode = btc->cx.wl.role_info.link_mode[RTW89_MAC_0];
6933 
6934 	if (btc->dm.run_reason != BTC_RSN_NTFY_INIT && !link_mode_chg)
6935 		return;
6936 
6937 	if (!(btc->mdinfo.wa_type & BTC_WA_HFP_ZB))
6938 		return;
6939 
6940 	if (btc->dm.tdd_bind.rf_band == BIT(RTW89_BAND_5G) ||
6941 	    rtwdev->btc.dm.freerun) {
6942 		zb_tbl0 = 0xffffffff;
6943 		zb_tbl1 = 0xffffffff;
6944 	} else if (mode == BTC_WLINK_DB_MCC) {
6945 		zb_tbl0 = 0xffffffff; /* for E5G slot */
6946 		zb_tbl1 = 0xda5a5a5a; /* for E2G slot */
6947 	}
6948 	rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_0, zb_tbl0);
6949 	rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_1, zb_tbl1);
6950 }
6951 
6952 static void _set_fw_report_map(struct rtw89_dev *rtwdev)
6953 {
6954 	struct rtw89_btc *btc = &rtwdev->btc;
6955 	struct rtw89_btc_wl_smap *wl_smap = &btc->cx.wl.status.map;
6956 	struct rtw89_btc_bt_info *bt0 = &btc->cx.bt0;
6957 	struct rtw89_btc_bt_info *bt1 = &btc->cx.bt1;
6958 	u32 rpt_map = btc->fwinfo.rpt_en_map;
6959 	u32 bt_rom_code_id, bt_fw_ver;
6960 	bool bt_ver_unknown = false;
6961 	u32 bitmap;
6962 
6963 	if (wl_smap->rf_off == 1 || wl_smap->lps != BTC_LPS_OFF) {
6964 		rtw89_btc_fw_en_rpt(rtwdev, false, 0);
6965 		return;
6966 	}
6967 
6968 	rpt_map |= rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_TDMA);
6969 	rpt_map |= rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_CYCLE);
6970 	rpt_map |= rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_MREG);
6971 
6972 	bitmap = rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_BT_SCAN_INFO);
6973 	if ((bt0->run_patch_code && bt0->enable.now) ||
6974 	    (bt1->run_patch_code && bt1->enable.now))
6975 		rpt_map |= bitmap;
6976 	else
6977 		rpt_map &= ~bitmap;
6978 
6979 	bt_rom_code_id = chip_id_to_bt_rom_code_id(rtwdev->btc.ver->chip_id);
6980 	bt_fw_ver = bt0->ver_info.fw & 0xffff;
6981 	if (bt_fw_ver == 0 ||
6982 	    (bt_fw_ver == bt_rom_code_id && bt0->run_patch_code))
6983 		bt_ver_unknown = true;
6984 
6985 	bitmap = rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_BT_VER_INFO);
6986 	if (bt0->enable.now && bt_ver_unknown)
6987 		rpt_map |= bitmap;
6988 	else
6989 		rpt_map &= ~bitmap;
6990 
6991 	bitmap = rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_BT_AFH_MAP) |
6992 		 rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_BT_AFH_MAP_LE) |
6993 		 rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_BT_TX_PWR_LVL);
6994 	if (bt0->link_info.link_cnt.now ||
6995 	    bt0->link_info_56g.link_cnt.now ||
6996 	    bt1->link_info.link_cnt.now ||
6997 	    bt1->link_info_56g.link_cnt.now)
6998 		rpt_map |= bitmap;
6999 	else
7000 		rpt_map &= ~bitmap;
7001 
7002 	bitmap = rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_BT_DEVICE_INFO);
7003 	if ((bt0->link_info.a2dp_desc.exist &&
7004 	     bt0->link_info.a2dp_desc.play_latency) ||
7005 	    (bt1->link_info.a2dp_desc.exist &&
7006 	     bt1->link_info.a2dp_desc.play_latency))
7007 		rpt_map |= bitmap;
7008 	else
7009 		rpt_map &= ~bitmap;
7010 
7011 	rtw89_btc_fw_en_rpt(rtwdev, false, rpt_map);
7012 }
7013 
7014 static void _set_trx_nss(struct rtw89_dev *rtwdev)
7015 {
7016 	struct rtw89_btc *btc = &rtwdev->btc;
7017 	struct rtw89_btc_dm *dm = &btc->dm;
7018 	struct rtw89_btc_bind_bt_status *btdd = &dm->tdd_bind.bt_smap;
7019 	struct rtw89_btc_bind_bt_status *bfdd = &dm->fdd_bind.bt_smap;
7020 	struct rtw89_btc_wl_trx_nss_para *trx_nss = &dm->wl_trx_nss;
7021 	struct rtw89_btc_module *module = &btc->mdinfo;
7022 	struct rtw89_btc_cx *cx = &btc->cx;
7023 	struct rtw89_btc_wl_info *wl = &cx->wl;
7024 	bool bt0_cis = cx->bt0.link_info.leaudio_desc.cis_exist;
7025 	bool bt1_cis = cx->bt1.link_info.leaudio_desc.cis_exist;
7026 	u8 tx_ss, rx_ss, tx_path, rx_path, limit_path;
7027 	u8 tx_limit = 0, rx_limit = 0;
7028 
7029 	/* tx/rx_limit: 1 = 1ss, 0 = HW default */
7030 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
7031 		    "[BTC], %s(): wl_rinfo->link_mode=%d, dm->wl_trx_nss_en=%d\n",
7032 		    __func__, wl->role_info.link_mode[RTW89_MAC_0], dm->wl_trx_nss_en);
7033 
7034 	/*
7035 	 * Skip 1SS MIMO-PS if:
7036 	 * - manual mode or DBCC enabled
7037 	 * - !wl_trx_nss_en: no MIMO-PS capability. The RFE configs that share
7038 	 *   a WL path with BT are selected in ops->set_rfe() (e.g. 8922D only
7039 	 *   sets it for ant.num=2), so this flag is the single gate here, no
7040 	 *   extra ant.num/bt1_sw_type check.
7041 	 * - non-LNV vendor and no DUAL_BT. Dual-BT chips run MIMO-PS for every
7042 	 *   vendor, single-BT chips only for LNV (LNV: PCIE-12223)
7043 	 */
7044 	if (btc->manual_ctrl || wl->role_info.dbcc_en || !dm->wl_trx_nss_en ||
7045 	    (dm->vid != RTW89_CUSTID_LENOVO &&
7046 	     !(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT)))
7047 		return;
7048 
7049 	/*
7050 	 * Disable 1SS limit when:
7051 	 * - No WiFi link (WL idle state)
7052 	 * - Out-of-band scenario (no BT coex needed)
7053 	 */
7054 	if (wl->role_info.link_mode[RTW89_MAC_0] == BTC_WLINK_NOLINK ||
7055 	    wl->role_info.link_mode[RTW89_MAC_1] == BTC_WLINK_NOLINK ||
7056 	    dm->out_of_band) {
7057 		tx_limit = 0;
7058 		rx_limit = 0;
7059 	} else if (bt0_cis || bt1_cis || btdd->cis_exist || bfdd->cis_exist) {
7060 		/*
7061 		 * Enable 2T1R when BT CIS profile exists (low latency audio).
7062 		 * tx_limit=1 (1T1R full isolation) reserved for future use
7063 		 * when WL needs to fully isolate Tx from BT on shared antenna.
7064 		 */
7065 		tx_limit = 0;
7066 		rx_limit = 1;
7067 	}
7068 
7069 	/*
7070 	 * BT1 at S0 has CIS -> WL must use S1 (path B)
7071 	 * BT0 at S1 has CIS -> WL must use S0 (path A)
7072 	 */
7073 	limit_path = bt1_cis ? RF_PATH_B : RF_PATH_A;
7074 
7075 	/*
7076 	 * Re-arm the exit-LPS one-shot once the event is over. lps_exiting is
7077 	 * held for a while by the LPS-exit timer, so it must not be used as
7078 	 * the force-exec condition directly.
7079 	 */
7080 	if (!wl->status.map.lps_exiting)
7081 		dm->trx_nss_lps_done = 0;
7082 
7083 	if (trx_nss->rx_limit == rx_limit && trx_nss->tx_limit == tx_limit &&
7084 	    (!rx_limit || trx_nss->rx_path == limit_path)) {
7085 		/*
7086 		 * WL just exited LPS: LPS may have cleared the BB/RF 1SS
7087 		 * setup, so re-issue cfg_1ss/cfg_trx_path/set_rfe once per
7088 		 * exit-LPS event. They are heavy (set_rfe() re-reads efuse and
7089 		 * does several RF I/O), so a one-shot flag instead of lps_exiting.
7090 		 */
7091 		if (wl->status.map.lps_exiting && !dm->trx_nss_lps_done)
7092 			goto force_exec;
7093 
7094 		return;
7095 	}
7096 
7097 force_exec:
7098 	/* one-shot consumed, no re-exec until the next exit-LPS event */
7099 	dm->trx_nss_lps_done = wl->status.map.lps_exiting;
7100 
7101 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
7102 		    "[BTC], %s(): stream_cnt=0x%02x, path_pos=0x%02x\n",
7103 		    __func__, module->ant.stream_cnt, module->ant.path_pos);
7104 
7105 	/*
7106 	 * Reduce TX to 1SS on the isolated path to avoid BT interference,
7107 	 * else restore TX to HW default stream count and path.
7108 	 */
7109 	if (tx_limit) {
7110 		tx_ss = 1;
7111 		tx_path = limit_path;
7112 	} else {
7113 		tx_ss = FIELD_GET(BTC_ANT_TX_MASK, module->ant.stream_cnt);
7114 		tx_path = FIELD_GET(BTC_ANT_TX_MASK, module->ant.path_pos);
7115 	}
7116 
7117 	/*
7118 	 * Reduce RX to 1SS on the isolated path to protect WL Rx stream,
7119 	 * else restore RX to HW default stream count and path.
7120 	 */
7121 	if (rx_limit) {
7122 		rx_ss = 1;
7123 		rx_path = limit_path;
7124 	} else {
7125 		rx_ss = FIELD_GET(BTC_ANT_RX_MASK, module->ant.stream_cnt);
7126 		rx_path = FIELD_GET(BTC_ANT_RX_MASK, module->ant.path_pos);
7127 	}
7128 
7129 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
7130 		    "[BTC], %s(): tx_ss=%d, rx_ss=%d, tx_path=%d, rx_path=%d\n",
7131 		    __func__, tx_ss, rx_ss, tx_path, rx_path);
7132 
7133 	/*
7134 	 * TODO: no driver API to apply tx_limit/rx_limit/tx_ss/rx_ss/tx_path/
7135 	 * rx_path to the BB/RF 1SS MIMO-PS HW state yet. Stop here so
7136 	 * trx_nss/always_freerun/ant.type/set_rfe()/_update_sdm_map() below
7137 	 * never run from a decision that was never applied to HW.
7138 	 */
7139 }
7140 
7141 static void _action_common(struct rtw89_dev *rtwdev)
7142 {
7143 	struct rtw89_btc *btc = &rtwdev->btc;
7144 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
7145 	struct rtw89_btc_wl_role_info *rinfo = &wl->role_info;
7146 	struct rtw89_btc_dm *dm = &btc->dm;
7147 	u8 i;
7148 
7149 	_wl_req_mac(rtwdev, rinfo->pta_req_band);
7150 	_set_trx_nss(rtwdev);
7151 	_update_zb_coex_tbl(rtwdev);
7152 	_set_btg_ctrl(rtwdev);
7153 	_set_wl_preagc_ctrl(rtwdev);
7154 	_set_wl_tx_limit(rtwdev);
7155 	_set_phl_bt_slot_req(rtwdev);
7156 	_set_bt_afh_info(rtwdev);
7157 	_set_bt_rx_agc(rtwdev);
7158 	_set_rf_trx_para(rtwdev);
7159 	_set_bt_rx_scan_pri(rtwdev);
7160 	_set_fw_report_map(rtwdev);
7161 
7162 	if (dm->run_reason == BTC_RSN_NTFY_INIT ||
7163 	    dm->run_reason == BTC_RSN_NTFY_RADIO_STATE ||
7164 	    dm->run_reason == BTC_RSN_NTFY_POWEROFF)
7165 		_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
7166 
7167 	for (i = BTC_BT_1ST; i <= BTC_BT_2ND; i++)
7168 		_sned_h2c_w2bscbd(rtwdev, false, i);
7169 
7170 	if (btc->ver->fcxosi) {
7171 		if (memcmp(&dm->ost_info_last, &dm->ost_info,
7172 			   sizeof(dm->ost_info_last)) ||
7173 		    dm->run_reason == BTC_RSN_NTFY_INIT ||
7174 		    dm->run_reason == BTC_RSN_NTFY_RADIO_STATE) {
7175 			dm->ost_info_last = dm->ost_info;
7176 			_fw_set_drv_info(rtwdev, CXDRVINFO_OSI);
7177 		}
7178 	}
7179 	dm->tdma_instant_excute = 0;
7180 	dm->lps_ctrl_change = false;
7181 	wl->role_info.link_mode_chg = 0;
7182 	wl->pta_reg_mac_chg = false;
7183 	dm->pre_agc_chg = false;
7184 	wl->dbcc_chg = 0;
7185 }
7186 
7187 static void _action_by_bt(struct rtw89_dev *rtwdev)
7188 {
7189 	struct rtw89_btc *btc = &rtwdev->btc;
7190 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
7191 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
7192 	struct rtw89_btc_bt_leaudio_desc leaudio = bt_linfo->leaudio_desc;
7193 	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
7194 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
7195 	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
7196 	struct rtw89_btc_dm *dm = &btc->dm;
7197 	u8 profile_map = 0;
7198 
7199 	if (dm->freerun_chk) {
7200 		_action_freerun(rtwdev);
7201 		return;
7202 	}
7203 
7204 	if (bt_linfo->hfp_desc.exist)
7205 		profile_map |= BTC_BT_HFP;
7206 
7207 	if (bt_linfo->hid_desc.exist)
7208 		profile_map |= BTC_BT_HID;
7209 
7210 	if (bt_linfo->a2dp_desc.exist)
7211 		profile_map |= BTC_BT_A2DP;
7212 
7213 	if (bt_linfo->pan_desc.exist)
7214 		profile_map |= BTC_BT_PAN;
7215 
7216 	if (leaudio.bis_exist)
7217 		profile_map |= BTC_BT_BIS;
7218 
7219 	if (leaudio.cis_exist)
7220 		profile_map |= BTC_BT_CIS;
7221 
7222 	switch (profile_map) {
7223 	case BTC_BT_NOPROFILE:
7224 		if (pan.active)
7225 			_action_bt_pan(rtwdev);
7226 		else
7227 			_action_bt_idle(rtwdev);
7228 		break;
7229 	case BTC_BT_HFP:
7230 		_action_bt_hfp(rtwdev);
7231 		break;
7232 	case BTC_BT_HFP | BTC_BT_HID:
7233 	case BTC_BT_HID:
7234 		_action_bt_hid(rtwdev);
7235 		break;
7236 	case BTC_BT_A2DP:
7237 		if (a2dp.sink)
7238 			_action_bt_a2dpsink(rtwdev);
7239 		else if (bt_linfo->multi_link.now && !hid.pair_cnt)
7240 			_action_bt_a2dp_pan(rtwdev);
7241 		else
7242 			_action_bt_a2dp(rtwdev);
7243 		break;
7244 	case BTC_BT_PAN:
7245 		_action_bt_pan(rtwdev);
7246 		break;
7247 	case BTC_BT_BIS:
7248 		_action_bt_bis(rtwdev);
7249 		break;
7250 	case BTC_BT_CIS:
7251 	case BTC_BT_CIS | BTC_BT_HID:
7252 		_action_bt_cis(rtwdev);
7253 		break;
7254 	case BTC_BT_A2DP | BTC_BT_HFP:
7255 	case BTC_BT_A2DP | BTC_BT_HID:
7256 	case BTC_BT_A2DP | BTC_BT_HFP | BTC_BT_HID:
7257 		if (a2dp.sink)
7258 			_action_bt_a2dpsink(rtwdev);
7259 		else if (pan.active)
7260 			_action_bt_a2dp_pan_hid(rtwdev);
7261 		else
7262 			_action_bt_a2dp_hid(rtwdev);
7263 		break;
7264 	case BTC_BT_A2DP | BTC_BT_PAN:
7265 		if (a2dp.sink)
7266 			_action_bt_a2dpsink(rtwdev);
7267 		else
7268 			_action_bt_a2dp_pan(rtwdev);
7269 		break;
7270 	case BTC_BT_PAN | BTC_BT_HFP:
7271 	case BTC_BT_PAN | BTC_BT_HID:
7272 	case BTC_BT_PAN | BTC_BT_HFP | BTC_BT_HID:
7273 		_action_bt_pan_hid(rtwdev);
7274 		break;
7275 	case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HID:
7276 	case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HFP:
7277 	default:
7278 		if (a2dp.sink)
7279 			_action_bt_a2dpsink(rtwdev);
7280 		else
7281 			_action_bt_a2dp_pan_hid(rtwdev);
7282 		break;
7283 	}
7284 }
7285 
7286 static void _action_wl_2g_sta(struct rtw89_dev *rtwdev)
7287 {
7288 	_action_by_bt(rtwdev);
7289 }
7290 
7291 static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev)
7292 {
7293 	struct rtw89_btc *btc = &rtwdev->btc;
7294 	u16 policy_type = BTC_CXP_OFF_BT;
7295 
7296 	if (btc->ant_type == BTC_ANT_SHARED) {
7297 		if (btc->cx.wl.status.map._4way)
7298 			policy_type = BTC_CXP_OFFE_WL;
7299 		else if (btc->cx.wl.status.val & btc_scanning_map.val)
7300 			policy_type = BTC_CXP_OFFE_2GBWMIXB;
7301 		else if (btc->cx.bt0.link_info.status.map.connect == 0)
7302 			policy_type = BTC_CXP_OFFE_2GISOB;
7303 		else
7304 			policy_type = BTC_CXP_OFFE_2GBWISOB;
7305 	} else { /* dedicated-antenna */
7306 		policy_type = BTC_CXP_OFF_EQ0;
7307 	}
7308 
7309 	btc->dm.e2g_slot_limit = BTC_E2G_LIMIT_DEF;
7310 
7311 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G);
7312 	_set_policy(rtwdev, policy_type, BTC_ACT_WL_25G_MCC);
7313 }
7314 
7315 static void _action_wl_scan(struct rtw89_dev *rtwdev)
7316 {
7317 	struct rtw89_btc *btc = &rtwdev->btc;
7318 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
7319 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
7320 
7321 	if (btc->cx.state_map != BTC_WLINKING &&
7322 	    btc->ctrl.wl_ctrl_info.fw_scan) {
7323 		_action_wl_25g_mcc(rtwdev);
7324 		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], Scan offload!\n");
7325 	} else if (rtwdev->dbcc_en) {
7326 		if (wl_dinfo->real_band[RTW89_PHY_0] != RTW89_BAND_2G &&
7327 		    wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G)
7328 			_action_wl_5g(rtwdev);
7329 		else
7330 			_action_by_bt(rtwdev);
7331 	} else {
7332 		if (wl->scan_info.band[RTW89_PHY_0] != RTW89_BAND_2G)
7333 			_action_wl_5g(rtwdev);
7334 		else
7335 			_action_by_bt(rtwdev);
7336 	}
7337 }
7338 
7339 static void _action_wl_2g_mcc(struct rtw89_dev *rtwdev)
7340 {	struct rtw89_btc *btc = &rtwdev->btc;
7341 
7342 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
7343 
7344 	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
7345 		if (btc->cx.bt0.link_info.link_cnt.now == 0)
7346 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
7347 				    BTC_ACT_WL_2G_MCC);
7348 		else
7349 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF,
7350 				    BTC_ACT_WL_2G_MCC);
7351 	} else { /* dedicated-antenna */
7352 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_MCC);
7353 	}
7354 }
7355 
7356 static void _action_wl_2g_scc(struct rtw89_dev *rtwdev)
7357 {
7358 	struct rtw89_btc *btc = &rtwdev->btc;
7359 	struct rtw89_btc_dm *dm = &btc->dm;
7360 	u16 policy_type;
7361 
7362 	if (!dm->tdd_bind.bt_smap.connect)
7363 		policy_type = BTC_CXP_OFFE_2GISOB;
7364 	else
7365 		policy_type = BTC_CXP_OFFE_2GBWISOB;
7366 
7367 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_PTA);
7368 	_set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
7369 }
7370 
7371 static void _action_wl_2g_ap(struct rtw89_dev *rtwdev)
7372 {
7373 	struct rtw89_btc *btc = &rtwdev->btc;
7374 
7375 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
7376 
7377 	if (btc->ant_type == BTC_ANT_SHARED) {
7378 		if (btc->cx.bt0.link_info.link_cnt.now == 0)
7379 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
7380 				    BTC_ACT_WL_2G_AP);
7381 		else
7382 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_AP);
7383 	} else {/* dedicated-antenna */
7384 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_AP);
7385 	}
7386 }
7387 
7388 static void _action_wl_2g_go(struct rtw89_dev *rtwdev)
7389 {
7390 	struct rtw89_btc *btc = &rtwdev->btc;
7391 
7392 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
7393 
7394 	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
7395 		if (btc->cx.bt0.link_info.link_cnt.now == 0)
7396 			_set_policy(rtwdev,
7397 				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_GO);
7398 		else
7399 			_set_policy(rtwdev,
7400 				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_GO);
7401 	} else { /* dedicated-antenna */
7402 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GO);
7403 	}
7404 }
7405 
7406 static void _action_wl_2g_gc(struct rtw89_dev *rtwdev)
7407 {
7408 	struct rtw89_btc *btc = &rtwdev->btc;
7409 
7410 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
7411 
7412 	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
7413 		_action_by_bt(rtwdev);
7414 	} else {/* dedicated-antenna */
7415 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GC);
7416 	}
7417 }
7418 
7419 static void _action_wl_2g_nan(struct rtw89_dev *rtwdev)
7420 {
7421 	struct rtw89_btc *btc = &rtwdev->btc;
7422 
7423 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
7424 
7425 	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
7426 		if (btc->cx.bt0.link_info.link_cnt.now == 0)
7427 			_set_policy(rtwdev,
7428 				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_NAN);
7429 		else
7430 			_set_policy(rtwdev,
7431 				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_NAN);
7432 	} else { /* dedicated-antenna */
7433 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_NAN);
7434 	}
7435 }
7436 
7437 static u8 _sned_h2c_w2bscbd(struct rtw89_dev *rtwdev, bool force_exec, u8 bid)
7438 {
7439 	struct rtw89_btc *btc = &rtwdev->btc;
7440 	struct rtw89_btc_cx *cx = &btc->cx;
7441 	struct rtw89_btc_wl_info *wl = &cx->wl;
7442 	u8 cnt_idx = BTC_WCNT_SCBDUPDATE;
7443 	u8 h2c_func = SET_IOFLD_SCBD;
7444 	u8 buf[4];
7445 
7446 	if (bid == BTC_BT_2ND) {
7447 		if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
7448 			return 0;
7449 
7450 		h2c_func |= BT_H2C_FUNC_BT2ND;
7451 		cnt_idx = BTC_WCNT_SCBDUPDATE2;
7452 	}
7453 
7454 	if (wl->scbd_chg[bid] || force_exec) {
7455 		/* Add delay to avoid BT FW loss information */
7456 
7457 		btc_dw2b(buf, 0, (wl->scbd[bid] | BIT(31))); /* trig */
7458 		if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO) {
7459 			if (!_send_fw_cmd(rtwdev, BTFC_SET,
7460 					  h2c_func, buf, sizeof(buf)))
7461 				return 0;
7462 		} else {
7463 			rtw89_mac_cfg_sb(rtwdev, wl->scbd[bid]);
7464 		}
7465 		wl->scbd_chg[bid] = 0;
7466 		wl->wcnt[cnt_idx]++;
7467 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
7468 			    "[BTC], %s() write BT%d scbd:0x%08x\n",
7469 			    __func__, bid, wl->scbd[bid]);
7470 	}
7471 	return 1;
7472 }
7473 
7474 static void _write_scbd(struct rtw89_dev *rtwdev, u8 bid, u32 val, bool state)
7475 {
7476 	const struct rtw89_chip_info *chip = rtwdev->chip;
7477 	struct rtw89_btc *btc = &rtwdev->btc;
7478 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
7479 	struct rtw89_btc_dm *dm = &btc->dm;
7480 	u8 force_exec, id, id_start, id_stop;
7481 	u32 scbd = 0;
7482 
7483 	if (!chip->scbd)
7484 		return;
7485 
7486 	if (bid == BTC_ALL_BT) {
7487 		id_start = BTC_BT_1ST;
7488 		id_stop = BTC_BT_2ND;
7489 	} else {
7490 		id_start = bid;
7491 		id_stop = bid;
7492 	}
7493 
7494 	for (id = id_start; id <= id_stop; id++) {
7495 		force_exec = false;
7496 		if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) &&
7497 		    id == BTC_BT_2ND)
7498 			continue;
7499 
7500 		if (state)
7501 			scbd = wl->scbd[id] | val;
7502 		else
7503 			scbd = wl->scbd[id] & (~val);
7504 
7505 		if (val & BTC_WSCB_CTCODE ||
7506 		    val & BTC_WSCB_RXGAIN ||
7507 		    val & BTC_WSCB_RXGAIN_56G) { /* instant exec */
7508 			force_exec = true;
7509 			wl->scbd[id] = scbd;
7510 			dm->scbd_write_instant = 1;
7511 			if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO)
7512 				_sned_h2c_w2bscbd(rtwdev, force_exec, id);
7513 			else
7514 				rtw89_mac_cfg_sb(rtwdev, wl->scbd[id]);
7515 			dm->scbd_write_instant = 0;
7516 		} else if ((val & BTC_WSCB_ACTIVE ||
7517 			   val & BTC_WSCB_ON ||
7518 			   val & BTC_WSCB_WLRFK) ||
7519 			   scbd != wl->scbd[id]) {
7520 			/*
7521 			 * Just update wl->scbd[] and set wl->scbd_chg[],
7522 			 * moved "Write scoreboard I/O" to  _action_common()
7523 			 * _write_scbd will be executed if run_coex()
7524 			 */
7525 			wl->scbd[id] = scbd;
7526 			wl->scbd_chg[id] = 1;
7527 		}
7528 	}
7529 }
7530 
7531 static u8
7532 _update_rssi_state(struct rtw89_dev *rtwdev, u8 pre_state, u8 rssi, u8 thresh)
7533 {
7534 	const struct rtw89_chip_info *chip = rtwdev->chip;
7535 	u8 next_state, tol = chip->rssi_tol;
7536 
7537 	if (pre_state == BTC_RSSI_ST_LOW ||
7538 	    pre_state == BTC_RSSI_ST_STAY_LOW) {
7539 		if (rssi >= (thresh + tol))
7540 			next_state = BTC_RSSI_ST_HIGH;
7541 		else
7542 			next_state = BTC_RSSI_ST_STAY_LOW;
7543 	} else {
7544 		if (rssi < thresh)
7545 			next_state = BTC_RSSI_ST_LOW;
7546 		else
7547 			next_state = BTC_RSSI_ST_STAY_HIGH;
7548 	}
7549 
7550 	return next_state;
7551 }
7552 
7553 static
7554 void _update_dbcc_band(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
7555 {
7556 	struct rtw89_btc *btc = &rtwdev->btc;
7557 
7558 	btc->cx.wl.dbcc_info.real_band[phy_idx] =
7559 		btc->cx.wl.scan_info.phy_map & BIT(phy_idx) ?
7560 		btc->cx.wl.dbcc_info.scan_band[phy_idx] :
7561 		btc->cx.wl.dbcc_info.op_band[phy_idx];
7562 }
7563 
7564 #define BTC_CHK_HANG_MAX 3
7565 #define BTC_SCB_INV_VALUE GENMASK(31, 0)
7566 
7567 static u8 _get_role_link_mode(u8 role)
7568 {
7569 	switch (role) {
7570 	case RTW89_WIFI_ROLE_STATION:
7571 	default:
7572 		return BTC_WLINK_STA;
7573 	case RTW89_WIFI_ROLE_P2P_GO:
7574 		return BTC_WLINK_GO;
7575 	case RTW89_WIFI_ROLE_P2P_CLIENT:
7576 		return BTC_WLINK_GC;
7577 	case RTW89_WIFI_ROLE_AP:
7578 		return BTC_WLINK_AP;
7579 	}
7580 }
7581 
7582 static bool _chk_role_ch_group(const struct rtw89_btc_chdef *r1,
7583 			       const struct rtw89_btc_chdef *r2)
7584 {
7585 	if (r1->chan != r2->chan) { /* primary ch is different */
7586 		return false;
7587 	} else if (r1->bw == RTW89_CHANNEL_WIDTH_40 &&
7588 		   r2->bw == RTW89_CHANNEL_WIDTH_40) {
7589 		if (r1->offset != r2->offset)
7590 			return false;
7591 	}
7592 	return true;
7593 }
7594 
7595 static u8 _chk_dbcc(struct rtw89_dev *rtwdev, struct rtw89_btc_chdef *ch,
7596 		    u8 *phy, u8 *role, u8 link_cnt)
7597 {
7598 	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
7599 	struct rtw89_btc_wl_role_info *rinfo = &wl->role_info;
7600 	bool is_2g_ch_exist = false, is_multi_role_in_2g_phy = false;
7601 	u8 j, k, dbcc_2g_cid = 0, dbcc_2g_cid2 = 0;
7602 
7603 	/* find out the 2G-PHY by connect-id ->ch  */
7604 	for (j = 0; j < link_cnt; j++) {
7605 		if (ch[j].center_ch <= 14) {
7606 			is_2g_ch_exist = true;
7607 			break;
7608 		}
7609 	}
7610 
7611 	/* If no any 2G-port exist, it's impossible because 5G-exclude */
7612 	if (!is_2g_ch_exist)
7613 		return BTC_WLINK_SB_MCC;
7614 
7615 	dbcc_2g_cid = j;
7616 	rinfo->dbcc_2g_phy = phy[dbcc_2g_cid];
7617 
7618 	if (rinfo->dbcc_2g_phy == RTW89_PHY_1)
7619 		rinfo->pta_req_band = RTW89_PHY_1;
7620 	else
7621 		rinfo->pta_req_band = RTW89_PHY_0;
7622 
7623 	/* connect_cnt <= 2 */
7624 	if (link_cnt < BTC_TDMA_WLROLE_MAX)
7625 		return _get_role_link_mode(role[dbcc_2g_cid]);
7626 
7627 	/* find the other-port in the 2G-PHY, ex: PHY-0:6G, PHY1: mcc/scc */
7628 	for (k = 0; k < link_cnt; k++) {
7629 		if (k == dbcc_2g_cid)
7630 			continue;
7631 
7632 		if (phy[k] == rinfo->dbcc_2g_phy) {
7633 			is_multi_role_in_2g_phy = true;
7634 			dbcc_2g_cid2 = k;
7635 			break;
7636 		}
7637 	}
7638 
7639 	/* Single-role in 2G-PHY */
7640 	if (!is_multi_role_in_2g_phy)
7641 		return _get_role_link_mode(role[dbcc_2g_cid]);
7642 
7643 	/* 2-role in 2G-PHY */
7644 	if (ch[dbcc_2g_cid2].center_ch > 14)
7645 		return BTC_WLINK_DB_MCC;
7646 	else if (_chk_role_ch_group(&ch[dbcc_2g_cid], &ch[dbcc_2g_cid2]))
7647 		return BTC_WLINK_SCC;
7648 	else
7649 		return BTC_WLINK_SB_MCC;
7650 }
7651 
7652 static void _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type)
7653 {
7654 	struct rtw89_btc *btc = &rtwdev->btc;
7655 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
7656 	struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info;
7657 	struct rtw89_btc_wl_role_info *r = &wl->role_info;
7658 	u8 p2p_exist = wl->role_info.p2p_exist[hw_band];
7659 
7660 	/* MLD: nLmR --> 2L1R: 2-Link by 1-RF,  2L2R: 2-link by 2-RF */
7661 	switch (type) {
7662 	case RTW89_MR_WTYPE_NONE: /* no-link */
7663 		r->link_mode[hw_band] = BTC_WLINK_NOLINK;
7664 		break;
7665 	case RTW89_MR_WTYPE_NONMLD:  /* Non_MLO 1-role 2+0/0+2 */
7666 	case RTW89_MR_WTYPE_MLD1L1R: /* MLO only-1 link 2+0/0+2 */
7667 		if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1AP) {
7668 			r->link_mode[hw_band] = BTC_WLINK_GO;
7669 		} else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1CLIENT &&
7670 			   p2p_exist) {
7671 			r->link_mode[hw_band] = BTC_WLINK_GC;
7672 		} else {
7673 			r->link_mode[hw_band] = BTC_WLINK_STA;
7674 		}
7675 		break;
7676 	case RTW89_MR_WTYPE_NONMLD_NONMLD: /* Non_MLO 2-role 2+0/0+2 */
7677 	case RTW89_MR_WTYPE_MLD1L1R_NONMLD: /* MLO only-1 link + P2P 2+0/0+2 */
7678 		if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ_5GHZ ||
7679 		    mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ_6GHZ) {
7680 			r->link_mode[hw_band] = BTC_WLINK_DB_MCC;
7681 		} else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ ||
7682 			   mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_5GHZ ||
7683 			   mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_6GHZ ||
7684 			   mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_5GHZ_6GHZ) {
7685 			r->link_mode[hw_band] = BTC_WLINK_SB_MCC;
7686 		} else {
7687 			r->link_mode[hw_band] = BTC_WLINK_SCC;
7688 		}
7689 		break;
7690 	case RTW89_MR_WTYPE_MLD2L1R: /* MLO_MLSR 2+0/0+2 */
7691 		if (p2p_exist) /* MLO_MLSR only support STA/GC */
7692 			r->link_mode[hw_band] = BTC_WLINK_GC;
7693 		else
7694 			r->link_mode[hw_band] = BTC_WLINK_STA;
7695 		break;
7696 	case RTW89_MR_WTYPE_MLD2L1R_NONMLD: /* MLO_MLSR + P2P 2+0/0+2 */
7697 	case RTW89_MR_WTYPE_MLD2L2R_NONMLD: /* MLO_MLMR + P2P 1+1/2+2*/
7698 		/* driver may doze 1-link (1+1) or 2+0->0+2->1+1
7699 		 * 2G+5G   -> TDMA slot switch by E2G/E5G
7700 		 * 5G only -> TDMA slot switch by E5G
7701 		 */
7702 		r->link_mode[hw_band] = BTC_WLINK_DB_MCC;
7703 		break;
7704 	case RTW89_MR_WTYPE_MLD2L2R: /* MLO_MLMR  1+1/2+2 */
7705 		/* MLMR only support STA now (2024) */
7706 		r->link_mode[hw_band] = BTC_WLINK_STA;
7707 		break;
7708 	}
7709 }
7710 
7711 static void _update_wl_mlo_info(struct rtw89_dev *rtwdev, u8 hw_band)
7712 {
7713 	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
7714 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
7715 	struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info;
7716 	struct rtw89_mr_chanctx_info qinfo;
7717 	struct rtw89_chanctx *ch;
7718 	u8 rf_band = RTW89_BAND_2G;
7719 	u8 i, type;
7720 
7721 	/* parse MLO info form PHL API for each HW-band */
7722 	for (i = RTW89_MAC_0; i <= RTW89_MAC_1; i++) {
7723 		memset(&qinfo, 0, sizeof(qinfo));
7724 
7725 		rtw89_query_mr_chanctx_info(rtwdev, i, &qinfo);
7726 
7727 		switch (qinfo.ctxtype) {
7728 		default:
7729 			mlo_info->hwb_rf_band[i] = 0;
7730 			break;
7731 		case RTW89_MR_CTX1_2GHZ:
7732 		case RTW89_MR_CTX2_2GHZ:
7733 			mlo_info->hwb_rf_band[i] = BIT(RTW89_BAND_2G);
7734 			break;
7735 		case RTW89_MR_CTX1_5GHZ:
7736 		case RTW89_MR_CTX2_5GHZ:
7737 			mlo_info->hwb_rf_band[i] = BIT(RTW89_BAND_5G);
7738 			break;
7739 		case RTW89_MR_CTX1_6GHZ:
7740 		case RTW89_MR_CTX2_6GHZ:
7741 			mlo_info->hwb_rf_band[i] = BIT(RTW89_BAND_6G);
7742 			break;
7743 		case RTW89_MR_CTX2_2GHZ_5GHZ:
7744 			mlo_info->hwb_rf_band[i] = BIT(RTW89_BAND_2G) |
7745 						    BIT(RTW89_BAND_5G);
7746 			break;
7747 		case RTW89_MR_CTX2_2GHZ_6GHZ:
7748 			mlo_info->hwb_rf_band[i] = BIT(RTW89_BAND_2G) |
7749 						    BIT(RTW89_BAND_6G);
7750 			break;
7751 		case RTW89_MR_CTX2_5GHZ_6GHZ:
7752 			mlo_info->hwb_rf_band[i] = BIT(RTW89_BAND_5G) |
7753 						    BIT(RTW89_BAND_6G);
7754 			break;
7755 		}
7756 		mlo_info->wmode[i] = qinfo.wmode;
7757 		mlo_info->ch_type[i] = qinfo.ctxtype;
7758 		mlo_info->wtype = qinfo.wtype;
7759 		wl->rf_band_map[i] = mlo_info->hwb_rf_band[i];
7760 		ch = &rtwdev->hal.chanctx[i];
7761 		wl->rf_ch_info[i].center_ch = ch->chan.channel;
7762 		wl->rf_ch_info[i].band = ch->chan.band_type;
7763 		wl->rf_ch_info[i].chan = ch->chan.channel;
7764 		wl->rf_ch_info[i].offset = ch->chan.pri_ch_idx;
7765 		wl->rf_ch_info[i].bw = ch->chan.band_width;
7766 	}
7767 
7768 	mlo_info->link_status = rtwdev->mlo_dbcc_mode;
7769 	type = mlo_info->wtype;
7770 
7771 	if (mlo_info->wtype == RTW89_MR_WTYPE_MLD1L1R ||
7772 	    mlo_info->wtype == RTW89_MR_WTYPE_MLD2L1R ||
7773 	    mlo_info->wtype == RTW89_MR_WTYPE_MLD2L2R ||
7774 	    mlo_info->wtype == RTW89_MR_WTYPE_MLD1L1R_NONMLD ||
7775 	    mlo_info->wtype == RTW89_MR_WTYPE_MLD2L1R_NONMLD ||
7776 	    mlo_info->wtype == RTW89_MR_WTYPE_MLD2L2R_NONMLD)
7777 		mlo_info->mlo_en = 1;
7778 	else
7779 		mlo_info->mlo_en = 0;
7780 
7781 	if (mlo_info->ch_type[RTW89_MAC_0] != RTW89_MR_CTX_NONE &&
7782 	    mlo_info->ch_type[RTW89_MAC_0] != RTW89_MR_CTX_UNKNOWN &&
7783 	    mlo_info->ch_type[RTW89_MAC_1] != RTW89_MR_CTX_NONE &&
7784 	    mlo_info->ch_type[RTW89_MAC_1] != RTW89_MR_CTX_UNKNOWN)
7785 		mlo_info->dual_hw_band_en = 1; /* two HW-hand link exist */
7786 	else
7787 		mlo_info->dual_hw_band_en = 0;
7788 
7789 	if (mlo_info->link_status == MLO_2_PLUS_0_2RF ||
7790 	    mlo_info->link_status == MLO_0_PLUS_2_2RF ||
7791 	    mlo_info->link_status == MLO_2_PLUS_2_2RF)
7792 		mlo_info->mlo_adie = 2;
7793 	else
7794 		mlo_info->mlo_adie = 1;
7795 
7796 	switch (mlo_info->link_status) {
7797 	default:
7798 	case MLO_2_PLUS_0_1RF: /* 2+0 */
7799 	case MLO_2_PLUS_0_2RF:
7800 		_update_wl_link_mode(rtwdev, RTW89_MAC_0, type);
7801 		wl_rinfo->link_mode[RTW89_MAC_1] = wl_rinfo->link_mode[RTW89_MAC_0];
7802 		wl_rinfo->pta_req_band = RTW89_MAC_0;
7803 		wl_rinfo->dbcc_2g_phy = RTW89_PHY_0;
7804 		wl_rinfo->dbcc_en = 0;
7805 
7806 		rf_band = wl->rf_band_map[RTW89_PHY_0];
7807 		mlo_info->path_rf_band[BTC_RF_S0] = rf_band;
7808 		mlo_info->path_rf_band[BTC_RF_S1] = rf_band;
7809 		mlo_info->rf_combination = BTC_MLO_RF_2_PLUS_0;
7810 		break;
7811 	case MLO_0_PLUS_2_1RF: /* 0+2 */
7812 	case MLO_0_PLUS_2_2RF:
7813 		_update_wl_link_mode(rtwdev, RTW89_MAC_1, type);
7814 		wl_rinfo->link_mode[RTW89_MAC_0] = wl_rinfo->link_mode[RTW89_MAC_1];
7815 		wl_rinfo->pta_req_band = RTW89_MAC_1;
7816 		wl_rinfo->dbcc_2g_phy = RTW89_PHY_1;
7817 		wl_rinfo->dbcc_en = 0;
7818 
7819 		rf_band = wl->rf_band_map[RTW89_PHY_1];
7820 		mlo_info->path_rf_band[BTC_RF_S0] = rf_band;
7821 		mlo_info->path_rf_band[BTC_RF_S1] = rf_band;
7822 		mlo_info->rf_combination = BTC_MLO_RF_0_PLUS_2;
7823 		break;
7824 	case MLO_1_PLUS_1_1RF: /* 1+1 */
7825 	case MLO_1_PLUS_1_2RF: /* 1+1 */
7826 	case MLO_2_PLUS_2_2RF: /* 2+2 */
7827 	case DBCC_LEGACY: /* DBCC 1+1 */
7828 		/* Check ch count from ch_type and modify type*/
7829 		if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX1_2GHZ ||
7830 		    mlo_info->ch_type[hw_band] == RTW89_MR_CTX1_5GHZ ||
7831 		    mlo_info->ch_type[hw_band] == RTW89_MR_CTX1_6GHZ)
7832 			type = RTW89_MR_WTYPE_NONMLD; /* only 1-role */
7833 		else
7834 			type = RTW89_MR_WTYPE_NONMLD_NONMLD;
7835 
7836 		rf_band = wl->rf_band_map[hw_band];
7837 		_update_wl_link_mode(rtwdev, hw_band, type);
7838 
7839 		if (hw_band == RTW89_MAC_0) {
7840 			mlo_info->path_rf_band[BTC_RF_S0] = rf_band;
7841 		} else {
7842 			mlo_info->path_rf_band[BTC_RF_S1] = rf_band;
7843 		}
7844 
7845 		/* set pta_req_band for 1-PTA architecture */
7846 		if (wl->rf_band_map[RTW89_MAC_0] & BIT(RTW89_BAND_2G)) {
7847 			wl_rinfo->pta_req_band = RTW89_MAC_0;
7848 			wl_rinfo->dbcc_2g_phy = RTW89_PHY_0;
7849 		} else if (wl->rf_band_map[RTW89_MAC_1] & BIT(RTW89_BAND_2G)) {
7850 			wl_rinfo->pta_req_band = RTW89_MAC_1;
7851 			wl_rinfo->dbcc_2g_phy = RTW89_PHY_1;
7852 		} else { /* Both HW-BAND are not on 2.4G*/
7853 			wl_rinfo->pta_req_band = RTW89_MAC_0;
7854 			wl_rinfo->dbcc_2g_phy = RTW89_PHY_0;
7855 		}
7856 
7857 		wl_rinfo->dbcc_en = 1; /* two HW-band both active */
7858 
7859 		if (mlo_info->link_status == MLO_2_PLUS_2_2RF)
7860 			mlo_info->rf_combination = BTC_MLO_RF_2_PLUS_2;
7861 		else
7862 			mlo_info->rf_combination = BTC_MLO_RF_1_PLUS_1;
7863 		break;
7864 	}
7865 
7866 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(), link_mode(HWB0=%s/HWB1=%s), pta_band=%d",
7867 		    __func__,
7868 		    id_to_linkmode(wl_rinfo->link_mode[RTW89_MAC_0]),
7869 		    id_to_linkmode(wl_rinfo->link_mode[RTW89_MAC_1]),
7870 		    wl_rinfo->pta_req_band);
7871 }
7872 
7873 static void _update_wl_non_mlo_info(struct rtw89_dev *rtwdev)
7874 {
7875 	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
7876 	struct rtw89_btc_wl_rlink *rlink = NULL;
7877 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
7878 	struct rtw89_btc_chdef cid_ch[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
7879 	u8 cid_role[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
7880 	u8 cid_phy[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
7881 	bool b2g = false, b5g = false, outloop = false;
7882 	u8 mode = BTC_WLINK_NOLINK;
7883 	u8 cnt_2g = 0, cnt_5g = 0;
7884 	u8 i, j, cnt = 0;
7885 
7886 	for (j = RTW89_PHY_0; j < RTW89_PHY_NUM; j++) {
7887 		wl->rf_band_map[j] = 0; /* j=link id, is the link use which band */
7888 		for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) {
7889 			rlink = &wl_rinfo->rlink[i][j];
7890 
7891 			if (!rlink->active || !rlink->connected)
7892 				continue;
7893 
7894 			if (cnt >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER) {
7895 				outloop = true;
7896 				break;
7897 			}
7898 
7899 			cid_ch[cnt] = wl->rlink_info[i][j].chdef;
7900 			cid_phy[cnt] = rlink->phy;
7901 			cid_role[cnt] = rlink->role;
7902 			cnt++;
7903 
7904 			if (rlink->rf_band != RTW89_BAND_2G) {
7905 				cnt_5g++;
7906 				b5g = true;
7907 			} else {
7908 				cnt_2g++;
7909 				b2g = true;
7910 			}
7911 			wl->rf_band_map[j] |= BIT(rlink->rf_band);
7912 		}
7913 		if (outloop)
7914 			break;
7915 	}
7916 
7917 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
7918 		    "[BTC], %s(): cnt_2g=%d, cnt_5g=%d\n", __func__, cnt_2g, cnt_5g);
7919 
7920 	wl_rinfo->pta_req_band = RTW89_PHY_0; /* no 0+2 for non-MLO */
7921 	wl_rinfo->dbcc_en = rtwdev->dbcc_en;
7922 
7923 	/* Be careful to change the following sequence!! */
7924 	if (cnt == 0) {
7925 		mode = BTC_WLINK_NOLINK;
7926 	} else if (wl_rinfo->dbcc_en) {
7927 		/* update pta_req_band to 2.4GHz HW-BAND for DBCC = 1*/
7928 		mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, cnt);
7929 	} else if (!b2g && b5g) {
7930 		mode = _get_role_link_mode(cid_role[0]);
7931 	} else if (b2g && b5g) {
7932 		mode = BTC_WLINK_DB_MCC;
7933 	} else if (cnt >= 2) {
7934 		if (_chk_role_ch_group(&cid_ch[0], &cid_ch[1]))
7935 			mode = BTC_WLINK_SCC;
7936 		else
7937 			mode = BTC_WLINK_SB_MCC;
7938 	} else {
7939 		mode = _get_role_link_mode(cid_role[0]);
7940 	}
7941 
7942 	wl_rinfo->link_mode[RTW89_MAC_0] = mode;
7943 	wl_rinfo->link_mode[RTW89_MAC_1] = mode;
7944 }
7945 
7946 static void _sync_wl_link_mode_v0(struct rtw89_dev *rtwdev)
7947 {
7948 	struct rtw89_btc_wl_role_info *r = &rtwdev->btc.cx.wl.role_info;
7949 	bool has_2g = false;
7950 	int i, j;
7951 
7952 	for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER && !has_2g; i++)
7953 		for (j = 0; j < RTW89_MAC_NUM && !has_2g; j++)
7954 			if (r->rlink[i][j].connected &&
7955 			    r->rlink[i][j].rf_band == RTW89_BAND_2G)
7956 				has_2g = true;
7957 
7958 	if (!has_2g && r->link_mode[RTW89_MAC_0] != BTC_WLINK_NOLINK) {
7959 		r->link_mode_v0 = BTC_WLINK_V0_5G;
7960 		return;
7961 	}
7962 
7963 	switch (r->link_mode[RTW89_MAC_0]) {
7964 	case BTC_WLINK_NOLINK:
7965 		r->link_mode_v0 = BTC_WLINK_V0_NOLINK;
7966 		break;
7967 	case BTC_WLINK_STA:
7968 		r->link_mode_v0 = BTC_WLINK_V0_2G_STA;
7969 		break;
7970 	case BTC_WLINK_AP:
7971 		r->link_mode_v0 = BTC_WLINK_V0_2G_AP;
7972 		break;
7973 	case BTC_WLINK_GO:
7974 		r->link_mode_v0 = BTC_WLINK_V0_2G_GO;
7975 		break;
7976 	case BTC_WLINK_GC:
7977 		r->link_mode_v0 = BTC_WLINK_V0_2G_GC;
7978 		break;
7979 	case BTC_WLINK_SCC:
7980 		r->link_mode_v0 = BTC_WLINK_V0_2G_SCC;
7981 		break;
7982 	case BTC_WLINK_SB_MCC:
7983 		r->link_mode_v0 = BTC_WLINK_V0_2G_MCC;
7984 		break;
7985 	case BTC_WLINK_DB_MCC:
7986 		r->link_mode_v0 = BTC_WLINK_V0_25G_MCC;
7987 		break;
7988 	default:
7989 		r->link_mode_v0 = BTC_WLINK_V0_OTHER;
7990 		break;
7991 	}
7992 }
7993 
7994 static void _modify_role_link_mode(struct rtw89_dev *rtwdev, u8 hw_band)
7995 {
7996 	struct rtw89_btc *btc = &rtwdev->btc;
7997 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
7998 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
7999 	u8 go_cleint_exist = wl->go_client_exist[hw_band];
8000 	u8 *link_mode = &wl_rinfo->link_mode[hw_band];
8001 	u32 role_map = wl_rinfo->role_map[hw_band];
8002 	u8 noa_exist = wl->noa_exist[hw_band];
8003 	u32 mrole = BTC_WLMROLE_NONE;
8004 
8005 	/* if no client_joined, don't care P2P-GO/AP role */
8006 	if (((role_map & BIT(RTW89_WIFI_ROLE_P2P_GO)) ||
8007 	      (role_map & BIT(RTW89_WIFI_ROLE_AP))) && !go_cleint_exist) {
8008 		if (*link_mode == BTC_WLINK_SCC) {
8009 			*link_mode = BTC_WLINK_STA;
8010 		} else if (*link_mode == BTC_WLINK_GO ||
8011 			   *link_mode == BTC_WLINK_AP) {
8012 			*link_mode = BTC_WLINK_NOLINK;
8013 		}
8014 	}
8015 
8016 	/* Identify 2-Role type  */
8017 	if  (*link_mode == BTC_WLINK_SCC ||
8018 	     *link_mode == BTC_WLINK_SB_MCC ||
8019 	     *link_mode == BTC_WLINK_DB_MCC) {
8020 		if ((role_map & BIT(RTW89_WIFI_ROLE_P2P_GO)) ||
8021 		     (role_map & BIT(RTW89_WIFI_ROLE_AP))) {
8022 			if (noa_exist)
8023 				mrole = BTC_WLMROLE_STA_GO_NOA;
8024 			else
8025 				mrole = BTC_WLMROLE_STA_GO;
8026 		} else if (role_map & BIT(RTW89_WIFI_ROLE_P2P_CLIENT)) {
8027 			if (noa_exist)
8028 				mrole = BTC_WLMROLE_STA_GC_NOA;
8029 			else
8030 				mrole = BTC_WLMROLE_STA_GC;
8031 		} else {
8032 			mrole = BTC_WLMROLE_STA_STA;
8033 		}
8034 
8035 		if (hw_band == RTW89_PHY_0) {
8036 			wl_rinfo->mrole_type &= GENMASK(31, 16); /* clear Low-Word */
8037 			wl_rinfo->mrole_type |= mrole;
8038 		} else {
8039 			wl_rinfo->mrole_type &= GENMASK(15, 0); /* clear high-Word */
8040 			wl_rinfo->mrole_type |= (mrole << 16);
8041 		}
8042 	} else {
8043 		wl_rinfo->mrole_type = BTC_WLMROLE_NONE;
8044 	}
8045 
8046 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
8047 		    "[BTC], %s(): link_mode=%s, mrole_type=%d\n", __func__,
8048 		    id_to_linkmode(*link_mode), wl_rinfo->mrole_type);
8049 }
8050 
8051 static void _update_wl_info(struct rtw89_dev *rtwdev, struct rtw89_btc_wl_link_info *wl_linfo)
8052 {
8053 	struct rtw89_btc *btc = &rtwdev->btc;
8054 	struct rtw89_btc_dm *dm = &btc->dm;
8055 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
8056 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
8057 	struct rtw89_btc_wl_rlink *rlink = NULL;
8058 	u8 dbcc_en_ori, is_5g_hi_ch = 0, bg_mode = 0, p2p_exist = 0;
8059 	u8 go_client_exist = 0, noa_exist = 0;
8060 	u8 rlink_id = wl_linfo->phy;
8061 	u8 role_id = wl_linfo->pid;
8062 	u8 i, link_mode_ori;
8063 	u32 role_map = 0;
8064 
8065 	if (role_id >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER || rlink_id >= RTW89_MAC_NUM)
8066 		return;
8067 
8068 	/*
8069 	 * Extract wl->link_info[role_id][rlink_id] to wl->role_info
8070 	 * role_id: role index
8071 	 * rlink_id: rlink index (= HW-band index)
8072 	 * pid: port_index
8073 	 */
8074 	rlink = &wl_rinfo->rlink[role_id][rlink_id];
8075 
8076 	rlink->role = wl_linfo->role;
8077 	rlink->active = wl_linfo->active; /* Doze or not */
8078 	rlink->pid = wl_linfo->pid;
8079 	rlink->mac_id = wl_linfo->mac_id;
8080 	rlink->phy = wl_linfo->phy;
8081 	rlink->rf_band = wl_linfo->chdef.band;
8082 	rlink->ch = wl_linfo->chdef.center_ch;
8083 	rlink->bw = wl_linfo->chdef.bw;
8084 	rlink->noa = wl_linfo->noa;
8085 	rlink->noa_dur = wl_linfo->noa_duration / 1000;
8086 	rlink->client_cnt = wl_linfo->client_cnt;
8087 	rlink->mode = wl_linfo->mode;
8088 
8089 	/* check if rlink connect? */
8090 	switch (wl_linfo->connected) {
8091 	case MLME_NO_LINK:
8092 		rlink->connected = 0;
8093 		break;
8094 	case MLME_LINKED:
8095 		rlink->connected = 1;
8096 
8097 		/* reset special-AP flag if station mode linked */
8098 		dm->leak_ap = 0;
8099 		break;
8100 	default:
8101 		return;
8102 	}
8103 
8104 	/* update by HW-Band */
8105 	for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) { /* i = role_id */
8106 		rlink = &wl_rinfo->rlink[i][rlink_id];
8107 
8108 		if (!rlink->active || !rlink->connected)
8109 			continue;
8110 
8111 		role_map |= BIT(rlink->role);
8112 
8113 		/* Identify if P2P-Go (GO/GC/AP) exist at 2GHz band */
8114 		if (((rlink->role == RTW89_WIFI_ROLE_P2P_GO ||
8115 		      rlink->role == RTW89_WIFI_ROLE_AP) &&
8116 		     rlink->client_cnt > 1)) {
8117 			p2p_exist = 1;
8118 			go_client_exist = 1;
8119 		}
8120 
8121 		if (rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)
8122 			p2p_exist = 1;
8123 
8124 		/* only one noa-role exist */
8125 		if (rlink->noa && rlink->noa_dur > 0)
8126 			noa_exist = 1;
8127 
8128 		/* for WL 5G-Rx interfered with BT issue */
8129 		if (rlink->rf_band == RTW89_BAND_5G && rlink->ch >= 100)
8130 			is_5g_hi_ch = 1;
8131 
8132 		if ((rlink->mode & BIT(BTC_WL_MODE_11B)) ||
8133 		    (rlink->mode & BIT(BTC_WL_MODE_11G)))
8134 			bg_mode = 1;
8135 	}
8136 
8137 	link_mode_ori = wl_rinfo->link_mode[rlink_id];
8138 	wl->is_5g_hi_ch[rlink_id] = is_5g_hi_ch;
8139 	wl->bg_mode[rlink_id] = bg_mode;
8140 	wl->go_client_exist[rlink_id] = go_client_exist;
8141 	wl->noa_exist[rlink_id] = noa_exist;
8142 	wl_rinfo->p2p_exist[rlink_id] = p2p_exist;
8143 	wl_rinfo->role_map[rlink_id] = role_map;
8144 
8145 	dbcc_en_ori = wl_rinfo->dbcc_en;
8146 
8147 	/* for MLO-supported, link-mode from driver directly */
8148 	if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) {
8149 		_update_wl_mlo_info(rtwdev, rlink_id);
8150 	} else { /* for non-MLO-supported, link-mode by BTC */
8151 		_update_wl_non_mlo_info(rtwdev);
8152 	}
8153 
8154 	_modify_role_link_mode(rtwdev, rlink_id);
8155 	_sync_wl_link_mode_v0(rtwdev);
8156 
8157 	if (wl_rinfo->link_mode[rlink_id] != link_mode_ori) {
8158 		wl_rinfo->link_mode_chg = 1;
8159 		wl->link_mode_chg = 1;
8160 	}
8161 
8162 	if (wl_rinfo->dbcc_en != dbcc_en_ori) {
8163 		wl->dbcc_chg = 1;
8164 		wl->role_info.dbcc_chg = 1;
8165 		wl->wcnt[BTC_WCNT_DBCC_CHG]++;
8166 	}
8167 }
8168 
8169 void rtw89_coex_act1_work(struct wiphy *wiphy, struct wiphy_work *work)
8170 {
8171 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
8172 						coex_act1_work.work);
8173 	struct rtw89_btc *btc = &rtwdev->btc;
8174 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
8175 	struct rtw89_btc_cx *cx = &btc->cx;
8176 	struct rtw89_btc_wl_info *wl = &cx->wl;
8177 
8178 	lockdep_assert_wiphy(wiphy);
8179 
8180 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
8181 	dm->cnt_notify[BTC_NCNT_TIMER]++;
8182 	if (wl->status.map.handshake ||
8183 	    wl->status.map._4way ||
8184 	    wl->status.map.dhcp) {
8185 		wl->status.map._4way = 0;
8186 		wl->status.map.dhcp = 0;
8187 		wl->status.map.handshake = 0;
8188 	}
8189 	_run_coex(rtwdev, BTC_RSN_ACT1_WORK);
8190 }
8191 
8192 void rtw89_coex_bt_devinfo_work(struct wiphy *wiphy, struct wiphy_work *work)
8193 {
8194 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
8195 						coex_bt_devinfo_work.work);
8196 	struct rtw89_btc *btc = &rtwdev->btc;
8197 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
8198 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
8199 
8200 	lockdep_assert_wiphy(wiphy);
8201 
8202 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
8203 	dm->cnt_notify[BTC_NCNT_TIMER]++;
8204 	a2dp->play_latency = 0;
8205 	_run_coex(rtwdev, BTC_RSN_BT_DEVINFO_WORK);
8206 }
8207 
8208 void rtw89_coex_rfk_chk_work(struct wiphy *wiphy, struct wiphy_work *work)
8209 {
8210 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
8211 						coex_rfk_chk_work.work);
8212 	struct rtw89_btc *btc = &rtwdev->btc;
8213 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
8214 	struct rtw89_btc_cx *cx = &btc->cx;
8215 	struct rtw89_btc_wl_info *wl = &cx->wl;
8216 
8217 	lockdep_assert_wiphy(wiphy);
8218 
8219 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
8220 	dm->cnt_notify[BTC_NCNT_TIMER]++;
8221 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
8222 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
8223 			    "[BTC], %s(): RFK timeout\n", __func__);
8224 		wl->wcnt[BTC_WCNT_RFK_TIMEOUT]++;
8225 		dm->error.map.wl_rfk_timeout = true;
8226 		wl->rfk_info.state = BTC_WRFK_STOP;
8227 		_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLRFK, false);
8228 		_run_coex(rtwdev, BTC_RSN_RFK_CHK_WORK);
8229 	}
8230 }
8231 
8232 static void _update_bt_ctrl_lps(struct rtw89_dev *rtwdev)
8233 {
8234 	struct rtw89_btc *btc = &rtwdev->btc;
8235 	struct rtw89_btc_bt_info *bt0 = &btc->cx.bt0;
8236 	struct rtw89_btc_bt_info *bt1 = &btc->cx.bt1;
8237 	struct rtw89_btc_dm *dm = &btc->dm;
8238 	bool lps_ctrl = false;
8239 
8240 	if (dm->out_of_band || dm->freerun)
8241 		lps_ctrl = false;
8242 	else if (bt0->whql_test || bt1->whql_test)
8243 		lps_ctrl = true;
8244 	else if (bt0->link_info.a2dp_desc.exist ||
8245 		 bt0->link_info.hfp_desc.exist ||
8246 		 bt0->link_info.pan_desc.exist)
8247 		lps_ctrl = true;
8248 	else if (bt1->link_info.a2dp_desc.exist ||
8249 		 bt1->link_info.hfp_desc.exist ||
8250 		 bt1->link_info.pan_desc.exist)
8251 		lps_ctrl = true;
8252 
8253 	if (dm->lps_ctrl_scbd != lps_ctrl) {
8254 		dm->lps_ctrl_scbd = lps_ctrl;
8255 		dm->lps_ctrl_change = true;
8256 	} else {
8257 		dm->lps_ctrl_change = false;
8258 	}
8259 }
8260 
8261 static u32 _read_scbd(struct rtw89_dev *rtwdev, u8 id)
8262 {
8263 	const struct rtw89_chip_info *chip = rtwdev->chip;
8264 	u32 val;
8265 
8266 	if (!chip->scbd)
8267 		return 0;
8268 
8269 	val = rtw89_read32(rtwdev, chip->btc_sb.n[id].get);
8270 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
8271 		    "[BTC], read scbd bt%d: 0x%08x\n", id, val);
8272 	return val;
8273 }
8274 
8275 static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid, bool is_c2h)
8276 {
8277 	struct rtw89_btc_bt_link_info *bt_2g, *bt_56g;
8278 	struct rtw89_btc *btc = &rtwdev->btc;
8279 	struct rtw89_btc_cx *cx = &btc->cx;
8280 	struct rtw89_btc_dm *dm = &btc->dm;
8281 	struct rtw89_btc_bt_info *bt;
8282 	u32 val, any_bt_connect, any_bt_6g_connect = 0;
8283 	bool bt_link_change = false;
8284 	u8 id, id_start, id_stop;
8285 
8286 	if (!rtwdev->chip->scbd || bid > BTC_ALL_BT)
8287 		return;
8288 
8289 	if (bid == BTC_ALL_BT) {
8290 		id_start = BTC_BT_1ST;
8291 		id_stop = BTC_BT_2ND;
8292 	} else {
8293 		id_start = bid;
8294 		id_stop = bid;
8295 	}
8296 
8297 	dm->lps_ctrl_change = false;
8298 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s()\n", __func__);
8299 
8300 	for (id = id_start; id <= id_stop; id++) {
8301 		bt = (id == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
8302 		bt_2g = &bt->link_info;
8303 		bt_56g = &bt->link_info_56g;
8304 
8305 		if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) && id == BTC_BT_2ND)
8306 			break;
8307 
8308 		val = is_c2h ? bt->scbd_c2h : _read_scbd(rtwdev, id);
8309 
8310 		if (val == 0xffffffff) {
8311 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
8312 				    "[BTC], %s return by invalid scbd value\n",
8313 				    __func__);
8314 			return;
8315 		}
8316 
8317 		if (!(val & BTC_BSCB_ON))
8318 			bt->enable.now = 0;
8319 		else
8320 			bt->enable.now = 1;
8321 
8322 		if (bt->enable.now != bt->enable.last)
8323 			bt_link_change = true;
8324 
8325 		/* reset bt info if bt re-enable */
8326 		if (bt->enable.now && !bt->enable.last) {
8327 			if (id == BTC_BT_1ST)
8328 				_reset_btc_var(rtwdev, BTC_RESET_BTINFO);
8329 			else
8330 				_reset_btc_var(rtwdev, BTC_RESET_BTINFO2);
8331 
8332 			bt->bcnt[BTC_BCNT_REENABLE]++;
8333 			bt->enable.now = 1;
8334 			bt->rf_band_map = BIT(RTW89_BAND_2G);
8335 			bt->link_weight[BTC_BT_B2G] = 5; /* no-profile */
8336 		}
8337 		bt->enable.last = bt->enable.now;
8338 
8339 		/* if BT will disconnect and adopt protect plan */
8340 		if ((val & BTC_BSCB_BT_PROTECT) &&
8341 		    !(bt->scbd & BTC_BSCB_BT_PROTECT))
8342 			bt->bcnt[BTC_BCNT_PROTECT]++;
8343 
8344 		bt->mbx_avl = !!(val & BTC_BSCB_ACT);
8345 		if (bt->whql_test != !!(val & BTC_BSCB_WHQL))
8346 			bt_link_change = true;
8347 
8348 		bt->whql_test = !!(val & BTC_BSCB_WHQL);
8349 		bt->btg_type = (val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE);
8350 
8351 		bt_2g->a2dp_desc.exist = !!(val & BTC_BSCB_A2DP_ACT);
8352 		bt_2g->pan_desc.exist = !!(val & BTC_BSCB_PAN_ACT);
8353 		bt_2g->hfp_desc.exist = !!(val & BTC_BSCB_HFP_ACT);
8354 		bt_2g->hid_desc.exist = !!(val & BTC_BSCB_HID_ACT);
8355 
8356 		bt->lna_constrain = 4 + !!(val & BTC_BSCB_BT_LNAB0) +
8357 				    !!(val & BTC_BSCB_BT_LNAB1) * 2;
8358 
8359 		if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
8360 			if ((val & BTC_BSCB_BT_15DOT4_TRX) !=
8361 			    (bt->scbd & BTC_BSCB_BT_15DOT4_TRX))
8362 				_update_sdm_map(rtwdev);
8363 
8364 			if (val & BTC_BSCB_BT_15DOT4)
8365 				bt->func_type |= (BTC_BTF_THREAD | BTC_BTF_ZB);
8366 			else
8367 				bt->func_type &= ~(BTC_BTF_THREAD | BTC_BTF_ZB);
8368 		}
8369 
8370 		bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA);
8371 		any_bt_connect = !!(val & BTC_BSCB_BT_CONNECT);
8372 
8373 		/* if connect change */
8374 		if (bt_2g->status.map.connect != any_bt_connect ||
8375 		    bt_56g->status.map.connect != any_bt_6g_connect) {
8376 			bt_link_change = true;
8377 			bt_2g->status.map.connect = any_bt_connect;
8378 			bt_56g->status.map.connect = any_bt_6g_connect;
8379 		}
8380 
8381 		bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE);
8382 		bt->scbd = val;
8383 	}
8384 
8385 	_update_bt_ctrl_lps(rtwdev);
8386 
8387 	if (bt_link_change) {
8388 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
8389 			    "[BTC], %s: bt status change!!\n", __func__);
8390 		/* TODO: Need to notify driver to update EXT-CTRL-BT-SLOT */
8391 	}
8392 }
8393 
8394 static void _update_bt_link_cnt(struct rtw89_dev *rtwdev,
8395 				struct rtw89_btc_bt_info *bt, bool b56g)
8396 {
8397 	struct rtw89_btc_bt_link_info *b = b56g ? &bt->link_info_56g :
8398 						  &bt->link_info;
8399 	struct rtw89_btc_bt_leaudio_desc *leaudio = &b->leaudio_desc;
8400 	struct rtw89_btc_bt_a2dp_desc *a2dp = &b->a2dp_desc;
8401 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
8402 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
8403 	struct rtw89_btc_bt_pan_desc *pan = &b->pan_desc;
8404 	u8 bt_rf_band = b56g ? BTC_BT_B5G : BTC_BT_B2G;
8405 	u8 val;
8406 
8407 	b->link_cnt.last = b->link_cnt.now;
8408 	b->link_cnt.now = 0;
8409 	b->link_cnt.chg = 0;
8410 
8411 	b->link_cnt.now += hfp->exist;
8412 	b->link_cnt.now += hid->exist;
8413 	b->link_cnt.now += a2dp->exist;
8414 	b->link_cnt.now += pan->exist;
8415 	b->link_cnt.now += leaudio->bis_exist;
8416 	b->link_cnt.now += leaudio->cis_exist;
8417 
8418 	if (leaudio->bis_exist || a2dp->sink) {
8419 		val = 70;
8420 	} else if (a2dp->exist) {
8421 		val = 40;
8422 		if (a2dp->vendor_id == 0x4c)
8423 			val += 10;
8424 		if (hid->exist)
8425 			val += 10;
8426 	} else if (pan->exist || pan->active || a2dp->active ||
8427 		   b->status.map.inq_pag) {
8428 		val = 30;
8429 	} else if (b->link_cnt.now == 0) {
8430 		val = 5;
8431 	} else {
8432 		val = 9;
8433 	}
8434 	bt->link_weight[bt_rf_band] = val;
8435 
8436 	if (b->link_cnt.last != b->link_cnt.now)
8437 		b->link_cnt.chg = 1;
8438 }
8439 
8440 static void _update_bt_leaudio_info(struct rtw89_dev *rtwdev, u8 bid,
8441 				    void *buf, u32 len)
8442 {
8443 	const struct rtw89_chip_info *chip = rtwdev->chip;
8444 	struct rtw89_btc *btc = &rtwdev->btc;
8445 	struct rtw89_btc_cx *cx = &btc->cx;
8446 	struct rtw89_btc_bt_info *bt = (bid == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
8447 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
8448 	struct rtw89_btc_bt_leaudio_info *src = buf;
8449 	struct rtw89_btc_bt_leaudio_desc *leaudio;
8450 	bool bt_56g = false, cis_exist, bis_exist;
8451 	u8 bis_cnt, cis_cnt;
8452 
8453 	if ((src->len & BIT(7)) && bt->band_56G_support) {
8454 		b = &bt->link_info_56g;
8455 		bt_56g = true;
8456 	}
8457 
8458 	leaudio = &b->leaudio_desc;
8459 
8460 	if (!memcmp(b->leaudio_raw_info, src, BTC_BTINFO_MAX)) {
8461 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
8462 			    "[BTC], %s return by leaudio-info duplicate!\n",
8463 			    __func__);
8464 		bt->bcnt[BTC_BCNT_LEAUDIO_INFOSAME]++;
8465 		return;
8466 	}
8467 
8468 	memcpy(b->leaudio_raw_info, src, BTC_BTINFO_MAX);
8469 
8470 	bis_exist = u8_get_bits(src->bis_cis, RTW89_BTC_LEAU_INFO_L2_BIS_EX);
8471 	cis_exist = u8_get_bits(src->bis_cis, RTW89_BTC_LEAU_INFO_L2_CIS_EX);
8472 	bis_cnt = u8_get_bits(src->bis_cis, RTW89_BTC_LEAU_INFO_L2_BIS_CNT);
8473 	cis_cnt = u8_get_bits(src->bis_cis, RTW89_BTC_LEAU_INFO_L2_CIS_CNT);
8474 
8475 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
8476 		    "[BTC], %s: bis_exist:%d bis_cnt:%d cis_exist:%d cis_cnt:%d rssi:%d\n",
8477 		    __func__, bis_exist, bis_cnt, cis_exist, cis_cnt, src->rssi);
8478 
8479 	if (!bis_exist && !cis_exist)
8480 		memset(leaudio, 0, sizeof(*leaudio));
8481 
8482 	leaudio->bis_cnt = bis_cnt;
8483 	leaudio->bis_exist = bis_exist;
8484 	leaudio->cis_cnt = cis_cnt;
8485 	leaudio->cis_exist = cis_exist;
8486 
8487 	if (leaudio->bis_exist)
8488 		b->status.map.profile_map |= BTC_BT_BIS;
8489 	else
8490 		b->status.map.profile_map &= ~BTC_BT_BIS;
8491 
8492 	if (leaudio->cis_exist)
8493 		b->status.map.profile_map |= BTC_BT_CIS;
8494 	else
8495 		b->status.map.profile_map &= ~BTC_BT_CIS;
8496 
8497 	_update_bt_link_cnt(rtwdev, bt, bt_56g);
8498 
8499 	leaudio->rssi = chip->ops->btc_get_bt_rssi(rtwdev, src->rssi);
8500 
8501 	leaudio->bis_cnt_last = leaudio->bis_cnt;
8502 	leaudio->bis_exist_last = leaudio->bis_exist;
8503 	leaudio->cis_cnt_last = leaudio->cis_cnt;
8504 	leaudio->cis_exist_last = leaudio->cis_exist;
8505 }
8506 
8507 static void _update_bt_bistdma_info(struct rtw89_dev *rtwdev, u8 bid,
8508 				    void *buf, u32 len)
8509 {
8510 	struct rtw89_btc *btc = &rtwdev->btc;
8511 	struct rtw89_btc_cx *cx = &btc->cx;
8512 	struct rtw89_btc_dm *dm = &btc->dm;
8513 	struct rtw89_btc_bt_info *bt = (bid == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
8514 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
8515 	struct rtw89_btc_bt_bistdma_info_le *src = buf;
8516 	struct rtw89_btc_bt_leaudio_desc *leaudio;
8517 
8518 	if ((src->len & BIT(7)) && bt->band_56G_support)
8519 		b = &bt->link_info_56g;
8520 
8521 	leaudio = &b->leaudio_desc;
8522 
8523 	if (!memcmp(b->bistdma_raw_info, src, BTC_BTINFO_MAX)) {
8524 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
8525 			    "[BTC], %s return by bistdma-info duplicate!\n",
8526 			    __func__);
8527 		bt->bcnt[BTC_BCNT_LEAUDIO_INFOSAME]++;
8528 		return;
8529 	}
8530 
8531 	memcpy(b->bistdma_raw_info, src, BTC_BTINFO_MAX);
8532 
8533 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
8534 		    "[BTC], %s: bis_start_end:%d bis_trx:%d\n",
8535 		    __func__,
8536 		    u8_get_bits(src->bis, RTW89_BTC_BIS_INFO_L2_START_END),
8537 		    u8_get_bits(src->bis, RTW89_BTC_BIS_INFO_L2_TRX));
8538 
8539 	leaudio->bis_trx = u8_get_bits(src->bis, RTW89_BTC_BIS_INFO_L2_TRX);
8540 	leaudio->bis_start_end = u8_get_bits(src->bis,
8541 					     RTW89_BTC_BIS_INFO_L2_START_END);
8542 
8543 	leaudio->diff_t = (src->diff_t_hb * 256 + src->diff_t_lb) * 625 / 1000;
8544 
8545 	if (btc->ant_type == BTC_ANT_SHARED && leaudio->diff_t > 13)
8546 		dm->bis_tdma = true;
8547 	else
8548 		dm->bis_tdma = false;
8549 }
8550 
8551 #define BTC_BTINFO_PWR_LEN 5
8552 static void _update_bt_txpwr_info(struct rtw89_dev *rtwdev, u8 bid, u8 *buf,
8553 				  u32 len)
8554 {
8555 	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
8556 	struct rtw89_btc_bt_link_info *b;
8557 	struct rtw89_btc_bt_info *bt;
8558 
8559 	if (len != BTC_BTINFO_PWR_LEN)
8560 		return;
8561 
8562 	bt = bid == BTC_BT_1ST ? &cx->bt0 : &cx->bt1;
8563 
8564 	if ((buf[BTC_BTINFO_L1] & BIT(7)) && bt->band_56G_support)
8565 		b = &bt->link_info_56g;
8566 	else
8567 		b = &bt->link_info;
8568 
8569 	if (!memcmp(bt->txpwr_info, buf, sizeof(bt->txpwr_info))) {
8570 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
8571 			    "[BTC], %s return by info duplicate!\n", __func__);
8572 		return;
8573 	}
8574 
8575 	memcpy(bt->txpwr_info, buf, BTC_BTINFO_MAX);
8576 	memcpy(&b->bt_txpwr_desc, &buf[2], sizeof(b->bt_txpwr_desc));
8577 }
8578 
8579 static void _set_bind_info(struct rtw89_btc *btc, u8 type)
8580 {
8581 	struct rtw89_btc_cx *cx = &btc->cx;
8582 	struct rtw89_btc_dm *dm = &btc->dm;
8583 	struct rtw89_btc_wl_info *wl = &cx->wl;
8584 	struct rtw89_btc_bt_info *bt = &cx->bt0;
8585 	struct rtw89_btc_bt_link_info *b;
8586 	struct rtw89_btc_bind_info *bd;
8587 	u8 path_hwb[BTC_RF_NUM] = {RTW89_PHY_0, RTW89_PHY_1};
8588 	u8 link_weight[BTC_ALL_BT_EZL][BTC_BT_BMAX];
8589 	u8 map[BTC_RF_NUM][BTC_ALL_BT_EZL];
8590 	u8 b2g_score = 0, b5g_score = 0;
8591 	u8 i, j, rf_band_map, thres;
8592 	u8 weight[BTC_BT_BMAX] = {};
8593 
8594 	if (type == BTC_MECH_TDD) {
8595 		bd = &dm->tdd_bind;
8596 		memcpy(map, dm->tdd_map, sizeof(map));
8597 		thres = 30; /* BT profile score threshold for TDMA */
8598 	} else {
8599 		bd = &dm->fdd_bind;
8600 		memcpy(map, dm->fdd_map, sizeof(map));
8601 		thres = 5;
8602 	}
8603 
8604 	memset(bd, 0, sizeof(*bd));
8605 	/* compare BT 2GHz/5GHz profile by link-weighting */
8606 	for (i = 0; i < BTC_BT_BMAX; i++) {
8607 		if (!cx->bt0.enable.now)
8608 			cx->bt0.link_weight[i] = 0;
8609 		if (!cx->bt1.enable.now)
8610 			cx->bt1.link_weight[i] = 0;
8611 		link_weight[BTC_BT_1ST][i] = cx->bt0.link_weight[i];
8612 		link_weight[BTC_BT_2ND][i] = cx->bt1.link_weight[i];
8613 		link_weight[BTC_BT_EXT][i] = cx->bt_ext.link_weight[i];
8614 	}
8615 
8616 	/*
8617 	 * get 2GHz/5GHz link weight score by "band-overlap" map
8618 	 * link_weight from _update_bt_link_cnt(),
8619 	 * if link_weight >30 --> TDMA-required
8620 	 */
8621 	for (j = 0; j < BTC_ALL_BT_EZL; j++) {
8622 		rf_band_map = map[BTC_RF_S0][j] | map[BTC_RF_S1][j];
8623 		if (rf_band_map & BIT(RTW89_BAND_2G))
8624 			b2g_score += link_weight[j][BTC_BT_B2G];
8625 		if (rf_band_map & BIT(RTW89_BAND_5G))
8626 			b5g_score += link_weight[j][BTC_BT_B5G];
8627 	}
8628 
8629 	/*
8630 	 * Consider WL RFK band for coex (avoid missing RFK case)
8631 	 * If WL is doing RFK, check RFK band vs BT band overlap
8632 	 * Only add score when RFK band matches BT band
8633 	 */
8634 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
8635 		if (wl->rfk_info.band == RTW89_BAND_2G) {
8636 			/* RFK on 2.4GHz, check if any BT is also on 2.4GHz */
8637 			if ((cx->bt0.rf_band_map & BIT(RTW89_BAND_2G)) ||
8638 			    (cx->bt1.rf_band_map & BIT(RTW89_BAND_2G)))
8639 				b2g_score = thres;
8640 		} else if (wl->rfk_info.band == RTW89_BAND_5G ||
8641 			   wl->rfk_info.band == RTW89_BAND_6G) {
8642 			/* RFK on 5/6GHz, check if any BT is also on 5GHz */
8643 			if ((cx->bt0.rf_band_map & BIT(RTW89_BAND_5G)) ||
8644 			    (cx->bt1.rf_band_map & BIT(RTW89_BAND_5G)))
8645 				b5g_score = thres;
8646 		}
8647 	}
8648 
8649 	/* rf-band bound by comparing link weight */
8650 	if (b2g_score == 0 && b5g_score == 0) /* no-rf-band overlap */
8651 		bd->rf_band = 0;
8652 	else if (b5g_score > b2g_score)
8653 		bd->rf_band = BIT(BTC_BT_B5G);
8654 	else
8655 		bd->rf_band = BIT(BTC_BT_B2G);
8656 
8657 	/*
8658 	 * if MR_WTYPE_MLD2L1R_NONMLD, FW will change 2+0/0+2/1+1
8659 	 * Therefore, BTC_MLO_RF_xxx is not real-time state.
8660 	 * In this case, RF_S0->HWB0, RF_S1->HWB1
8661 	 * If link-mode change by _ntfy_generic(BTC_GNTFY_MRCX_INFO)
8662 	 * HW-Band is decided by wl->mlo_info.mrcx_act_hwb_map
8663 	 */
8664 	if (wl->mlo_info.wtype == RTW89_MR_WTYPE_MLD2L1R_NONMLD) {
8665 		if (wl->role_info.link_mode[RTW89_MAC_0] != BTC_WLINK_DB_MCC) { /* mode chg */
8666 			if (wl->mlo_info.mrcx_act_hwb_map == BIT(RTW89_MAC_1))
8667 				path_hwb[BTC_RF_S0] = RTW89_PHY_1; /* S0/1->HWB1 */
8668 			else
8669 				path_hwb[BTC_RF_S1] = RTW89_PHY_0; /* S0/1->HWB0 */
8670 		}
8671 	} else {
8672 		/*
8673 		 * Dual-RF_band(HWB)TDMA if BT-profile is TDMA-type at both
8674 		 * 2GHz and 5GHz.
8675 		 * ex: 1+1: HWB0 5GHz + BT0 5GHz (BIS, HDT)
8676 		 * && HWB1 2.4GHz + BT1 2.4GHz(PAN)
8677 		 * for TDD: the link score must > 30 (from _bt_link_cnt)
8678 		 * for FDD: the link score must > 5 (bt enable)
8679 		 */
8680 		if ((wl->mlo_info.rf_combination == BTC_MLO_RF_1_PLUS_1 ||
8681 		     wl->mlo_info.rf_combination == BTC_MLO_RF_2_PLUS_2) &&
8682 		     (b2g_score >= thres && b5g_score >= thres)) {
8683 			bd->rf_band = BIT(BTC_BT_B2G) | BIT(BTC_BT_B5G);
8684 		}
8685 
8686 		if (wl->mlo_info.rf_combination == BTC_MLO_RF_2_PLUS_0)
8687 			path_hwb[BTC_RF_S1] = RTW89_PHY_0; /* 2+0 RF-S0/1->HWB0 */
8688 		else if (wl->mlo_info.rf_combination == BTC_MLO_RF_0_PLUS_2)
8689 			path_hwb[BTC_RF_S0] = RTW89_PHY_1; /* 2+0 RF-S0/1->HWB1 */
8690 	}
8691 
8692 	/* Get HWB-sel and BT-sel by rf-band-binding */
8693 	for (i = 0; i < BTC_RF_NUM; i++) {
8694 		for (j = 0; j < BTC_ALL_BT_EZL; j++) {
8695 			if (!(map[i][j] & bd->rf_band)) /* no-overlap */
8696 				continue;
8697 
8698 			bd->wl_hwb_sel |= BIT(path_hwb[i]);
8699 			bd->bt_sel |= BIT(j);
8700 		}
8701 	}
8702 
8703 	if (wl->mlo_info.wtype == RTW89_MR_WTYPE_MLD2L2R &&
8704 	    (bd->wl_hwb_sel == (BIT(RTW89_MAC_1) | BIT(RTW89_MAC_0)))) {
8705 		if (wl->role_info.link_mode[RTW89_MAC_0] == BTC_WLINK_AP ||
8706 		    wl->role_info.link_mode[RTW89_MAC_1] == BTC_WLINK_AP)
8707 			bd->wl_link_mode = BTC_WLINK_DB_MCC;
8708 		else
8709 			bd->wl_link_mode = BTC_WLINK_STA;
8710 		bd->wl_bg_mode = wl->bg_mode[RTW89_MAC_0] | wl->bg_mode[RTW89_MAC_1];
8711 	} else if (bd->wl_hwb_sel == (BIT(RTW89_MAC_1))) {
8712 		bd->wl_link_mode = wl->role_info.link_mode[RTW89_MAC_1];
8713 		bd->wl_bg_mode = wl->bg_mode[RTW89_MAC_1];
8714 	} else {/* HW-BAND-0 or no-hw-band */
8715 		bd->wl_hwb_sel = BIT(RTW89_MAC_0);
8716 		bd->wl_link_mode = wl->role_info.link_mode[RTW89_MAC_0];
8717 		bd->wl_bg_mode = wl->bg_mode[RTW89_MAC_0];
8718 	}
8719 
8720 	/* update Bind-BT status map for BT0/BT1 */
8721 	for (i = BTC_BT_1ST; i < BTC_ALL_BT_EZL; i++) {
8722 		if (!(bd->bt_sel & BIT(i)))
8723 			continue;
8724 
8725 		for (j = BTC_BT_B2G; j <= BTC_BT_B5G; j++) {
8726 			if (!(bd->rf_band & BIT(j)))
8727 				continue;
8728 
8729 			if (i == BTC_BT_EXT) {
8730 				bd->bt_profile |= cx->bt_ext.profile_map[j];
8731 				weight[j] = cx->bt_ext.link_weight[j];
8732 				if (weight[j] > bd->bt_link_weight) /* max */
8733 					bd->bt_link_weight = weight[j];
8734 				continue;
8735 			} else if (i == BTC_BT_1ST) {
8736 				bt = &cx->bt0;
8737 			} else {
8738 				bt = &cx->bt1;
8739 			}
8740 
8741 			if (j == BTC_BT_B2G)
8742 				b = &bt->link_info;
8743 			else
8744 				b = &bt->link_info_56g;
8745 
8746 			bd->bt_profile |= b->status.map.profile_map;
8747 			bd->bt_smap.a2dp_active |= b->a2dp_desc.active;
8748 			bd->bt_smap.a2dp_sink |= b->a2dp_desc.sink;
8749 			bd->bt_smap.pan_active |= b->pan_desc.active;
8750 			bd->bt_smap.connect |= b->status.map.connect;
8751 			bd->bt_smap.hid_cnt += b->hid_desc.pair_cnt;
8752 			bd->bt_smap.hid_type |= b->hid_desc.type;
8753 			bd->bt_smap.cis_cnt += b->leaudio_desc.cis_cnt;
8754 			bd->bt_smap.link_cnt += b->link_cnt.now;
8755 			bd->bt_smap.inq_page |= b->status.map.inq_pag;
8756 			bd->bt_smap.page |= b->pag;
8757 
8758 			if (bt->link_weight[j] > bd->bt_link_weight) /* max */
8759 				bd->bt_link_weight = bt->link_weight[j];
8760 
8761 			if (b->slave_role)
8762 				bd->bt_smap.slave_role = b->slave_role;
8763 
8764 			if (b->a2dp_desc.vendor_id != 0)
8765 				bd->bt_smap.a2dp_vendor_id =
8766 							b->a2dp_desc.vendor_id;
8767 		}
8768 	}
8769 
8770 	if (bd->bt_profile & BTC_BT_HFP)
8771 		bd->bt_smap.hfp_exist = 1;
8772 	if (bd->bt_profile & BTC_BT_HID)
8773 		bd->bt_smap.hid_exist = 1;
8774 	if (bd->bt_profile & BTC_BT_A2DP)
8775 		bd->bt_smap.a2dp_exist = 1;
8776 	if (bd->bt_profile & BTC_BT_PAN)
8777 		bd->bt_smap.pan_exist = 1;
8778 	if (bd->bt_profile & BTC_BT_BIS)
8779 		bd->bt_smap.bis_exist = 1;
8780 	if (bd->bt_profile & BTC_BT_CIS)
8781 		bd->bt_smap.cis_exist = 1;
8782 	if (bd->bt_profile & BTC_BT_THREAD)
8783 		bd->bt_smap.thread_exist = 1;
8784 	if (bd->bt_profile & BTC_BT_ULL)
8785 		bd->bt_smap.ull_exist = 1;
8786 }
8787 
8788 /*
8789  * Get the only WL RF-path that still receives under 1SS MIMO-PS.
8790  *
8791  * Single source of truth for "is WL Rx confined to one RF-path, and which
8792  * one". Both _update_sdm_map() (xtk_xmap) and _set_coex_binding() (fit_map)
8793  * must agree, otherwise the two maps describe different WL Rx topologies.
8794  *
8795  * Conditions:
8796  * - rx_limit: the BB/RF was actually programmed to 1SS by _set_trx_nss()
8797  * - DL only: rx_limit shrinks the Rx stream, WL Tx still runs 2SS/2TX on both
8798  *   paths for UL, so every path stays BT-interactive there
8799  * - 2+0/0+2 only: both RF-path serve the same link on one HW-band, so there
8800  *   is an unused path. In 1+1/2+2 each RF-path serves its own link on its own
8801  *   HW-band and none of them can be dropped
8802  *
8803  * Return dm->wl_trx_nss.rx_path (RF_PATH_A/B, == BTC_RF_S0/S1) if 1SS
8804  * MIMO-PS is active, RF_PATH_AB if WL keeps both Rx paths.
8805  */
8806 static u8 _get_sdm_1ss_path(struct rtw89_dev *rtwdev)
8807 {
8808 	struct rtw89_btc_wl_trx_nss_para *trx_nss = &rtwdev->btc.dm.wl_trx_nss;
8809 	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
8810 
8811 	if (!trx_nss->rx_limit ||
8812 	    !(wl->status.map.traffic_dir & BIT(RTW89_TFC_DL)))
8813 		return RF_PATH_AB;
8814 
8815 	if (wl->mlo_info.rf_combination != BTC_MLO_RF_2_PLUS_0 &&
8816 	    wl->mlo_info.rf_combination != BTC_MLO_RF_0_PLUS_2)
8817 		return RF_PATH_AB;
8818 
8819 	/*
8820 	 * rx_path is what _set_trx_nss() passed to cfg_trx_path(), it must be
8821 	 * a single path to be used as an RF-path index below
8822 	 */
8823 	if (trx_nss->rx_path != RF_PATH_A && trx_nss->rx_path != RF_PATH_B)
8824 		return RF_PATH_AB;
8825 
8826 	return trx_nss->rx_path;
8827 }
8828 
8829 static void _update_sdm_map(struct rtw89_dev *rtwdev)
8830 {
8831 	struct rtw89_btc *btc = &rtwdev->btc;
8832 	struct rtw89_btc_module *module = &btc->mdinfo;
8833 	struct rtw89_btc_cx *cx = &btc->cx;
8834 	struct rtw89_btc_bt_info *bt0 = &cx->bt0;
8835 	struct rtw89_btc_bt_info *bt1 = &cx->bt1;
8836 	struct rtw89_btc_wl_info *wl = &cx->wl;
8837 	struct rtw89_btc_dm *dm = &btc->dm;
8838 	u8 map[BTC_RF_NUM][BTC_ALL_BT_EZL];
8839 	bool mlo_1_plus_1 = false;
8840 	u8 used_path;
8841 	u8 i, j;
8842 
8843 	/*
8844 	 * xtk_xmap(Cross-talk map)-> 1: interaction, 0: no-interaction
8845 	 * calculate WL/BT interference by SIR
8846 	 * ==>1:If WL_RSSI < (BT-Pin -SIR), it means BT-Tx interfer with WL-Rx
8847 	 * ==>BT-pin = BT-Tx-Power - Ant-isolation
8848 	 */
8849 	if (wl->mlo_info.wtype != RTW89_MR_WTYPE_MLD2L1R_NONMLD &&
8850 	    (wl->mlo_info.rf_combination == BTC_MLO_RF_1_PLUS_1 ||
8851 	     wl->mlo_info.rf_combination == BTC_MLO_RF_2_PLUS_2))
8852 		mlo_1_plus_1 = true;
8853 
8854 	/*
8855 	 * WL running 1SS MIMO-PS (CIS LE-audio): WL Rx is confined to a single
8856 	 * path. The used path co-Rx with its co-ant BT (=1) or follows RSSI vs.
8857 	 * the other BT; the unused path no longer co-Rx with any BT (=0).
8858 	 * RF_PATH_AB -> not 1SS, keep the original per-path logic.
8859 	 *
8860 	 * Record it: this function also runs at the _set_trx_nss() exit, after
8861 	 * rx_limit/rx_path changed, so dm->fit_used_path stays the up-to-date
8862 	 * 1SS state for the _action_common() consumers that run later in the
8863 	 * same coex cycle (_set_wl_preagc_ctrl, _set_bt_corx_table).
8864 	 */
8865 	used_path = _get_sdm_1ss_path(rtwdev);
8866 	dm->fit_used_path = used_path;
8867 
8868 	memset(map, 0, sizeof(map));
8869 	for (i = 0; i < BTC_RF_NUM; i++) {
8870 		if (module->ant.num == 1 && i == BTC_RF_S1)
8871 			break;
8872 
8873 		for (j = 0; j < BTC_ALL_BT_EZL; j++) {
8874 			if ((bt0->scbd_c2h & BTC_BSCB_BT_15DOT4_TRX) ||
8875 			    (bt1->scbd_c2h & BTC_BSCB_BT_15DOT4_TRX)) {
8876 				/* 15.4 TRX active: force BT0/BT1 to TDD */
8877 				if (j < BTC_ALL_BT)
8878 					dm->xtk_xmap[i][j] = 1;
8879 				else
8880 					continue; /* j == EXT: not force TDD */
8881 			} else if (used_path != RF_PATH_AB && j < BTC_ALL_BT) {
8882 				/* 1SS MIMO-PS: only the used WL path co-Rx */
8883 				if (i != used_path)
8884 					dm->xtk_xmap[i][j] = 0;
8885 				else if (dm->ant_xmap[i][j] == 1)
8886 					dm->xtk_xmap[i][j] = 1;
8887 				else
8888 					dm->xtk_xmap[i][j] =
8889 						BTC_RSSI_LOW(dm->sir_state[j]) ? 1 : 0;
8890 			} else if (dm->ant_xmap[i][j] == 1) {
8891 				/* if WL RF-pathx co-ant with BTx */
8892 				dm->xtk_xmap[i][j] = 1;
8893 			} else if (((j == BTC_BT_1ST &&
8894 				     module->bt0_sw_type != BTC_SWITCH_V1_NONE) ||
8895 				    (j == BTC_BT_2ND &&
8896 				     module->bt1_sw_type != BTC_SWITCH_V1_NONE)) &&
8897 				   !mlo_1_plus_1) {
8898 				/*
8899 				 * if WL RF-pathx not co-ant/path with BTx
8900 				 * but BTx co-ant/path with the other WL-path
8901 				 * and WL is 2+0/0+2
8902 				 * ex: WL-S0 + (WL-S1 & BT0-S1) ->
8903 				 * BT0-S1 vs. WL-S0 = 1
8904 				 */
8905 				dm->xtk_xmap[i][j] = 1;
8906 			} else if (BTC_RSSI_LOW(dm->sir_state[j])) {
8907 				/* if WL_RSSI below BT-Tx interference thres */
8908 				dm->xtk_xmap[i][j] = 1;
8909 			} else {
8910 				dm->xtk_xmap[i][j] = 0;
8911 			}
8912 
8913 			map[i][j] = dm->ant_xmap[i][j] | dm->xtk_xmap[i][j];
8914 		}
8915 	}
8916 
8917 	memcpy(dm->sit_xmap, map, sizeof(map));
8918 }
8919 
8920 static void _set_bttrx_en(struct rtw89_dev *rtwdev)
8921 {
8922 	struct rtw89_btc_wl_smap *wl_smap = &rtwdev->btc.cx.wl.status.map;
8923 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
8924 	u8 state = dm->ost_info.bt_enable_state;
8925 	u8 i, want, done;
8926 
8927 	/* only dual-BT chips drive the BT TX/RX enable from the driver */
8928 	if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
8929 		return;
8930 
8931 	/*
8932 	 * RF is not accessible, leave the shadow alone. Leaving this state is
8933 	 * a radio-state run, which drops the shadow and re-programs below.
8934 	 */
8935 	if (wl_smap->rf_off || wl_smap->lps == BTC_LPS_RF_OFF)
8936 		return;
8937 
8938 	/*
8939 	 * RF may have been re-initialized, drop the shadow and re-program.
8940 	 * Power-off is not listed, it is always followed by an init run
8941 	 * before the next RF access.
8942 	 */
8943 	if (dm->run_reason == BTC_RSN_NTFY_INIT ||
8944 	    dm->run_reason == BTC_RSN_NTFY_RADIO_STATE)
8945 		dm->bttrx_en_ack = 0;
8946 
8947 	for (i = BTC_BT_1ST; i <= BTC_BT_2ND; i++) {
8948 		want = !!(state & BIT(i));
8949 		done = !!(dm->bttrx_en_done & BIT(i));
8950 
8951 		if (dm->bttrx_en_ack & BIT(i) && want == done)
8952 			continue;
8953 
8954 		if (rtw89_phy_btc_bttrx_en(rtwdev, i, want)) {
8955 			/* leave the bit un-acked, the next run retries it */
8956 			dm->bttrx_en_ack &= ~BIT(i);
8957 
8958 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
8959 				    "[BTC], %s(): BT%d trx_en=%d write fail\n",
8960 				    __func__, i, want);
8961 			continue;
8962 		}
8963 
8964 		dm->bttrx_en_ack |= BIT(i);
8965 
8966 		if (want)
8967 			dm->bttrx_en_done |= BIT(i);
8968 		else
8969 			dm->bttrx_en_done &= ~BIT(i);
8970 	}
8971 }
8972 
8973 #define _bind_is_btonly 0x7
8974 static void _set_coex_binding(struct rtw89_dev *rtwdev)
8975 {
8976 	struct rtw89_btc *btc = &rtwdev->btc;
8977 	struct rtw89_btc_cx *cx = &btc->cx;
8978 	struct rtw89_btc_extsoc_info *bt2 =  &cx->bt_ext;
8979 	struct rtw89_btc_bt_info *bt0 = &cx->bt0;
8980 	struct rtw89_btc_bt_info *bt1 = &cx->bt1;
8981 	struct rtw89_btc_wl_info *wl = &cx->wl;
8982 	struct rtw89_btc_dm *dm = &btc->dm;
8983 	u8 path_hwb[BTC_RF_NUM] = {RTW89_PHY_0, RTW89_PHY_1};
8984 	u8 wl_rf_band[RTW89_BAND_NUM] = {};
8985 	u8 i, j, val = 0, fit, used_path;
8986 
8987 	/*
8988 	 * sit_xmap(Space-Interaction) = ant_xmap | xtk_xmap
8989 	 * 1: WL-BT space-interference, always 1 if BTG/BTA/SPDT = 1
8990 	 * if dedicated-ant, it may be 1 if BT-TX is bigger than WL-Rx(xtk_xmap)
8991 	 *
8992 	 * ant_xmap(ANT-Division-Multiplexing)
8993 	 * ==> dedicated-ant->0, BTG/BTA/SPDT->1
8994 	 *
8995 	 * xtk_xmap(Cross-talk map)-> calculate WL/BT interference by SIR
8996 	 * ==> 1: interference, 0: no-interference
8997 	 *
8998 	 * fdm_map(Frequency-Division-Multiplexing): WL/BT RF_Band overlap-map
8999 	 * 2bit-map: bit[1]:5/6GHz, bit[0]:2.4GHz
9000 	 */
9001 	for (i = 0; i < RTW89_PHY_NUM; i++) {
9002 		if (wl->rf_band_map[i] & BIT(RTW89_BAND_2G))
9003 			wl_rf_band[i] |= BIT(RTW89_BAND_2G);
9004 
9005 		if (wl->rf_band_map[i] & (BIT(RTW89_BAND_5G) | BIT(RTW89_BAND_6G)))
9006 			wl_rf_band[i] |= BIT(RTW89_BAND_5G);
9007 
9008 		dm->fit_xmap[i][BTC_BT_1ST] = wl_rf_band[i] & bt0->rf_band_map;
9009 		dm->fit_xmap[i][BTC_BT_2ND] = wl_rf_band[i] & bt1->rf_band_map;
9010 		dm->fit_xmap[i][BTC_BT_EXT] = wl_rf_band[i] & bt2->rf_band_map;
9011 	}
9012 
9013 	/*
9014 	 * if MR_WTYPE_MLD2L1R_NONMLD, FW will change 2+0/0+2/1+1
9015 	 * Therefore, BTC_MLO_RF_xxx is not real-time state.
9016 	 * if link mode change by _ntfy_generic(BTC_GNTFY_MRCX_INFO)
9017 	 * the HW-BAND is decided by wl->mlo_info.mrcx_act_hwb_map
9018 	 * In this case, BTC_RF_S0->HWB0, BTC_RF_S1->HWB1
9019 	 */
9020 	if (wl->mlo_info.wtype == RTW89_MR_WTYPE_MLD2L1R_NONMLD) {
9021 		if (wl->role_info.link_mode[RTW89_MAC_0] != BTC_WLINK_DB_MCC) {/* mode chg */
9022 			if (wl->mlo_info.mrcx_act_hwb_map == BIT(RTW89_PHY_1))
9023 				path_hwb[BTC_RF_S0] = RTW89_PHY_1;/* S0/1->HWB1 */
9024 			else
9025 				path_hwb[BTC_RF_S1] = RTW89_PHY_0;/* S0/1->HWB0 */
9026 		}
9027 	} else {
9028 		if (wl->mlo_info.rf_combination == BTC_MLO_RF_2_PLUS_0)
9029 			path_hwb[BTC_RF_S1] = RTW89_PHY_0; /* 2+0 RF-S0/1->HWB0 */
9030 		else if (wl->mlo_info.rf_combination == BTC_MLO_RF_0_PLUS_2)
9031 			path_hwb[BTC_RF_S0] = RTW89_PHY_1; /* 2+0 RF-S0/1->HWB1 */
9032 	}
9033 
9034 	/*
9035 	 * WL 1SS MIMO-PS: WL RX is confined to a single path, so the unused
9036 	 * path has no WL-RX frequency interference with any BT.
9037 	 * RF_PATH_AB -> not 1SS, both paths keep their real fit_xmap.
9038 	 * Same helper as _update_sdm_map(), so xtk_xmap and fit_map always
9039 	 * agree on which RF-path is the unused one.
9040 	 * e.g. CIS@BT_2ND -> rx_path=RF_PATH_B, used_path=S1:
9041 	 *      RF-S1 keeps its real fit_xmap, RF-S0 is cleared.
9042 	 */
9043 	used_path = _get_sdm_1ss_path(rtwdev);
9044 	dm->fit_used_path = used_path; /* record for dbg cmd "xmap" */
9045 
9046 	/*
9047 	 * tdd_map = sit_xmap * fdm_map, 1: WL-RF-Sx vs. BTx take TDD-Action
9048 	 * fdd_map =(!sit_xmap) * fdm_map, 1: WL-RF-Sx vs.BTx take FDD-Action
9049 	 * co-rx map = ant_xmap * fdm_map 1:WL/BT co-rx (for halbb-btg-ctrl)
9050 	 * sit_xmap,ant_xmap = 0 or 1, so tdd/fdd use multiplication (*)
9051 	 *
9052 	 * fit: WL-BT freq-interact(2bit band-map) of RF-Sx vs. BTx,
9053 	 * = fit_xmap[HWB][BTx], the used_path keeps this real band-map,
9054 	 * the unused path is cleared to 0 if 1SS MIMO-PS.
9055 	 */
9056 
9057 	for (i = 0; i < BTC_RF_NUM; i++)
9058 		for (j = 0; j < BTC_ALL_BT_EZL; j++) {
9059 			fit = dm->fit_xmap[path_hwb[i]][j];
9060 
9061 			/*
9062 			 * 1SS MIMO-PS: no WL-Rx on the unused path.
9063 			 * Only the local fit is dropped, dm->fit_xmap keeps
9064 			 * the real per-HW-band map: it is indexed by HW-band,
9065 			 * and both RF-path may map to the same HW-band, so
9066 			 * clearing it there would also drop used_path's entry
9067 			 * (and the other MLO link's entry in DB_MCC).
9068 			 */
9069 			if (used_path != RF_PATH_AB && i != used_path)
9070 				fit = 0;
9071 
9072 			dm->fit_map[i][j] = fit; /* for dbg cmd "xmap" */
9073 
9074 			dm->tdd_map[i][j] = dm->sit_xmap[i][j] * fit;
9075 			dm->fdd_map[i][j] = !dm->sit_xmap[i][j] * fit;
9076 			dm->corx_map[i][j] = dm->ant_xmap[i][j] * fit;
9077 	}
9078 
9079 	/* TDD-Binding */
9080 	_set_bind_info(btc, BTC_MECH_TDD);
9081 
9082 	/* FDD-Binding */
9083 	_set_bind_info(btc, BTC_MECH_FDD);
9084 
9085 	dm->out_of_band = !dm->tdd_bind.rf_band && !dm->fdd_bind.rf_band;
9086 	dm->fdd_en = !!dm->fdd_bind.rf_band;
9087 	dm->tdd_en = !!dm->tdd_bind.rf_band;
9088 
9089 	/* set BT on/off state for GNT_WL Combined-MUX control */
9090 	if (bt0->enable.now)
9091 		val |= BIT(BTC_BT_1ST);
9092 
9093 	if (bt1->enable.now)
9094 		val |= BIT(BTC_BT_2ND);
9095 
9096 	if (bt2->func_type)
9097 		val |= BIT(BTC_BT_EXT);
9098 
9099 	dm->ost_info.bt_enable_state = dm->bt_only ? _bind_is_btonly : val;
9100 
9101 	/*
9102 	 * Turn the BT TX/RX on/off by the BTG control in WL RF. Driven by
9103 	 * bt_enable_state shadow instead of its change, so a write the RF
9104 	 * layer rejects is retried in the next run. Call it every time, the
9105 	 * shadow compare inside is what suppresses the redundant RF I/O.
9106 	 */
9107 	_set_bttrx_en(rtwdev);
9108 }
9109 
9110 static void _update_run_ctrl_info(struct rtw89_dev *rtwdev)
9111 {
9112 	struct rtw89_btc *btc = &rtwdev->btc;
9113 	struct rtw89_btc_dm *dm = &btc->dm;
9114 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9115 	struct rtw89_btc_ctrl ctrl = btc->ctrl;
9116 	struct rtw89_fbtc_wl_ctrl_info *wl_ctrl_info = &ctrl.wl_ctrl_info;
9117 	u8 i;
9118 
9119 	ctrl.wl_only = dm->wl_only;
9120 	ctrl.bt_only = dm->bt_only;
9121 	ctrl.ntfy_type = dm->run_reason;
9122 
9123 	wl_ctrl_info->smap_val = wl->status.val;
9124 	wl_ctrl_info->rfk_state = wl->rfk_info.state;
9125 	wl_ctrl_info->rfk_type = wl->rfk_info.type;
9126 	wl_ctrl_info->client_pstdma_on =  dm->client_ps_tdma_on;
9127 	wl_ctrl_info->fw_scan = wl->scan_info.fw_scan;
9128 
9129 	for (i = RTW89_MAC_0; i <= RTW89_MAC_1; i++) {
9130 		wl_ctrl_info->rf_band_map[i] = wl->rf_band_map[i];
9131 		wl_ctrl_info->rf_ch[i] = wl->rf_ch_info[i].center_ch;
9132 	}
9133 
9134 	if (memcmp(&btc->ctrl, &ctrl, sizeof(struct rtw89_btc_ctrl))) {
9135 		memcpy(&btc->ctrl, &ctrl, sizeof(struct rtw89_btc_ctrl));
9136 		if (btc->ver->fcxctrl >= 9)
9137 			_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
9138 	}
9139 }
9140 
9141 static
9142 void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
9143 {
9144 	struct rtw89_btc *btc = &rtwdev->btc;
9145 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
9146 	struct rtw89_btc_cx *cx = &btc->cx;
9147 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9148 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
9149 	u8 mode = btc->dm.tdd_bind.wl_link_mode;
9150 	u8 mode_v0 = BTC_WLINK_V0_OTHER;
9151 	bool has_2ghz;
9152 
9153 	lockdep_assert_wiphy(rtwdev->hw->wiphy);
9154 
9155 	dm->run_reason = reason;
9156 	_update_dm_step(rtwdev, reason);
9157 
9158 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reason=%d, mode=%d\n",
9159 		    __func__, reason, mode);
9160 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): wl_only=%d, bt_only=%d\n",
9161 		    __func__, dm->wl_only, dm->bt_only);
9162 
9163 	/* Be careful to change the following function sequence!! */
9164 	if (btc->manual_ctrl) {
9165 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9166 			    "[BTC], %s(): return for Manual CTRL!!\n",
9167 			    __func__);
9168 		return;
9169 	}
9170 
9171 	if (!wl->status.map.init_ok) {
9172 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9173 			    "[BTC], %s(): return for WL init fail!!\n",
9174 			    __func__);
9175 		return;
9176 	}
9177 
9178 	if (wl->status.map.rf_off_pre == wl->status.map.rf_off &&
9179 	    wl->status.map.lps_pre == wl->status.map.lps &&
9180 	    !dm->lps_ctrl_change && !dm->lps_ctrl_scbd) {
9181 		if (reason == BTC_RSN_NTFY_POWEROFF ||
9182 		    reason == BTC_RSN_NTFY_RADIO_STATE) {
9183 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
9184 				    "[BTC], %s(): return for WL rf off state no change!!\n",
9185 				    __func__);
9186 			return;
9187 		}
9188 		if (wl->status.map.rf_off == 1 ||
9189 		    wl->status.map.lps == BTC_LPS_RF_OFF) {
9190 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
9191 				    "[BTC], %s(): return for WL rf off state!!\n",
9192 				    __func__);
9193 			return;
9194 		}
9195 	}
9196 
9197 	_update_run_ctrl_info(rtwdev);
9198 
9199 	if (reason == BTC_RSN_NTFY_RADIO_STATE)
9200 		_update_bt_scbd(rtwdev, BTC_ALL_BT, false);
9201 
9202 	dm->freerun = false;
9203 	dm->cnt_dm[BTC_DCNT_RUN]++;
9204 	dm->fddt_train = BTC_FDDT_DISABLE;
9205 	bt->scan_rx_low_pri = false;
9206 
9207 	_set_coex_binding(rtwdev);
9208 	_update_btc_state_map(rtwdev);
9209 
9210 	dm->freerun_chk = _check_freerun(rtwdev); /* check if meet freerun */
9211 
9212 	if (btc->ctrl.always_freerun) {
9213 		_action_freerun(rtwdev);
9214 		goto exit;
9215 	}
9216 
9217 	if (dm->wl_only) {
9218 		_action_wl_only(rtwdev);
9219 		goto exit;
9220 	}
9221 
9222 	if (wl->status.map.rf_off || dm->bt_only || wl->status.map.lps) {
9223 		_action_wl_off(rtwdev, mode);
9224 		goto exit;
9225 	}
9226 
9227 	if (reason == BTC_RSN_NTFY_INIT) {
9228 		_action_wl_init(rtwdev);
9229 		goto exit;
9230 	}
9231 
9232 	if (!cx->bt0.enable.now && !cx->bt_ext.func_type) {
9233 		_action_bt_off(rtwdev);
9234 		goto exit;
9235 	}
9236 
9237 	if (cx->bt0.whql_test) {
9238 		_action_bt_whql(rtwdev);
9239 		goto exit;
9240 	}
9241 
9242 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
9243 		_action_wl_rfk(rtwdev);
9244 		goto exit;
9245 	}
9246 
9247 	if (wl->status.val & btc_scanning_map.val && !wl->rfk_info.con_rfk) {
9248 		_action_wl_scan(rtwdev);
9249 		bt->scan_rx_low_pri = true;
9250 		goto exit;
9251 	}
9252 
9253 	if (mode == BTC_WLINK_NOLINK) {
9254 		mode_v0 = BTC_WLINK_V0_NOLINK;
9255 	} else if (btc->dm.tdd_bind.rf_band == BIT(RTW89_BAND_5G)) {
9256 		mode_v0 = BTC_WLINK_V0_5G;
9257 	} else if (btc->dm.tdd_bind.rf_band & BIT(RTW89_BAND_5G) &&
9258 		   btc->dm.tdd_bind.rf_band & BIT(RTW89_BAND_2G)) {
9259 		mode_v0 = BTC_WLINK_V0_25G_MCC;
9260 	} else if (btc->dm.tdd_bind.rf_band == BIT(RTW89_BAND_2G)) {
9261 		switch (mode) {
9262 		case BTC_WLINK_STA:
9263 			mode_v0 = BTC_WLINK_V0_2G_STA;
9264 			break;
9265 		case BTC_WLINK_AP:
9266 			mode_v0 = BTC_WLINK_V0_2G_AP;
9267 			break;
9268 		case BTC_WLINK_GO:
9269 			mode_v0 = BTC_WLINK_V0_2G_GO;
9270 			break;
9271 		case BTC_WLINK_GC:
9272 			mode_v0 = BTC_WLINK_V0_2G_GC;
9273 			break;
9274 		case BTC_WLINK_SCC:
9275 			mode_v0 = BTC_WLINK_V0_2G_SCC;
9276 			break;
9277 		case BTC_WLINK_SB_MCC:
9278 			mode_v0 = BTC_WLINK_V0_2G_MCC;
9279 			break;
9280 		default:
9281 			mode_v0 = BTC_WLINK_V0_OTHER;
9282 			break;
9283 		}
9284 	} else {
9285 		/* No binding (out_of_band): derive mode_v0 from link_mode + rf_band_map */
9286 		has_2ghz = wl->rf_band_map[RTW89_MAC_0] & BIT(RTW89_BAND_2G) ||
9287 			   wl->rf_band_map[RTW89_MAC_1] & BIT(RTW89_BAND_2G);
9288 
9289 		if (!has_2ghz) {
9290 			mode_v0 = BTC_WLINK_V0_5G;
9291 		} else if (mode == BTC_WLINK_DB_MCC) {
9292 			mode_v0 = BTC_WLINK_V0_25G_MCC;
9293 		} else {
9294 			switch (mode) {
9295 			case BTC_WLINK_STA:
9296 				mode_v0 = BTC_WLINK_V0_2G_STA;
9297 				break;
9298 			case BTC_WLINK_AP:
9299 				mode_v0 = BTC_WLINK_V0_2G_AP;
9300 				break;
9301 			case BTC_WLINK_GO:
9302 				mode_v0 = BTC_WLINK_V0_2G_GO;
9303 				break;
9304 			case BTC_WLINK_GC:
9305 				mode_v0 = BTC_WLINK_V0_2G_GC;
9306 				break;
9307 			case BTC_WLINK_SCC:
9308 				mode_v0 = BTC_WLINK_V0_2G_SCC;
9309 				break;
9310 			case BTC_WLINK_SB_MCC:
9311 				mode_v0 = BTC_WLINK_V0_2G_MCC;
9312 				break;
9313 			default:
9314 				mode_v0 = BTC_WLINK_V0_OTHER;
9315 				break;
9316 			}
9317 		}
9318 	}
9319 
9320 	switch (mode_v0) {
9321 	case BTC_WLINK_NOLINK:
9322 		_action_wl_nc(rtwdev);
9323 		break;
9324 	case BTC_WLINK_V0_2G_STA:
9325 		if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL))
9326 			bt->scan_rx_low_pri = true;
9327 		_action_wl_2g_sta(rtwdev);
9328 		break;
9329 	case BTC_WLINK_V0_2G_AP:
9330 		bt->scan_rx_low_pri = true;
9331 		_action_wl_2g_ap(rtwdev);
9332 		break;
9333 	case BTC_WLINK_V0_2G_GO:
9334 		bt->scan_rx_low_pri = true;
9335 		_action_wl_2g_go(rtwdev);
9336 		break;
9337 	case BTC_WLINK_V0_2G_GC:
9338 		bt->scan_rx_low_pri = true;
9339 		_action_wl_2g_gc(rtwdev);
9340 		break;
9341 	case BTC_WLINK_V0_2G_SCC:
9342 		bt->scan_rx_low_pri = true;
9343 		_action_wl_2g_scc(rtwdev);
9344 		break;
9345 	case BTC_WLINK_V0_2G_MCC:
9346 		bt->scan_rx_low_pri = true;
9347 		_action_wl_2g_mcc(rtwdev);
9348 		break;
9349 	case BTC_WLINK_V0_25G_MCC:
9350 		bt->scan_rx_low_pri = true;
9351 		_action_wl_25g_mcc(rtwdev);
9352 		break;
9353 	case BTC_WLINK_V0_5G:
9354 		_action_wl_5g(rtwdev);
9355 		break;
9356 	case BTC_WLINK_V0_2G_NAN:
9357 		_action_wl_2g_nan(rtwdev);
9358 		break;
9359 	default:
9360 		_action_wl_other(rtwdev);
9361 		break;
9362 	}
9363 
9364 exit:
9365 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): exit\n", __func__);
9366 	_action_common(rtwdev);
9367 }
9368 
9369 void rtw89_btc_init(struct rtw89_dev *rtwdev)
9370 {
9371 	const struct rtw89_chip_info *chip = rtwdev->chip;
9372 	struct rtw89_btc *btc = &rtwdev->btc;
9373 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9374 
9375 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9376 		    "[BTC], %s(): Init %s !!\n", __func__,
9377 		    chip_id_str(chip->chip_id));
9378 
9379 	_reset_btc_var(rtwdev, BTC_RESET_ALL);
9380 
9381 	btc->dm.run_reason = BTC_RSN_NONE;
9382 	btc->dm.run_action = BTC_ACT_NONE;
9383 	wl->status.map.init_ok = true;
9384 }
9385 
9386 void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev)
9387 {
9388 	struct rtw89_btc *btc = &rtwdev->btc;
9389 
9390 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
9391 	btc->dm.cnt_notify[BTC_NCNT_POWER_ON]++;
9392 }
9393 
9394 void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev)
9395 {
9396 	struct rtw89_btc *btc = &rtwdev->btc;
9397 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9398 
9399 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
9400 	btc->dm.cnt_notify[BTC_NCNT_POWER_OFF]++;
9401 
9402 	btc->cx.wl.status.map.rf_off = 1;
9403 	btc->cx.wl.status.map.busy = 0;
9404 	wl->status.map.lps = BTC_LPS_OFF;
9405 
9406 	_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_ALL, false);
9407 	_run_coex(rtwdev, BTC_RSN_NTFY_POWEROFF);
9408 
9409 	btc->cx.wl.status.map.rf_off_pre = btc->cx.wl.status.map.rf_off;
9410 }
9411 
9412 #define BTC_PLATFORM_LITTLE_ENDIAN 0
9413 static void _set_init_info(struct rtw89_dev *rtwdev)
9414 {
9415 	const struct rtw89_chip_info *chip = rtwdev->chip;
9416 	struct rtw89_btc *btc = &rtwdev->btc;
9417 	struct rtw89_btc_dm *dm = &btc->dm;
9418 	struct rtw89_btc_cx *cx = &btc->cx;
9419 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9420 
9421 	dm->init_info.init_mode = wl->coex_mode;
9422 	dm->init_info.wl_init_ok = wl->status.map.init_ok;
9423 	dm->init_info.endian_type = BTC_PLATFORM_LITTLE_ENDIAN;
9424 	dm->init_info.bt0_function = cx->bt0.func_type;
9425 	dm->init_info.bt1_function = cx->bt1.func_type;
9426 	dm->init_info.bt2_function = cx->bt_ext.func_type;
9427 	dm->init_info.pta_mode = RTW89_MAC_AX_COEX_RTK_MODE;
9428 	dm->init_info.pta_direction = RTW89_MAC_AX_COEX_INNER;
9429 	dm->init_info.wl_only = dm->wl_only;
9430 	dm->init_info.bt_only = dm->bt_only;
9431 	dm->init_info.wl_init_ok = wl->status.map.init_ok;
9432 	dm->init_info.cx_other = btc->cx.bt_ext.func_type;
9433 	dm->init_info.wl_guard_ch = chip->afh_guard_ch;
9434 	dm->init_info.dbcc_en = rtwdev->dbcc_en;
9435 
9436 	dm->init_info.module = btc->mdinfo;
9437 
9438 	_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
9439 	_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
9440 	rtw89_btc_fw_set_slots(rtwdev);
9441 	btc_fw_set_monreg(rtwdev);
9442 	_set_ext_interface(rtwdev);
9443 	_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR, RTW89_PHY_0);
9444 
9445 	_update_sdm_map(rtwdev);
9446 }
9447 
9448 void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
9449 {
9450 	struct rtw89_btc *btc = &rtwdev->btc;
9451 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
9452 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9453 	const struct rtw89_chip_info *chip = rtwdev->chip;
9454 
9455 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9456 		    "[BTC], %s(): mode=%d\n", __func__, mode);
9457 
9458 	wl->coex_mode = mode;
9459 	dm->cnt_notify[BTC_NCNT_INIT_COEX]++;
9460 	dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
9461 	dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
9462 	wl->status.map.rf_off = mode == BTC_MODE_WLOFF ? 1 : 0;
9463 	dm->vid = rtwdev->custid;
9464 	btc->ctrl.always_freerun = mode == BTC_MODE_COTX;
9465 
9466 	if (!wl->status.map.init_ok) {
9467 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9468 			    "[BTC], %s(): return for WL init fail!!\n",
9469 			    __func__);
9470 		dm->error.map.init = true;
9471 		return;
9472 	}
9473 
9474 	btc->cx.bt0.enable.now = 1;
9475 	btc->cx.bt0.run_patch_code = 1;
9476 	if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
9477 		btc->cx.bt1.enable.now = 1;
9478 		btc->cx.bt1.run_patch_code = 1;
9479 	}
9480 
9481 	if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO)
9482 		btc->io_oflld_type = BTC_IO_OFLD_BTC_H2C;
9483 	else
9484 		btc->io_oflld_type = BTC_IO_OFLD_NO_SUPPORT;
9485 
9486 	chip->ops->btc_set_rfe(rtwdev);
9487 	chip->ops->btc_init_cfg(rtwdev);
9488 
9489 	_write_scbd(rtwdev, BTC_ALL_BT,
9490 		    BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true);
9491 
9492 	if (rtw89_mac_get_ctrl_path(rtwdev)) {
9493 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9494 			    "[BTC], %s(): PTA owner warning!!\n",
9495 			    __func__);
9496 		dm->error.map.pta_owner = true;
9497 	}
9498 
9499 	_set_init_info(rtwdev);
9500 	_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR, RTW89_PHY_0);
9501 	btc_fw_set_monreg(rtwdev);
9502 	rtw89_btc_fw_set_slots(rtwdev);
9503 	_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
9504 	_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
9505 
9506 	_run_coex(rtwdev, BTC_RSN_NTFY_INIT);
9507 }
9508 
9509 void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
9510 {
9511 	struct rtw89_btc *btc = &rtwdev->btc;
9512 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9513 
9514 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9515 		    "[BTC], %s(): phy_idx=%d, band=%d\n",
9516 		    __func__, phy_idx, band);
9517 
9518 	if (phy_idx >= RTW89_PHY_NUM)
9519 		return;
9520 
9521 	btc->dm.cnt_notify[BTC_NCNT_SCAN_START]++;
9522 	wl->status.map.scan = true;
9523 	wl->scan_info.band[phy_idx] = band;
9524 	wl->scan_info.phy_map |= BIT(phy_idx);
9525 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
9526 
9527 	if (rtwdev->dbcc_en) {
9528 		wl->dbcc_info.scan_band[phy_idx] = band;
9529 		_update_dbcc_band(rtwdev, phy_idx);
9530 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
9531 	}
9532 
9533 	if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw))
9534 		btc->ctrl.wl_ctrl_info.fw_scan = 1;
9535 
9536 	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_START);
9537 }
9538 
9539 void rtw89_btc_ntfy_scan_finish(struct rtw89_dev *rtwdev, u8 phy_idx)
9540 {
9541 	struct rtw89_btc *btc = &rtwdev->btc;
9542 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9543 
9544 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9545 		    "[BTC], %s(): phy_idx=%d\n", __func__, phy_idx);
9546 	btc->dm.cnt_notify[BTC_NCNT_SCAN_FINISH]++;
9547 
9548 	wl->status.map.scan = false;
9549 	wl->scan_info.phy_map &= ~BIT(phy_idx);
9550 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
9551 
9552 	if (rtwdev->dbcc_en) {
9553 		_update_dbcc_band(rtwdev, phy_idx);
9554 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
9555 	}
9556 
9557 	btc->dm.tdma_instant_excute = 1;
9558 
9559 	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_FINISH);
9560 }
9561 
9562 void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
9563 {
9564 	struct rtw89_btc *btc = &rtwdev->btc;
9565 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9566 
9567 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9568 		    "[BTC], %s(): phy_idx=%d, band=%d\n",
9569 		    __func__, phy_idx, band);
9570 
9571 	if (phy_idx >= RTW89_PHY_NUM)
9572 		return;
9573 
9574 	btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++;
9575 
9576 	if (rtwdev->dbcc_en) {
9577 		wl->dbcc_info.scan_band[phy_idx] = band;
9578 		_update_dbcc_band(rtwdev, phy_idx);
9579 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
9580 	}
9581 	_run_coex(rtwdev, BTC_RSN_NTFY_SWBAND);
9582 }
9583 
9584 void rtw89_btc_ntfy_specific_packet(struct rtw89_dev *rtwdev,
9585 				    enum btc_pkt_type pkt_type)
9586 {
9587 	struct rtw89_btc *btc = &rtwdev->btc;
9588 	struct rtw89_btc_cx *cx = &btc->cx;
9589 	struct rtw89_btc_wl_info *wl = &cx->wl;
9590 	struct rtw89_btc_bt_link_info *b = &cx->bt0.link_info;
9591 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
9592 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
9593 	u32 cnt;
9594 	u32 delay = RTW89_COEX_ACT1_WORK_PERIOD;
9595 	bool delay_work = false;
9596 
9597 	switch (pkt_type) {
9598 	case PACKET_DHCP:
9599 		cnt = ++wl->wcnt[BTC_WCNT_DHCP];
9600 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9601 			    "[BTC], %s(): DHCP cnt=%d\n", __func__, cnt);
9602 		wl->status.map.handshake = 0;
9603 		wl->status.map._4way = 0;
9604 		wl->status.map.dhcp = 1;
9605 		delay_work = true;
9606 		break;
9607 	case PACKET_EAPOL:
9608 		cnt = ++wl->wcnt[BTC_WCNT_EAPOL];
9609 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9610 			    "[BTC], %s(): EAPOL cnt=%d\n", __func__, cnt);
9611 		wl->status.map.handshake = 0;
9612 		wl->status.map._4way = 1;
9613 		wl->status.map.dhcp = 0;
9614 		delay_work = true;
9615 		if (hfp->exist || hid->exist)
9616 			delay /= 2;
9617 		break;
9618 	case PACKET_EAPOL_END:
9619 		cnt = ++wl->wcnt[BTC_WCNT_EAPOL];
9620 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9621 			    "[BTC], %s(): EAPOL_End cnt=%d\n",
9622 			    __func__, cnt);
9623 		wl->status.map._4way = 0;
9624 		wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_act1_work);
9625 		break;
9626 	case PACKET_ARP:
9627 		cnt = ++wl->wcnt[BTC_WCNT_ARP];
9628 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9629 			    "[BTC], %s(): ARP cnt=%d\n", __func__, cnt);
9630 		return;
9631 	case PACKET_ICMP:
9632 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9633 			    "[BTC], %s(): ICMP pkt\n", __func__);
9634 		return;
9635 	default:
9636 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9637 			    "[BTC], %s(): unknown packet type %d\n",
9638 			    __func__, pkt_type);
9639 		return;
9640 	}
9641 
9642 	if (delay_work) {
9643 		wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_act1_work);
9644 		wiphy_delayed_work_queue(rtwdev->hw->wiphy,
9645 					 &rtwdev->coex_act1_work, delay);
9646 	}
9647 
9648 	btc->dm.cnt_notify[BTC_NCNT_SPECIAL_PACKET]++;
9649 	_run_coex(rtwdev, BTC_RSN_NTFY_SPECIFIC_PACKET);
9650 }
9651 
9652 void rtw89_btc_ntfy_eapol_packet_work(struct wiphy *wiphy, struct wiphy_work *work)
9653 {
9654 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
9655 						btc.eapol_notify_work);
9656 
9657 	lockdep_assert_wiphy(wiphy);
9658 
9659 	rtw89_leave_ps_mode(rtwdev);
9660 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL);
9661 }
9662 
9663 void rtw89_btc_ntfy_arp_packet_work(struct wiphy *wiphy, struct wiphy_work *work)
9664 {
9665 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
9666 						btc.arp_notify_work);
9667 
9668 	lockdep_assert_wiphy(wiphy);
9669 
9670 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ARP);
9671 }
9672 
9673 void rtw89_btc_ntfy_dhcp_packet_work(struct wiphy *wiphy, struct wiphy_work *work)
9674 {
9675 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
9676 						btc.dhcp_notify_work);
9677 
9678 	lockdep_assert_wiphy(wiphy);
9679 
9680 	rtw89_leave_ps_mode(rtwdev);
9681 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_DHCP);
9682 }
9683 
9684 void rtw89_btc_ntfy_icmp_packet_work(struct wiphy *wiphy, struct wiphy_work *work)
9685 {
9686 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
9687 						btc.icmp_notify_work);
9688 
9689 	lockdep_assert_wiphy(wiphy);
9690 
9691 	rtw89_leave_ps_mode(rtwdev);
9692 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ICMP);
9693 }
9694 
9695 static u8 _update_bt_rssi_level(struct rtw89_dev *rtwdev, u8 rssi)
9696 {
9697 	const struct rtw89_chip_info *chip = rtwdev->chip;
9698 	struct rtw89_btc *btc = &rtwdev->btc;
9699 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
9700 	u8 *rssi_st, rssi_th, rssi_level = 0;
9701 	u8 i;
9702 
9703 	/* for rssi locate in which {40, 36, 31, 28}
9704 	 * if rssi >= 40% (-60dBm) --> rssi_level = 4
9705 	 * if 36% <= rssi < 40%    --> rssi_level = 3
9706 	 * if 31% <= rssi < 36%    --> rssi_level = 2
9707 	 * if 28% <= rssi < 31%    --> rssi_level = 1
9708 	 * if rssi < 28%           --> rssi_level = 0
9709 	 */
9710 
9711 	/* check if rssi across bt_rssi_thres boundary */
9712 	for (i = 0; i < BTC_BT_RSSI_THMAX; i++) {
9713 		rssi_th = chip->bt_rssi_thres[i];
9714 		rssi_st = &bt->link_info.rssi_state[i];
9715 
9716 		*rssi_st = _update_rssi_state(rtwdev, *rssi_st, rssi, rssi_th);
9717 
9718 		if (BTC_RSSI_HIGH(*rssi_st)) {
9719 			rssi_level = BTC_BT_RSSI_THMAX - i;
9720 			break;
9721 		}
9722 	}
9723 	return rssi_level;
9724 }
9725 
9726 #define BT_PROFILE_PROTOCOL_MASK GENMASK(7, 4)
9727 
9728 static void _update_bt_info(struct rtw89_dev *rtwdev, u8 bid, u8 *buf, u32 len)
9729 {
9730 	const struct rtw89_chip_info *chip = rtwdev->chip;
9731 	struct rtw89_btc *btc = &rtwdev->btc;
9732 	struct rtw89_btc_bt_a2dp_desc *a2dp;
9733 	struct rtw89_btc_cx *cx = &btc->cx;
9734 	struct rtw89_btc_bt_hfp_desc *hfp;
9735 	struct rtw89_btc_bt_hid_desc *hid;
9736 	struct rtw89_btc_bt_pan_desc *pan;
9737 	struct rtw89_btc_bt_link_info *b;
9738 	struct rtw89_btc_bt_info *bt;
9739 	union btc_btinfo btinfo;
9740 	u8 is_bt_56g = 0;
9741 	u8 *raw_info;
9742 
9743 	/* Bit7 is used for RF-band: 0:BT_2.4 GHz, 1:BT_5/6 GHz */
9744 	if ((buf[BTC_BTINFO_L1] & 0x7f) != 6)
9745 		return;
9746 
9747 	bt = (bid == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
9748 
9749 	if ((buf[BTC_BTINFO_L1] & BIT(7)) && bt->band_56G_support) {
9750 		b = &bt->link_info_56g;
9751 		is_bt_56g = 1;
9752 		if (b->status.map.connect)
9753 			bt->rf_band_map |= BIT(RTW89_BAND_5G);
9754 		else
9755 			bt->rf_band_map &= ~BIT(RTW89_BAND_5G);
9756 	} else {
9757 		b = &bt->link_info;
9758 		bt->rf_band_map |= BIT(RTW89_BAND_2G);
9759 	}
9760 
9761 	hfp = &b->hfp_desc;
9762 	hid = &b->hid_desc;
9763 	a2dp = &b->a2dp_desc;
9764 	pan = &b->pan_desc;
9765 	raw_info = is_bt_56g ? bt->raw_info_56g : bt->raw_info;
9766 
9767 	if (!memcmp(raw_info, buf, BTC_BTINFO_MAX)) {
9768 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9769 			    "[BTC], %s(): return by bt-info duplicate!!\n",
9770 			    __func__);
9771 		bt->bcnt[BTC_BCNT_INFOSAME]++;
9772 		return;
9773 	}
9774 
9775 	memcpy(raw_info, buf, BTC_BTINFO_MAX);
9776 
9777 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9778 		    "[BTC], %s(): bt_info[2]=0x%02x\n",
9779 		    __func__, raw_info[2]);
9780 
9781 	hid->type = 0;
9782 
9783 	/* parse raw info low-Byte2 */
9784 	btinfo.val = raw_info[BTC_BTINFO_L2];
9785 	b->status.map.connect = btinfo.lb2.connect;
9786 	b->status.map.sco_busy = btinfo.lb2.sco_busy;
9787 	b->status.map.acl_busy = btinfo.lb2.acl_busy;
9788 	b->status.map.inq_pag = btinfo.lb2.inq_pag;
9789 	bt->inq_pag.now = btinfo.lb2.inq_pag;
9790 	bt->bcnt[BTC_BCNT_INQPAG] += !!(bt->inq_pag.now && !bt->inq_pag.last);
9791 
9792 	hfp->exist = btinfo.lb2.hfp;
9793 	hid->exist = btinfo.lb2.hid;
9794 	a2dp->exist = btinfo.lb2.a2dp;
9795 	pan->exist = btinfo.lb2.pan;
9796 	_update_bt_link_cnt(rtwdev, bt, is_bt_56g);
9797 	if (bid == BTC_BT_1ST)
9798 		btc->dm.trx_info.bt0_profile =
9799 			u32_get_bits(btinfo.val, BT_PROFILE_PROTOCOL_MASK);
9800 	else
9801 		btc->dm.trx_info.bt1_profile =
9802 			u32_get_bits(btinfo.val, BT_PROFILE_PROTOCOL_MASK);
9803 
9804 	/* parse raw info low-Byte3 */
9805 	btinfo.val = raw_info[BTC_BTINFO_L3];
9806 	if (btinfo.lb3.retry != 0)
9807 		bt->bcnt[BTC_BCNT_RETRY]++;
9808 	b->cqddr = btinfo.lb3.cqddr;
9809 	bt->bcnt[BTC_BCNT_INQ] += !!(btinfo.lb3.inq && !bt->inq);
9810 	bt->inq = btinfo.lb3.inq;
9811 	bt->bcnt[BTC_BCNT_PAGE] += !!(btinfo.lb3.pag && !bt->pag);
9812 	bt->pag = btinfo.lb3.pag;
9813 
9814 	b->status.map.mesh_busy = btinfo.lb3.mesh_busy;
9815 	/* parse raw info high-Byte0 */
9816 	btinfo.val = raw_info[BTC_BTINFO_H0];
9817 	/* raw val is dBm unit, translate from -100~ 0dBm to 0~100%*/
9818 	b->rssi = chip->ops->btc_get_bt_rssi(rtwdev, btinfo.hb0.rssi);
9819 	bt->rssi_level = _update_bt_rssi_level(rtwdev, b->rssi);
9820 	btc->dm.trx_info.bt_rssi = bt->rssi_level;
9821 
9822 	/* parse raw info high-Byte1 */
9823 	btinfo.val = raw_info[BTC_BTINFO_H1];
9824 	b->status.map.ble_connect = btinfo.hb1.ble_connect;
9825 	if (btinfo.hb1.ble_connect) {
9826 		if (hid->exist)
9827 			hid->type |= BTC_HID_BLE;
9828 		else if (btinfo.hb1.voice)
9829 			hid->type |= BTC_HID_RCU_VOICE;
9830 		else
9831 			hid->type |= BTC_HID_RCU;
9832 	}
9833 
9834 	bt->bcnt[BTC_BCNT_REINIT] += !!(btinfo.hb1.reinit && !bt->reinit);
9835 	bt->reinit = btinfo.hb1.reinit;
9836 	bt->bcnt[BTC_BCNT_RELINK] += !!(btinfo.hb1.relink && !b->relink.now);
9837 	b->relink.now = btinfo.hb1.relink;
9838 	bt->bcnt[BTC_BCNT_IGNOWL] += !!(btinfo.hb1.igno_wl && !bt->igno_wl);
9839 	bt->igno_wl = btinfo.hb1.igno_wl;
9840 
9841 	if (bt->igno_wl && !cx->wl.status.map.rf_off)
9842 		_set_bt_ignore_wlan_act(rtwdev, false);
9843 
9844 	bt->ble_scan_en = btinfo.hb1.ble_scan;
9845 
9846 	bt->bcnt[BTC_BCNT_ROLESW] += !!(btinfo.hb1.role_sw && !b->role_sw);
9847 	b->role_sw = btinfo.hb1.role_sw;
9848 
9849 	b->multi_link.now = btinfo.hb1.multi_link;
9850 
9851 	/* parse raw info high-Byte2 */
9852 	btinfo.val = raw_info[BTC_BTINFO_H2];
9853 	pan->active = !!btinfo.hb2.pan_active;
9854 
9855 	bt->bcnt[BTC_BCNT_AFH] += !!(btinfo.hb2.afh_update && !b->afh_update);
9856 	b->afh_update = btinfo.hb2.afh_update;
9857 	a2dp->active = btinfo.hb2.a2dp_active;
9858 	b->slave_role = btinfo.hb2.slave;
9859 	hid->slot_info = btinfo.hb2.hid_slot;
9860 	hid->pair_cnt = btinfo.hb2.hid_cnt;
9861 	if (!b->status.map.ble_connect || hid->pair_cnt > 1)
9862 		hid->type |= (hid->slot_info == BTC_HID_218 ?
9863 			      BTC_HID_218 : BTC_HID_418);
9864 	/* parse raw info high-Byte3 */
9865 	btinfo.val = raw_info[BTC_BTINFO_H3];
9866 	a2dp->bitpool = btinfo.hb3.a2dp_bitpool;
9867 
9868 	if (b->tx_3m != (u32)btinfo.hb3.tx_3m)
9869 		bt->bcnt[BTC_BCNT_RATECHG]++;
9870 	b->tx_3m = (u32)btinfo.hb3.tx_3m;
9871 
9872 	a2dp->sink = btinfo.hb3.a2dp_sink;
9873 
9874 	if (!a2dp->exist_last && a2dp->exist) {
9875 		a2dp->vendor_id = 0;
9876 		a2dp->flush_time = 0;
9877 		a2dp->play_latency = 1;
9878 		wiphy_delayed_work_queue(rtwdev->hw->wiphy,
9879 					 &rtwdev->coex_bt_devinfo_work,
9880 					 RTW89_COEX_BT_DEVINFO_WORK_PERIOD);
9881 	}
9882 
9883 	_update_bt_ctrl_lps(rtwdev);
9884 	_run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO);
9885 }
9886 
9887 static void _ntfy_role_info(struct rtw89_dev *rtwdev, u8 rid,
9888 			    struct rtw89_btc_wl_link_info *info,
9889 			    enum btc_role_state reason)
9890 {
9891 	struct rtw89_btc *btc = &rtwdev->btc;
9892 	struct rtw89_btc_wl_link_info *wlinfo = NULL;
9893 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
9894 	const struct rtw89_btc_ver *ver = btc->ver;
9895 	u8 rlink_id = info->phy; /* 1 role_id has 2 rlink_id(by HW_Band0/1) */
9896 	bool refresh_role = false;
9897 
9898 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9899 		    "[BTC], %s(), role_id=%d, reason=%d\n",
9900 		    __func__, rid, reason);
9901 
9902 	if (rid >= ver->max_role_num || rlink_id >= RTW89_PHY_NUM)
9903 		return;
9904 
9905 	btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
9906 
9907 	wlinfo = &wl->rlink_info[rid][rlink_id];
9908 	memcpy(wlinfo, info, sizeof(struct rtw89_btc_wl_link_info));
9909 
9910 	switch (reason) {
9911 	case BTC_ROLE_START:
9912 		wlinfo->active = true;
9913 		return;
9914 	case BTC_ROLE_STOP:
9915 		wlinfo->active = false;
9916 		return;
9917 	case BTC_ROLE_MSTS_STA_CONN_START:
9918 		wl->status.map.transacting = 1;
9919 		wiphy_delayed_work_cancel(rtwdev->hw->wiphy,
9920 					  &rtwdev->coex_act1_work);
9921 		wiphy_delayed_work_queue(rtwdev->hw->wiphy,
9922 					 &rtwdev->coex_act1_work,
9923 					 RTW89_COEX_ACT1_WORK_PERIOD);
9924 		break;
9925 	case BTC_ROLE_MSTS_STA_CONN_END:
9926 		wl->status.map.transacting = 0;
9927 		refresh_role = true;
9928 		break;
9929 	case BTC_ROLE_MSTS_STA_DIS_CONN:
9930 		wl->status.map.transacting = 1;
9931 		refresh_role = false;
9932 		wiphy_delayed_work_cancel(rtwdev->hw->wiphy,
9933 					  &rtwdev->coex_act1_work);
9934 		wiphy_delayed_work_queue(rtwdev->hw->wiphy,
9935 					 &rtwdev->coex_act1_work,
9936 					 RTW89_COEX_ACT1_WORK_PERIOD);
9937 		break;
9938 	case BTC_ROLE_MSTS_AP_START:
9939 	case BTC_ROLE_MSTS_AP_STOP:
9940 		refresh_role = true;
9941 		break;
9942 	case BTC_ROLE_STATE_UNKNOWN:
9943 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
9944 			    "[BTC], %s(), role_id=%d, Unknown reason return!\n",
9945 			    __func__, rid);
9946 		return;
9947 	default:
9948 		return;
9949 	}
9950 
9951 	if (refresh_role) {
9952 		_update_wl_info(rtwdev, wlinfo);
9953 		_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
9954 	}
9955 
9956 	_run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
9957 }
9958 
9959 void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
9960 			      struct rtw89_vif_link *rtwvif_link,
9961 			      struct rtw89_sta_link *rtwsta_link,
9962 			      enum btc_role_state state)
9963 {
9964 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
9965 						       rtwvif_link->chanctx_idx);
9966 	struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
9967 	struct ieee80211_p2p_noa_attr *noa_attr;
9968 	struct ieee80211_p2p_noa_desc *noa_desc;
9969 	struct ieee80211_bss_conf *bss_conf;
9970 	struct ieee80211_link_sta *link_sta;
9971 	struct rtw89_btc_wl_link_info r = {0};
9972 	u8 i, role_id, mode = 0;
9973 
9974 	rcu_read_lock();
9975 
9976 	bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
9977 
9978 	role_id = rtwvif_link->port;
9979 
9980 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state);
9981 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9982 		    "[BTC], role is STA=%d\n",
9983 		    vif->type == NL80211_IFTYPE_STATION);
9984 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", role_id);
9985 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n",
9986 		    chan->band_type, chan->channel, chan->band_width);
9987 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n",
9988 		    state == BTC_ROLE_MSTS_STA_CONN_END);
9989 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
9990 		    "[BTC], bcn_period=%d dtim_period=%d\n",
9991 		    bss_conf->beacon_int, bss_conf->dtim_period);
9992 
9993 	if (rtwsta_link) {
9994 		link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
9995 
9996 		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n",
9997 			    rtwsta_link->mac_id);
9998 
9999 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
10000 			    "[BTC], STA support HE=%d VHT=%d HT=%d\n",
10001 			    link_sta->he_cap.has_he,
10002 			    link_sta->vht_cap.vht_supported,
10003 			    link_sta->ht_cap.ht_supported);
10004 		if (link_sta->he_cap.has_he)
10005 			mode |= BIT(BTC_WL_MODE_HE);
10006 		if (link_sta->vht_cap.vht_supported)
10007 			mode |= BIT(BTC_WL_MODE_VHT);
10008 		if (link_sta->ht_cap.ht_supported)
10009 			mode |= BIT(BTC_WL_MODE_HT);
10010 
10011 		r.mode = mode;
10012 	}
10013 
10014 	if (rtwvif_link->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX) {
10015 		rcu_read_unlock();
10016 		return;
10017 	}
10018 
10019 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
10020 		    "[BTC], wifi_role=%d\n", rtwvif_link->wifi_role);
10021 
10022 	if (vif->type == NL80211_IFTYPE_P2P_GO ||
10023 	    vif->type == NL80211_IFTYPE_P2P_CLIENT) {
10024 		noa_attr = &bss_conf->p2p_noa_attr;
10025 
10026 		for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) {
10027 			noa_desc = &noa_attr->desc[i];
10028 			if (noa_desc->count != 0) {
10029 				r.noa = 1;
10030 				r.noa_duration = le32_to_cpu(noa_desc->duration);
10031 				break;
10032 			}
10033 		}
10034 	}
10035 
10036 	r.mode = mode;
10037 	r.role = rtwvif_link->wifi_role;
10038 	r.phy = rtwvif_link->phy_idx;
10039 	r.pid = role_id;
10040 	r.active = true;
10041 	if (vif->active_links) {
10042 		if (rtwvif_link->link_id < 16)
10043 			r.active = !!(vif->active_links & BIT(rtwvif_link->link_id));
10044 	}
10045 	r.bcn_period = bss_conf->beacon_int;
10046 	r.dtim_period = bss_conf->dtim_period;
10047 	r.band = chan->band_type;
10048 	r.ch = chan->channel;
10049 	r.bw = chan->band_width;
10050 	r.chdef.band = chan->band_type;
10051 	r.chdef.center_ch = chan->channel;
10052 	r.chdef.bw = chan->band_width;
10053 	r.chdef.chan = chan->primary_channel;
10054 
10055 	if (rtwsta_link && vif->type == NL80211_IFTYPE_STATION) {
10056 		r.mac_id = rtwsta_link->mac_id;
10057 		ether_addr_copy(r.mac_addr, rtwvif_link->mac_addr);
10058 	}
10059 
10060 	switch (state) {
10061 	case BTC_ROLE_MSTS_STA_CONN_END:
10062 	case BTC_ROLE_MSTS_AP_START:
10063 		r.connected = MLME_LINKED;
10064 		break;
10065 	default:
10066 		r.connected = MLME_NO_LINK;
10067 		break;
10068 	}
10069 
10070 	rcu_read_unlock();
10071 
10072 	_ntfy_role_info(rtwdev, role_id, &r, state);
10073 }
10074 
10075 void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state)
10076 {
10077 	const struct rtw89_chip_info *chip = rtwdev->chip;
10078 	struct rtw89_btc *btc = &rtwdev->btc;
10079 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
10080 	u32 val;
10081 
10082 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): rf_state = %d\n",
10083 		    __func__, rf_state);
10084 	btc->dm.cnt_notify[BTC_NCNT_RADIO_STATE]++;
10085 
10086 	switch (rf_state) {
10087 	case BTC_RFCTRL_WL_OFF:
10088 		wl->status.map.rf_off = 1;
10089 		wl->status.map.lps = BTC_LPS_OFF;
10090 		wl->status.map.busy = 0;
10091 		break;
10092 	case BTC_RFCTRL_FW_CTRL:
10093 		wl->status.map.rf_off = 0;
10094 		wl->status.map.lps = BTC_LPS_RF_OFF;
10095 		wl->status.map.busy = 0;
10096 		break;
10097 	case BTC_RFCTRL_LPS_WL_ON: /* LPS-Protocol (RFon) */
10098 		wl->status.map.rf_off = 0;
10099 		wl->status.map.lps = BTC_LPS_RF_ON;
10100 		wl->status.map.busy = 0;
10101 		break;
10102 	case BTC_RFCTRL_WL_ON:
10103 	default:
10104 		wl->status.map.rf_off = 0;
10105 		wl->status.map.lps = BTC_LPS_OFF;
10106 		break;
10107 	}
10108 
10109 	if (rf_state == BTC_RFCTRL_WL_ON) {
10110 		val = BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG;
10111 		_write_scbd(rtwdev, BTC_ALL_BT, val, true);
10112 		chip->ops->btc_init_cfg(rtwdev);
10113 	} else {
10114 		if (rf_state == BTC_RFCTRL_FW_CTRL)
10115 			_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_ACTIVE, false);
10116 		else if (rf_state == BTC_RFCTRL_WL_OFF)
10117 			_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_ALL, false);
10118 		else
10119 			_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_ACTIVE, false);
10120 	}
10121 
10122 	btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;
10123 	btc->dm.tdma_instant_excute = 1;
10124 
10125 	_run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE);
10126 	wl->status.map.rf_off_pre = wl->status.map.rf_off;
10127 	wl->status.map.lps_pre = wl->status.map.lps;
10128 }
10129 
10130 static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
10131 			 enum btc_wl_rfk_type type,
10132 			 enum btc_wl_rfk_state state)
10133 {
10134 	struct rtw89_btc *btc = &rtwdev->btc;
10135 	struct rtw89_btc_cx *cx = &btc->cx;
10136 	struct rtw89_btc_wl_info *wl = &cx->wl;
10137 	bool result = BTC_WRFK_REJECT;
10138 
10139 	wl->rfk_info.type = type;
10140 	wl->rfk_info.path_map = FIELD_GET(BTC_RFK_PATH_MAP, phy_path);
10141 	wl->rfk_info.phy_map = FIELD_GET(BTC_RFK_PHY_MAP, phy_path);
10142 	wl->rfk_info.band = FIELD_GET(BTC_RFK_BAND_MAP, phy_path);
10143 
10144 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
10145 		    "[BTC], %s()_start: phy=0x%x, path=0x%x, type=%d, state=%d\n",
10146 		    __func__, wl->rfk_info.phy_map, wl->rfk_info.path_map,
10147 		    type, state);
10148 
10149 	switch (state) {
10150 	case BTC_WRFK_START:
10151 		result = BTC_WRFK_ALLOW;
10152 		wl->rfk_info.state = BTC_WRFK_START;
10153 
10154 		btc->cx.wl.wcnt[BTC_WCNT_RFK_REQ]++;
10155 		btc->dm.cnt_notify[BTC_NCNT_WL_RFK]++;
10156 
10157 		_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLRFK, true);
10158 		break;
10159 	case BTC_WRFK_ONESHOT_START:
10160 	case BTC_WRFK_ONESHOT_STOP:
10161 		btc->cx.wl.wcnt[BTC_WCNT_RFK_GO]++;
10162 		if (type != BTC_WRFKT_RXDCK)
10163 			return BTC_WRFK_ALLOW;
10164 		break;
10165 	case BTC_WRFK_STOP:
10166 		result = BTC_WRFK_ALLOW;
10167 		wl->rfk_info.state = BTC_WRFK_STOP;
10168 
10169 		_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLRFK, false);
10170 		wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_rfk_chk_work);
10171 		break;
10172 	default:
10173 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
10174 			    "[BTC], %s() warning state=%d\n", __func__, state);
10175 		return result;
10176 	}
10177 
10178 	if (result == BTC_WRFK_ALLOW) {
10179 		if (wl->rfk_info.state == BTC_WRFK_START ||
10180 		    wl->rfk_info.state == BTC_WRFK_STOP)
10181 			_run_coex(rtwdev, BTC_RSN_NTFY_WL_RFK);
10182 
10183 		if (wl->rfk_info.state == BTC_WRFK_START)
10184 			wiphy_delayed_work_queue(rtwdev->hw->wiphy,
10185 						 &rtwdev->coex_rfk_chk_work,
10186 						 RTW89_COEX_RFK_CHK_WORK_PERIOD);
10187 	}
10188 
10189 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
10190 		    "[BTC], %s()_finish: rfk_cnt=%d, result=%d\n",
10191 		    __func__, btc->dm.cnt_notify[BTC_NCNT_WL_RFK], result);
10192 
10193 	return result;
10194 }
10195 
10196 void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
10197 			   enum btc_wl_rfk_type type,
10198 			   enum btc_wl_rfk_state state)
10199 {
10200 	u8 band;
10201 	bool allow;
10202 	int ret;
10203 
10204 	lockdep_assert_wiphy(rtwdev->hw->wiphy);
10205 
10206 	band = FIELD_GET(BTC_RFK_BAND_MAP, phy_map);
10207 
10208 	rtw89_debug(rtwdev, RTW89_DBG_RFK,
10209 		    "[RFK] RFK notify (%s / PHY%u / K_type = %u / path_idx = %lu / process = %s)\n",
10210 		    band == RTW89_BAND_2G ? "2G" :
10211 		    band == RTW89_BAND_5G ? "5G" : "6G",
10212 		    !!(FIELD_GET(BTC_RFK_PHY_MAP, phy_map) & BIT(RTW89_PHY_1)),
10213 		    type,
10214 		    FIELD_GET(BTC_RFK_PATH_MAP, phy_map),
10215 		    state == BTC_WRFK_STOP ? "RFK_STOP" :
10216 		    state == BTC_WRFK_START ? "RFK_START" :
10217 		    state == BTC_WRFK_ONESHOT_START ? "ONE-SHOT_START" :
10218 		    "ONE-SHOT_STOP");
10219 
10220 	if (state != BTC_WRFK_START || rtwdev->is_bt_iqk_timeout) {
10221 		_ntfy_wl_rfk(rtwdev, phy_map, type, state);
10222 		return;
10223 	}
10224 
10225 	ret = read_poll_timeout(_ntfy_wl_rfk, allow, allow, 40, 100000, false,
10226 				rtwdev, phy_map, type, state);
10227 	if (ret) {
10228 		rtw89_warn(rtwdev, "RFK notify timeout\n");
10229 		rtwdev->is_bt_iqk_timeout = true;
10230 	}
10231 }
10232 EXPORT_SYMBOL(rtw89_btc_ntfy_wl_rfk);
10233 
10234 struct rtw89_btc_wl_sta_iter_data {
10235 	struct rtw89_dev *rtwdev;
10236 	u8 busy_all;
10237 	u8 dir_all;
10238 	u8 rssi_map_all;
10239 	bool is_sta_change;
10240 	bool is_traffic_change;
10241 };
10242 
10243 static
10244 void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link,
10245 				  struct rtw89_sta_link *rtwsta_link,
10246 				  struct rtw89_btc_wl_sta_iter_data *iter_data)
10247 {
10248 	struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
10249 	struct rtw89_dev *rtwdev = iter_data->rtwdev;
10250 	struct rtw89_btc *btc = &rtwdev->btc;
10251 	struct rtw89_btc_dm *dm = &btc->dm;
10252 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
10253 	struct rtw89_btc_wl_link_info *link_info = NULL;
10254 	struct rtw89_traffic_stats *link_info_t = NULL;
10255 	struct rtw89_traffic_stats *stats = &rtwvif->stats;
10256 	const struct rtw89_chip_info *chip = rtwdev->chip;
10257 	struct rtw89_btc_wl_role_info *r;
10258 	u32 last_tx_rate, last_rx_rate;
10259 	u8 link = rtwvif_link->phy_idx;
10260 	u16 last_tx_lvl, last_rx_lvl;
10261 	u8 port = rtwvif_link->port;
10262 	u8 rssi;
10263 	u8 busy = 0;
10264 	u8 dir = 0;
10265 	u8 rssi_map = 0;
10266 	u8 i = 0;
10267 	bool is_sta_change = false, is_traffic_change = false;
10268 
10269 	rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR;
10270 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi);
10271 
10272 	link_info = &wl->rlink_info[port][link];
10273 
10274 	link_info->stat.traffic = *stats;
10275 	link_info_t = &link_info->stat.traffic;
10276 
10277 	if (link_info->connected == MLME_NO_LINK) {
10278 		link_info->rx_rate_drop_cnt = 0;
10279 		return;
10280 	}
10281 
10282 	link_info->stat.rssi = rssi;
10283 	for (i = 0; i < BTC_WL_RSSI_THMAX; i++) {
10284 		link_info->rssi_state[i] =
10285 			_update_rssi_state(rtwdev,
10286 					   link_info->rssi_state[i],
10287 					   link_info->stat.rssi,
10288 					   chip->wl_rssi_thres[i]);
10289 		if (BTC_RSSI_LOW(link_info->rssi_state[i]))
10290 			rssi_map |= BIT(i);
10291 
10292 		if (btc->ant_type == BTC_ANT_DEDICATED &&
10293 		    BTC_RSSI_CHANGE(link_info->rssi_state[i]))
10294 			is_sta_change = true;
10295 	}
10296 	iter_data->rssi_map_all |= rssi_map;
10297 
10298 	last_tx_rate = link_info_t->tx_rate;
10299 	last_rx_rate = link_info_t->rx_rate;
10300 	last_tx_lvl = (u16)link_info_t->tx_tfc_lv;
10301 	last_rx_lvl = (u16)link_info_t->rx_tfc_lv;
10302 
10303 	if (stats->tx_tfc_lv != RTW89_TFC_IDLE ||
10304 	    stats->rx_tfc_lv != RTW89_TFC_IDLE)
10305 		busy = 1;
10306 
10307 	if (stats->tx_tfc_lv > stats->rx_tfc_lv)
10308 		dir = RTW89_TFC_UL;
10309 	else
10310 		dir = RTW89_TFC_DL;
10311 
10312 	if (link_info->busy != busy || link_info->dir != dir) {
10313 		is_sta_change = true;
10314 		link_info->busy = busy;
10315 		link_info->dir = dir;
10316 	}
10317 
10318 	iter_data->busy_all |= busy;
10319 	iter_data->dir_all |= BIT(dir);
10320 
10321 	if (rtwsta_link->rx_hw_rate <= RTW89_HW_RATE_CCK2 &&
10322 	    last_rx_rate > RTW89_HW_RATE_CCK2 &&
10323 	    link_info_t->rx_tfc_lv > RTW89_TFC_IDLE)
10324 		link_info->rx_rate_drop_cnt++;
10325 
10326 	if (last_tx_rate != rtwsta_link->ra_report.hw_rate ||
10327 	    last_rx_rate != rtwsta_link->rx_hw_rate ||
10328 	    last_tx_lvl != link_info_t->tx_tfc_lv ||
10329 	    last_rx_lvl != link_info_t->rx_tfc_lv)
10330 		is_traffic_change = true;
10331 
10332 	link_info_t->tx_rate = rtwsta_link->ra_report.hw_rate;
10333 	link_info_t->rx_rate = rtwsta_link->rx_hw_rate;
10334 
10335 	if (link_info->role == RTW89_WIFI_ROLE_STATION ||
10336 	    link_info->role == RTW89_WIFI_ROLE_P2P_CLIENT) {
10337 		dm->trx_info.tx_rate = link_info_t->tx_rate;
10338 		dm->trx_info.rx_rate = link_info_t->rx_rate;
10339 	}
10340 
10341 	r = &wl->role_info;
10342 	r->rlink[port][link].tx_lvl = stats->tx_tfc_lv;
10343 	r->rlink[port][link].rx_lvl = stats->rx_tfc_lv;
10344 	r->rlink[port][link].tx_rate = rtwsta_link->ra_report.hw_rate;
10345 	r->rlink[port][link].rx_rate = rtwsta_link->rx_hw_rate;
10346 
10347 	dm->trx_info.tx_lvl = stats->tx_tfc_lv;
10348 	dm->trx_info.rx_lvl = stats->rx_tfc_lv;
10349 	dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate;
10350 	dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate;
10351 	dm->trx_info.tx_tp = link_info_t->tx_throughput;
10352 	dm->trx_info.rx_tp = link_info_t->rx_throughput;
10353 
10354 	/* Trigger coex-run if 0x10980 reg-value is diff with coex setup */
10355 	if ((dm->wl_btg_rx_rb != dm->wl_btg_rx &&
10356 	     dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) ||
10357 	     (dm->wl_pre_agc_rb != dm->wl_pre_agc &&
10358 	      dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND))
10359 		iter_data->is_sta_change = true;
10360 
10361 	if (is_sta_change)
10362 		iter_data->is_sta_change = true;
10363 
10364 	if (is_traffic_change)
10365 		iter_data->is_traffic_change = true;
10366 }
10367 
10368 static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
10369 {
10370 	struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
10371 	struct rtw89_btc_wl_sta_iter_data *iter_data =
10372 				(struct rtw89_btc_wl_sta_iter_data *)data;
10373 	struct rtw89_vif_link *rtwvif_link;
10374 	struct rtw89_sta_link *rtwsta_link;
10375 	unsigned int link_id;
10376 
10377 	rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
10378 		rtwvif_link = rtwsta_link->rtwvif_link;
10379 		__rtw89_btc_ntfy_wl_sta_iter(rtwvif_link, rtwsta_link, iter_data);
10380 	}
10381 }
10382 
10383 #define BTC_NHM_CHK_INTVL 20
10384 
10385 static bool _update_wl_rssi_status(struct rtw89_dev *rtwdev)
10386 {
10387 	struct rtw89_btc *btc = &rtwdev->btc;
10388 	struct rtw89_btc_cx *cx = &btc->cx;
10389 	struct rtw89_btc_wl_info *wl = &cx->wl;
10390 	struct rtw89_btc_dm *dm = &btc->dm;
10391 	struct rtw89_btc_bt_link_info *b;
10392 	u8 i, j, ant_iso, th, rssi, nxt, bt_enable;
10393 	u8 wl_rf_band = RTW89_BAND_2G, cnt = 0;
10394 	bool status_change = false;
10395 	s8 bt_pin;
10396 	s32 val;
10397 
10398 	/* Update WL RSSI (search the min value between all role/HW-band) */
10399 	rssi = 110; /* unit: % */
10400 	for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) {
10401 		for (j = 0; j < RTW89_MAC_NUM; j++) {
10402 			if (!wl->rlink_info[i][j].active ||
10403 			    wl->rlink_info[i][j].connected == MLME_NO_LINK)
10404 				continue;
10405 
10406 			if (wl->rlink_info[i][j].stat.rssi < rssi) { /* find min */
10407 				rssi = wl->rlink_info[i][j].stat.rssi;
10408 				wl_rf_band = wl->rlink_info[i][j].band;
10409 				cnt++;
10410 			}
10411 		}
10412 	}
10413 
10414 	if (cnt == 0) /* no wifi link exist */
10415 		wl->rssi = 0;
10416 	else
10417 		wl->rssi = rssi;
10418 
10419 	/* SIR state: compare WL_RSSI with each BT-Tx interference */
10420 	for (i = BTC_BT_1ST; i <= BTC_BT_EXT; i++) {
10421 		switch (i) {
10422 		case BTC_BT_1ST:
10423 		default:
10424 			bt_enable = cx->bt0.enable.now;
10425 			ant_iso = cx->bt0.ant_iso_to_wl;
10426 			if (wl_rf_band != RTW89_BAND_2G) /* find same rf-band */
10427 				b = &cx->bt0.link_info_56g;
10428 			else
10429 				b = &cx->bt0.link_info;
10430 			if (b->bt_txpwr_desc.le_dbm > b->bt_txpwr_desc.br_dbm)
10431 				bt_pin = b->bt_txpwr_desc.le_dbm;
10432 			else
10433 				bt_pin = b->bt_txpwr_desc.br_dbm;
10434 			break;
10435 		case BTC_BT_2ND:
10436 			bt_enable = cx->bt1.enable.now;
10437 			ant_iso = cx->bt1.ant_iso_to_wl;
10438 			if (wl_rf_band != RTW89_BAND_2G) /* find same rf-band */
10439 				b = &cx->bt0.link_info_56g;
10440 			else
10441 				b = &cx->bt0.link_info;
10442 			if (b->bt_txpwr_desc.le_dbm > b->bt_txpwr_desc.br_dbm)
10443 				bt_pin = b->bt_txpwr_desc.le_dbm;
10444 			else
10445 				bt_pin = b->bt_txpwr_desc.br_dbm;
10446 			break;
10447 		case BTC_BT_EXT:
10448 			bt_enable = !!cx->bt_ext.func_type;
10449 			ant_iso = cx->bt_ext.ant_iso_to_wl;
10450 			bt_pin = cx->bt_ext.max_tx_pwr;
10451 			break;
10452 		}
10453 
10454 		val = 110 + bt_pin - ant_iso - dm->sir_thres;
10455 		if (!bt_enable || val <= 0)
10456 			th = 0;
10457 		else if (val >= 110)
10458 			th = 110;
10459 		else
10460 			th = (u8)val;
10461 
10462 		dm->tdd_rssi_thres = th;
10463 
10464 		nxt = _update_rssi_state(rtwdev, dm->sir_state[i], wl->rssi, th);
10465 
10466 		if (nxt != dm->sir_state[i]) {
10467 			dm->sir_state[i] = nxt;
10468 			status_change = true;
10469 		}
10470 	}
10471 
10472 	return status_change;
10473 }
10474 
10475 void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev)
10476 {
10477 	struct rtw89_btc *btc = &rtwdev->btc;
10478 	struct rtw89_btc_dm *dm = &btc->dm;
10479 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
10480 	struct rtw89_btc_wl_sta_iter_data data = {.rtwdev = rtwdev};
10481 	u8 i;
10482 
10483 	ieee80211_iterate_stations_atomic(rtwdev->hw,
10484 					  rtw89_btc_ntfy_wl_sta_iter,
10485 					  &data);
10486 
10487 	wl->rssi_level = 0;
10488 	btc->dm.cnt_notify[BTC_NCNT_WL_STA]++;
10489 	for (i = BTC_WL_RSSI_THMAX; i > 0; i--) {
10490 		/* set RSSI level 4 ~ 0 if rssi bit map match */
10491 		if (data.rssi_map_all & BIT(i - 1)) {
10492 			wl->rssi_level = i;
10493 			break;
10494 		}
10495 	}
10496 
10497 	if (dm->trx_info.wl_rssi != wl->rssi_level)
10498 		dm->trx_info.wl_rssi = wl->rssi_level;
10499 
10500 	if (_update_wl_rssi_status(rtwdev))
10501 		_update_sdm_map(rtwdev);
10502 
10503 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): busy=%d\n",
10504 		    __func__, !!wl->status.map.busy);
10505 
10506 	_write_scbd(rtwdev, BTC_ALL_BT, BTC_WSCB_WLBUSY, (!!wl->status.map.busy));
10507 
10508 	if (data.is_traffic_change)
10509 		_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
10510 	if (data.is_sta_change) {
10511 		wl->status.map.busy = data.busy_all;
10512 		if (wl->status.map.traffic_dir != data.dir_all) {
10513 			wl->status.map.traffic_dir = data.dir_all;
10514 			/*
10515 			 * traffic_dir (UL/DL) switch changes the 1SS MIMO-PS
10516 			 * xtk_xmap, recompute sit_xmap in the same coex cycle
10517 			 */
10518 			_update_sdm_map(rtwdev);
10519 		}
10520 		_run_coex(rtwdev, BTC_RSN_NTFY_WL_STA);
10521 	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] >=
10522 		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] + BTC_NHM_CHK_INTVL) {
10523 		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
10524 			btc->dm.cnt_notify[BTC_NCNT_WL_STA];
10525 	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] <
10526 		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST]) {
10527 		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
10528 		btc->dm.cnt_notify[BTC_NCNT_WL_STA];
10529 	}
10530 }
10531 
10532 static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func)
10533 {
10534 	struct rtw89_btc *btc = &rtwdev->btc;
10535 	const struct rtw89_btc_ver *ver = btc->ver;
10536 
10537 	switch (func) {
10538 	case BTF_EVNT_RPT:
10539 	case BTF_EVNT_BT_INFO:
10540 	case BTF_EVNT_BT_SCBD:
10541 	case BTF_EVNT_BT_REG:
10542 	case BTF_EVNT_CX_RUNINFO:
10543 	case BTF_EVNT_BT_PSD:
10544 		return func;
10545 	case BTF_EVNT_BT_DEV_INFO:
10546 		if (ver->fwc2hfunc == 0)
10547 			return BTF_EVNT_BUF_OVERFLOW;
10548 		else
10549 			return BTF_EVNT_BT_DEV_INFO;
10550 	case BTF_EVNT_BT_LEAUDIO_INFO:
10551 		if (ver->fwc2hfunc == 0)
10552 			return BTF_EVNT_C2H_LOOPBACK;
10553 		else if (ver->fwc2hfunc == 1)
10554 			return BTF_EVNT_BUF_OVERFLOW;
10555 		else if (ver->fwc2hfunc == 2)
10556 			return func;
10557 		else if (ver->fwc2hfunc == 3 || ver->fwc2hfunc == 4)
10558 			return BTF_EVNT_BUF_OVERFLOW;
10559 		else
10560 			return BTF_EVNT_MAX;
10561 	case BTF_EVNT_BUF_OVERFLOW:
10562 		if (ver->fwc2hfunc == 0)
10563 			return BTF_EVNT_MAX;
10564 		else if (ver->fwc2hfunc == 1)
10565 			return BTF_EVNT_C2H_LOOPBACK;
10566 		else if (ver->fwc2hfunc == 2)
10567 			return func;
10568 		else if (ver->fwc2hfunc == 3 || ver->fwc2hfunc == 4)
10569 			return BTF_EVNT_C2H_LOOPBACK;
10570 		else
10571 			return BTF_EVNT_MAX;
10572 	case BTF_EVNT_C2H_LOOPBACK:
10573 		if (ver->fwc2hfunc == 2)
10574 			return func;
10575 		else if (ver->fwc2hfunc == 3 || ver->fwc2hfunc == 4)
10576 			return BTF_EVNT_BT_LEAUDIO_INFO;
10577 		else
10578 			return BTF_EVNT_MAX;
10579 	case BTF_EVNT_BT_QUERY_TXPWR:
10580 		if (ver->fwc2hfunc == 3 || ver->fwc2hfunc == 4)
10581 			return func;
10582 		else
10583 			return BTF_EVNT_MAX;
10584 	case BTF_EVNT_ZB_INFO:
10585 	case BTF_EVNT_ZB_CH:
10586 	case BTF_EVNT_ZB_QUERY_TXPWR:
10587 		if (ver->fwc2hfunc == 4)
10588 			return func;
10589 		else
10590 			return BTF_EVNT_MAX;
10591 	case BTF_EVNT_MAX:
10592 	default:
10593 		return BTF_EVNT_MAX;
10594 	}
10595 }
10596 
10597 void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
10598 			  u32 len, u8 class, u8 func)
10599 {
10600 	struct rtw89_btc *btc = &rtwdev->btc;
10601 	struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt0;
10602 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
10603 	u8 *buf = &skb->data[RTW89_C2H_HEADER_LEN];
10604 	u8 bid = BTC_BT_1ST;
10605 
10606 	len -= RTW89_C2H_HEADER_LEN;
10607 
10608 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
10609 		    "[BTC], %s(): C2H BT len:%d class:%d fun:%d\n",
10610 		    __func__, len, class, func);
10611 
10612 	if (class != BTFC_FW_EVENT)
10613 		return;
10614 
10615 	if (func & BT_C2H_FUNC_BT2ND) {
10616 		bid = BTC_BT_2ND;
10617 		func &= ~BT_C2H_FUNC_BT2ND;
10618 		bt = &btc->cx.bt1;
10619 	}
10620 
10621 	func = rtw89_btc_c2h_get_index_by_ver(rtwdev, func);
10622 	pfwinfo->cnt_c2h++;
10623 
10624 	switch (func) {
10625 	case BTF_EVNT_BUF_OVERFLOW:
10626 		pfwinfo->event[func]++;
10627 		break;
10628 	case BTF_EVNT_RPT:
10629 		pfwinfo->event[func]++;
10630 		/* Don't need rtw89_leave_ps_mode() */
10631 		btc_fw_event(rtwdev, func, buf, len);
10632 		break;
10633 	case BTF_EVNT_BT_INFO:
10634 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
10635 			    "[BTC], handle C2H BT INFO with data %8ph\n", buf);
10636 		bt->bcnt[BTC_BCNT_INFOUPDATE]++;
10637 		_update_bt_info(rtwdev, bid, buf, len);
10638 		break;
10639 	case BTF_EVNT_BT_SCBD:
10640 		bt->bcnt[BTC_BCNT_SCBDUPDATE]++;
10641 		bt->scbd_c2h = ((buf[3] << 24) | (buf[2] << 16) |
10642 				(buf[1] << 8) | (buf[0]));
10643 		bt->scbd_rb = bt->scbd_c2h;
10644 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
10645 			    "[BTC], handle C2H BT%d SCBD with data 0x%08x\n",
10646 			    bid, bt->scbd_c2h);
10647 		_update_bt_scbd(rtwdev, bid, true);
10648 		_run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
10649 		break;
10650 	case BTF_EVNT_BT_PSD:
10651 		break;
10652 	case BTF_EVNT_BT_REG:
10653 		btc->dbg.rb_done = true;
10654 		btc->dbg.rb_val = le32_to_cpu(*((__le32 *)buf));
10655 
10656 		break;
10657 	case BTF_EVNT_C2H_LOOPBACK:
10658 		btc->dbg.rb_done = true;
10659 		btc->dbg.rb_val = buf[0];
10660 		break;
10661 	case BTF_EVNT_CX_RUNINFO:
10662 		btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++;
10663 		break;
10664 	case BTF_EVNT_BT_LEAUDIO_INFO:
10665 		bt->bcnt[BTC_BCNT_LEAUDIO_INFOUPDATE]++;
10666 		if (buf[BTC_BTINFO_L0] == BTC_BTINFO_BISTDMA)
10667 			_update_bt_bistdma_info(rtwdev, bid, buf, len);
10668 		else
10669 			_update_bt_leaudio_info(rtwdev, bid, buf, len);
10670 		_run_coex(rtwdev, BTC_RSN_UPDATE_BT_LEAUDINFO);
10671 		break;
10672 	case BTF_EVNT_BT_QUERY_TXPWR:
10673 		bt->bcnt[BTC_BCNT_TXPWR_UPDATE]++;
10674 		_update_bt_txpwr_info(rtwdev, bid, buf, len);
10675 	}
10676 }
10677 
10678 #define BTC_CX_FW_OFFLOAD 0
10679 
10680 static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10681 {
10682 	struct rtw89_btc_module *md = &rtwdev->btc.mdinfo;
10683 	const struct rtw89_chip_info *chip = rtwdev->chip;
10684 	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
10685 	struct rtw89_hal *hal = &rtwdev->hal;
10686 	struct rtw89_btc *btc = &rtwdev->btc;
10687 	struct rtw89_btc_dm *dm = &btc->dm;
10688 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
10689 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
10690 	u32 ver_main = 0, ver_sub = 0, ver_hotfix = 0, id_branch = 0;
10691 	char *p = buf, *end = buf + bufsz;
10692 
10693 	if (!(dm->coex_info_map & BTC_COEX_INFO_CX))
10694 		return 0;
10695 
10696 	p += scnprintf(p, end - p,
10697 		       "\n========== [BTC COEX INFO (%s)] ==========\n",
10698 		       chip_id_str(chip->chip_id));
10699 
10700 	ver_main = FIELD_GET(GENMASK(31, 24), RTW89_COEX_VERSION);
10701 	ver_sub = FIELD_GET(GENMASK(23, 16), RTW89_COEX_VERSION);
10702 	ver_hotfix = FIELD_GET(GENMASK(15, 8), RTW89_COEX_VERSION);
10703 	id_branch = FIELD_GET(GENMASK(7, 0), RTW89_COEX_VERSION);
10704 	p += scnprintf(p, end - p, " %-15s : Coex:%d.%d.%d(branch:%d), ",
10705 		       "[coex_version]", ver_main, ver_sub, ver_hotfix,
10706 		       id_branch);
10707 
10708 	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw_coex);
10709 	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw_coex);
10710 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw_coex);
10711 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw_coex);
10712 	p += scnprintf(p, end - p, "WL_FW_coex:%d.%d.%d(branch:%d)",
10713 		       ver_main, ver_sub, ver_hotfix, id_branch);
10714 
10715 	ver_main = FIELD_GET(GENMASK(31, 24), chip->wlcx_desired);
10716 	ver_sub = FIELD_GET(GENMASK(23, 16), chip->wlcx_desired);
10717 	ver_hotfix = FIELD_GET(GENMASK(15, 8), chip->wlcx_desired);
10718 	p += scnprintf(p, end - p, "(%s, desired:%d.%d.%d), ",
10719 		       (wl->ver_info.fw_coex >= chip->wlcx_desired ?
10720 			"Match" : "Mismatch"), ver_main, ver_sub, ver_hotfix);
10721 
10722 	p += scnprintf(p, end - p, "BT_FW_coex:%d(%s, desired:%d)\n",
10723 		       bt->ver_info.fw_coex,
10724 		       (bt->ver_info.fw_coex >= ver->bt_desired ?
10725 			"Match" : "Mismatch"), ver->bt_desired);
10726 
10727 	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw);
10728 	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw);
10729 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw);
10730 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw);
10731 	p += scnprintf(p, end - p,
10732 		       " %-15s : WL_FW:%d.%d.%d.%d(built:%.12s-%.12s), BT_FW:0x%x(%s)\n",
10733 		       "[sub_module]",
10734 		       ver_main, ver_sub, ver_hotfix, id_branch,
10735 		       wl->ver_info.build_time, wl->ver_info.build_date,
10736 		       bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM");
10737 
10738 	p += scnprintf(p, end - p,
10739 		       " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s",
10740 		       "[hw_info]",
10741 		       md->kt_ver, md->rfe_type, md->ant.isolation,
10742 		       md->ant.num, md->ant.num > 1 ? "" :
10743 		       md->ant.single_pos ? "1Ant_Pos:S1, " : "1Ant_Pos:S0, ");
10744 
10745 	p += scnprintf(p, end - p,
10746 		       "3rd_coex:%d, dbcc:%d, tx_num:%d, rx_num:%d\n",
10747 		       btc->cx.bt_ext.func_type, rtwdev->dbcc_en, hal->tx_nss,
10748 		       hal->rx_nss);
10749 
10750 	return p - buf;
10751 }
10752 
10753 static int _show_wl_role_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10754 {
10755 	struct rtw89_btc *btc = &rtwdev->btc;
10756 	struct rtw89_btc_wl_link_info *plink = NULL;
10757 	struct rtw89_traffic_stats *t;
10758 	char *p = buf, *end = buf + bufsz;
10759 	u8 i, j;
10760 
10761 	for (i = 0; i < btc->ver->max_role_num; i++) {
10762 		for (j = 0; j < RTW89_MAC_NUM; j++) {
10763 			plink = &btc->cx.wl.rlink_info[i][j];
10764 
10765 			if (!plink->active)
10766 				continue;
10767 
10768 			p += scnprintf(p, end - p,
10769 				       " [port_%d]        : role=%d(phy-%d), connect=%s(client_cnt=%d), mode=%d, center_ch=%d, bw=%d",
10770 				       plink->pid, plink->role, plink->phy,
10771 				       id_to_mlme_state(plink->connected),
10772 				       plink->client_cnt - 1, plink->mode,
10773 				       plink->ch, plink->bw);
10774 
10775 			if (plink->connected == MLME_NO_LINK) {
10776 				p += scnprintf(p, end - p, "\n");
10777 				continue;
10778 			}
10779 
10780 			p += scnprintf(p, end - p,
10781 				       ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n",
10782 				       plink->mac_id, plink->tx_time, plink->tx_retry);
10783 
10784 			p += scnprintf(p, end - p,
10785 				       " [port_%d]        : rssi=-%ddBm(%d), busy=%d, dir=%s, ",
10786 				       plink->pid, 110 - plink->stat.rssi,
10787 				       plink->stat.rssi, plink->busy,
10788 				       plink->dir == RTW89_TFC_UL ? "UL" : "DL");
10789 
10790 			t = &plink->stat.traffic;
10791 
10792 			p += scnprintf(p, end - p,
10793 				       "tx[rate:%d/busy_level:%d], ",
10794 				       t->tx_rate, t->tx_tfc_lv);
10795 
10796 			p += scnprintf(p, end - p,
10797 				       "rx[rate:%d/busy_level:%d/drop:%d]\n",
10798 				       t->rx_rate,
10799 				       t->rx_tfc_lv, plink->rx_rate_drop_cnt);
10800 		}
10801 	}
10802 	return p - buf;
10803 }
10804 
10805 static int _show_wl_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10806 {
10807 	struct rtw89_btc *btc = &rtwdev->btc;
10808 	struct rtw89_btc_cx *cx = &btc->cx;
10809 	struct rtw89_btc_wl_info *wl = &cx->wl;
10810 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
10811 	struct rtw89_btc_wl_mlo_info *wl_minfo = &wl->mlo_info;
10812 	char *p = buf, *end = buf + bufsz;
10813 	u8 mode;
10814 
10815 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_WL))
10816 		return 0;
10817 
10818 	p += scnprintf(p, end - p, "========== [WL Status] ==========\n");
10819 
10820 	mode = wl_rinfo->link_mode[RTW89_MAC_0];
10821 
10822 	p += scnprintf(p, end - p, " %-15s : link_mode:%s(HWB0)/%s(HWB1), ", "[status]",
10823 		       id_to_linkmode(mode),
10824 		       id_to_linkmode(wl_rinfo->link_mode[RTW89_MAC_1]));
10825 
10826 	p += scnprintf(p, end - p,
10827 		       "rf_off:%d, power_save:%d, scan:%s(band:%d/phy_map:0x%x), ",
10828 		       wl->status.map.rf_off, wl->status.map.lps,
10829 		       wl->status.map.scan ? "Y" : "N",
10830 		       wl->scan_info.band[RTW89_PHY_0], wl->scan_info.phy_map);
10831 
10832 	p += scnprintf(p, end - p,
10833 		       "handshake:%s, roam:%s, 4way:%s, init_ok:%s\n",
10834 		       wl->status.map.handshake ? "Y" : "N",
10835 		       wl->status.map.roaming ?  "Y" : "N",
10836 		       wl->status.map._4way ? "Y" : "N",
10837 		       wl->status.map.init_ok ? "Y" : "N");
10838 
10839 	if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) {
10840 		p += scnprintf(p, end - p,
10841 			       " %-15s : type:%d/rf_comb:%d/dbcc_en:%d, ",
10842 			       "[MLO]", wl_minfo->wtype, wl_minfo->rf_combination,
10843 			       wl_rinfo->dbcc_en);
10844 		p += scnprintf(p, end - p,
10845 			       "HWB0(wmode:%d/ch:%d/rf_band:%d/p2p:%d), ",
10846 			       wl_minfo->wmode[RTW89_MAC_0],
10847 			       wl_minfo->ch_type[RTW89_MAC_0],
10848 			       wl_minfo->hwb_rf_band[RTW89_MAC_0],
10849 			       wl_rinfo->p2p_exist[RTW89_MAC_0]);
10850 		p += scnprintf(p, end - p,
10851 			       "HWB1(wmode:%d/ch:%d/rf_band:%d/p2p:%d)\n",
10852 			       wl_minfo->wmode[RTW89_MAC_1],
10853 			       wl_minfo->ch_type[RTW89_MAC_1],
10854 			       wl_minfo->hwb_rf_band[RTW89_MAC_1],
10855 			       wl_rinfo->p2p_exist[RTW89_MAC_1]);
10856 	}
10857 
10858 	p += _show_wl_role_info(rtwdev, p, end - p);
10859 
10860 	return p - buf;
10861 }
10862 
10863 enum btc_bt_a2dp_type {
10864 	BTC_A2DP_LEGACY = 0,
10865 	BTC_A2DP_TWS_SNIFF = 1,
10866 	BTC_A2DP_TWS_RELAY = 2,
10867 };
10868 
10869 static int _show_bt_profile_info(struct rtw89_dev *rtwdev, char *buf,
10870 				 size_t bufsz, u8 bid)
10871 {
10872 	struct rtw89_btc *btc = &rtwdev->btc;
10873 	struct rtw89_btc_bt_info *bt = (bid == BTC_BT_1ST) ?
10874 				       &btc->cx.bt0 : &btc->cx.bt1;
10875 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
10876 	struct rtw89_btc_bt_hfp_desc hfp = bt_linfo->hfp_desc;
10877 	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
10878 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
10879 	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
10880 	char *p = buf, *end = buf + bufsz;
10881 
10882 	if (hfp.exist) {
10883 		p += scnprintf(p, end - p,
10884 			       " %-15s : type:%s, sut_pwr:%d, golden-rx:%d",
10885 			       "[HFP]", (hfp.type == 0 ? "SCO" : "eSCO"),
10886 			       bt_linfo->sut_pwr_level[0],
10887 			       bt_linfo->golden_rx_shift[0]);
10888 	}
10889 
10890 	if (hid.exist) {
10891 		p += scnprintf(p, end - p,
10892 			       "\n %-15s : type:%s%s%s%s%s pair-cnt:%d, sut_pwr:%d, golden-rx:%d\n",
10893 			       "[HID]",
10894 			       hid.type & BTC_HID_218 ? "2/18," : "",
10895 			       hid.type & BTC_HID_418 ? "4/18," : "",
10896 			       hid.type & BTC_HID_BLE ? "BLE," : "",
10897 			       hid.type & BTC_HID_RCU ? "RCU," : "",
10898 			       hid.type & BTC_HID_RCU_VOICE ? "RCU-Voice," : "",
10899 			       hid.pair_cnt, bt_linfo->sut_pwr_level[1],
10900 			       bt_linfo->golden_rx_shift[1]);
10901 	}
10902 
10903 	if (a2dp.exist) {
10904 		p += scnprintf(p, end - p,
10905 			       " %-15s : type:%s, bit-pool:%d, flush-time:%d, ",
10906 			       "[A2DP]",
10907 			       a2dp.type == BTC_A2DP_LEGACY ? "Legacy" : "TWS",
10908 			       a2dp.bitpool, a2dp.flush_time);
10909 
10910 		p += scnprintf(p, end - p,
10911 			       "vid:0x%x, Dev-name:0x%x, sut_pwr:%d, golden-rx:%d\n",
10912 			       a2dp.vendor_id, a2dp.device_name,
10913 			       bt_linfo->sut_pwr_level[2],
10914 			       bt_linfo->golden_rx_shift[2]);
10915 	}
10916 
10917 	if (pan.exist) {
10918 		p += scnprintf(p, end - p,
10919 			       " %-15s : sut_pwr:%d, golden-rx:%d\n",
10920 			       "[PAN]",
10921 			       bt_linfo->sut_pwr_level[3],
10922 			       bt_linfo->golden_rx_shift[3]);
10923 	}
10924 
10925 	return p - buf;
10926 }
10927 
10928 static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz, u8 bid)
10929 {
10930 	struct rtw89_btc *btc = &rtwdev->btc;
10931 	const struct rtw89_btc_ver *ver = btc->ver;
10932 	struct rtw89_btc_cx *cx = &btc->cx;
10933 	struct rtw89_btc_bt_info *bt = (bid == BTC_BT_1ST) ? &cx->bt0 : &cx->bt1;
10934 	struct rtw89_btc_wl_info *wl = &cx->wl;
10935 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
10936 	struct rtw89_btc_module *md = &btc->mdinfo;
10937 	u8 bt_pos = (bid == BTC_BT_1ST) ? md->bt0_pos : md->bt1_pos;
10938 	s8 br_dbm = bt->link_info.bt_txpwr_desc.br_dbm;
10939 	s8 le_dbm = bt->link_info.bt_txpwr_desc.le_dbm;
10940 	u8 hw_band = wl->role_info.pta_req_band;
10941 	struct rtw89_btc_wl_afh_info *wl_afh;
10942 	char *p = buf, *end = buf + bufsz;
10943 	u8 *afh = bt_linfo->afh_map;
10944 	u8 *afh_le = bt_linfo->afh_map_le;
10945 
10946 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT))
10947 		return 0;
10948 
10949 	if (bid == BTC_BT_2ND) {
10950 		if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT))
10951 			return 0;
10952 		if (!bt->enable.now)
10953 			return 0;
10954 	}
10955 
10956 	p += scnprintf(p, end - p, "========== [BT_%s Status] ==========\n",
10957 		       bid == BTC_BT_1ST ? "1ST" : "2ND");
10958 
10959 	p += scnprintf(p, end - p,
10960 		       " %-15s : enable:%s, btg:%s%s, connect:%s, ",
10961 		       "[status]", bt->enable.now ? "Y" : "N",
10962 		       bt->btg_type ? "Y" : "N",
10963 		       (bt->enable.now && (bt->btg_type != bt_pos) ?
10964 			"(efuse-mismatch!!)" : ""),
10965 		       (bt_linfo->status.map.connect ? "Y" : "N"));
10966 
10967 	p += scnprintf(p, end - p,
10968 		       "igno_wl:%s, mailbox_avl:%s, rfk_state:0x%x\n",
10969 		       bt->igno_wl ? "Y" : "N",
10970 		       bt->mbx_avl ? "Y" : "N", bt->rfk_info.val);
10971 
10972 	p += scnprintf(p, end - p, " %-15s : profile:%s%s%s%s%s ",
10973 		       "[profile]",
10974 		       (bt_linfo->link_cnt.now == 0) ? "None," : "",
10975 		       bt_linfo->hfp_desc.exist ? "HFP," : "",
10976 		       bt_linfo->hid_desc.exist ? "HID," : "",
10977 		       bt_linfo->a2dp_desc.exist ?
10978 		       (bt_linfo->a2dp_desc.sink ? "A2DP_sink," : "A2DP,") : "",
10979 		       bt_linfo->pan_desc.exist ? "PAN," : "");
10980 
10981 	p += scnprintf(p, end - p,
10982 		       "multi-link:%s, role:%s, ble-connect:%s, CQDDR:%s, A2DP_active:%s, PAN_active:%s\n",
10983 		       bt_linfo->multi_link.now ? "Y" : "N",
10984 		       bt_linfo->slave_role ? "Slave" : "Master",
10985 		       bt_linfo->status.map.ble_connect ? "Y" : "N",
10986 		       bt_linfo->cqddr ? "Y" : "N",
10987 		       bt_linfo->a2dp_desc.active ? "Y" : "N",
10988 		       bt_linfo->pan_desc.active ? "Y" : "N");
10989 
10990 	p += scnprintf(p, end - p,
10991 		       " %-15s : rssi:%ddBm(lvl:%d), tx_rate:%dM, %s%s%s",
10992 		       "[link]", bt_linfo->rssi - 100,
10993 		       bt->rssi_level,
10994 		       bt_linfo->tx_3m ? 3 : 2,
10995 		       bt_linfo->status.map.inq_pag ? " inq-page!!" : "",
10996 		       bt_linfo->status.map.acl_busy ? " acl_busy!!" : "",
10997 		       bt_linfo->status.map.mesh_busy ? " mesh_busy!!" : "");
10998 
10999 	p += scnprintf(p, end - p,
11000 		       "%s afh_map[%02x%02x_%02x%02x_%02x%02x_%02x%02x_%02x%02x], ",
11001 		       bt_linfo->relink.now ? " ReLink!!" : "",
11002 		       afh[0], afh[1], afh[2], afh[3], afh[4],
11003 		       afh[5], afh[6], afh[7], afh[8], afh[9]);
11004 
11005 	if (ver->fcxbtafh == 2 && bt_linfo->status.map.ble_connect)
11006 		p += scnprintf(p, end - p,
11007 			       "LE[%02x%02x_%02x_%02x%02x]",
11008 			       afh_le[0], afh_le[1], afh_le[2],
11009 			       afh_le[3], afh_le[4]);
11010 
11011 	wl_afh = &wl->afh_info[hw_band][RTW89_BAND_2G];
11012 	p += scnprintf(p, end - p, "wl_ch_map[hwb:%d/en:%d/ch:%d/bw:%d/rf_band:%d]\n",
11013 		       hw_band, wl_afh->en, wl_afh->ch, wl_afh->bw, wl_afh->band);
11014 
11015 	p += scnprintf(p, end - p,
11016 		       " %-15s : retry:%d, relink:%d, rate_chg:%d, reinit:%d, reenable:%d, ",
11017 		       "[stat_cnt]", bt->bcnt[BTC_BCNT_RETRY],
11018 		       bt->bcnt[BTC_BCNT_RELINK],
11019 		       bt->bcnt[BTC_BCNT_RATECHG],
11020 		       bt->bcnt[BTC_BCNT_REINIT],
11021 		       bt->bcnt[BTC_BCNT_REENABLE]);
11022 
11023 	p += scnprintf(p, end - p,
11024 		       "role-switch:%d, afh:%d, inq_page:%d(inq:%d/page:%d), igno_wl:%d\n",
11025 		       bt->bcnt[BTC_BCNT_ROLESW], bt->bcnt[BTC_BCNT_AFH],
11026 		       bt->bcnt[BTC_BCNT_INQPAG], bt->bcnt[BTC_BCNT_INQ],
11027 		       bt->bcnt[BTC_BCNT_PAGE], bt->bcnt[BTC_BCNT_IGNOWL]);
11028 
11029 	p += _show_bt_profile_info(rtwdev, p, end - p, bid);
11030 
11031 	p += scnprintf(p, end - p,
11032 		       " %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)\n",
11033 		       "[bt_info]", bt->raw_info[2], bt->raw_info[3],
11034 		       bt->raw_info[4], bt->raw_info[5], bt->raw_info[6],
11035 		       bt->raw_info[7],
11036 		       bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply",
11037 		       bt->bcnt[BTC_BCNT_INFOUPDATE],
11038 		       bt->bcnt[BTC_BCNT_INFOSAME]);
11039 
11040 	p += scnprintf(p, end - p,
11041 		       " %-15s : Hi-rx = %d, Hi-tx = %d, Lo-rx = %d, Lo-tx = %d (bt_polut_wl_tx = %d)",
11042 		       "[trx_req_cnt]", bt->bcnt[BTC_BCNT_HIPRI_RX],
11043 		       bt->bcnt[BTC_BCNT_HIPRI_TX],
11044 		       bt->bcnt[BTC_BCNT_LOPRI_RX],
11045 		       bt->bcnt[BTC_BCNT_LOPRI_TX],
11046 		       bt->bcnt[BTC_BCNT_POLLUTED]);
11047 
11048 	if (ver->fcxbtscan == 1) {
11049 		p += scnprintf(p, end - p,
11050 			       "(INQ:%d-%d/PAGE:%d-%d/LE:%d-%d/INIT:%d-%d)",
11051 			       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_INQ].win),
11052 			       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_INQ].intvl),
11053 			       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_PAGE].win),
11054 			       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_PAGE].intvl),
11055 			       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_BLE].win),
11056 			       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_BLE].intvl),
11057 			       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_INIT].win),
11058 			       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_INIT].intvl));
11059 	} else if (ver->fcxbtscan == 2) {
11060 		p += scnprintf(p, end - p,
11061 			       "(BG:%d-%d/INIT:%d-%d/LE:%d-%d)",
11062 			       le16_to_cpu(bt->scan_info_v2[CXSCAN_BG].win),
11063 			       le16_to_cpu(bt->scan_info_v2[CXSCAN_BG].intvl),
11064 			       le16_to_cpu(bt->scan_info_v2[CXSCAN_INIT].win),
11065 			       le16_to_cpu(bt->scan_info_v2[CXSCAN_INIT].intvl),
11066 			       le16_to_cpu(bt->scan_info_v2[CXSCAN_LE].win),
11067 			       le16_to_cpu(bt->scan_info_v2[CXSCAN_LE].intvl));
11068 	}
11069 	p += scnprintf(p, end - p, "\n");
11070 
11071 	if (bt->bcnt[BTC_BCNT_TXPWR_UPDATE]) {
11072 		p += scnprintf(p, end - p,
11073 			       " %-15s : br_index:0x%x, le_index:0x%x",
11074 			       "[bt_txpwr_lvl]",
11075 			       bt->link_info.bt_txpwr_desc.br_gain_index,
11076 			       bt->link_info.bt_txpwr_desc.le_gain_index);
11077 		p += scnprintf(p, end - p, ", br_dbm:%d dBm", br_dbm);
11078 		p += scnprintf(p, end - p, ", le_dbm:%d dBm", le_dbm);
11079 	} else {
11080 		p += scnprintf(p, end - p,
11081 			       " %-15s : br_index:NA, le_index:NA, br_dbm:%d dBm[def], le_dbm:%d dBm[def]",
11082 			       "[bt_txpwr_lvl]",
11083 			       bt->link_info.bt_txpwr_desc.br_dbm,
11084 			       bt->link_info.bt_txpwr_desc.le_dbm);
11085 	}
11086 	p += scnprintf(p, end - p, "\n");
11087 
11088 	return p - buf;
11089 }
11090 
11091 #define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e
11092 #define CASE_BTC_ACT_STR(e) case BTC_ACT_ ## e | BTC_ACT_EXT_BIT: return #e
11093 #define CASE_BTC_POLICY_STR(e) \
11094 	case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e
11095 #define CASE_BTC_SLOT_STR(e) case CXST_ ## e: return #e
11096 #define CASE_BTC_EVT_STR(e) case CXEVNT_## e: return #e
11097 #define CASE_BTC_INIT(e) case BTC_MODE_## e: return #e
11098 #define CASE_BTC_ANTPATH_STR(e) case BTC_ANT_##e: return #e
11099 #define CASE_BTC_POLUT_STR(e) case BTC_PLT_## e: return #e
11100 #define CASE_BTC_REGTYPE_STR(e) case REG_## e: return #e
11101 #define CASE_BTC_GDBG_STR(e) case BTC_DBG_## e: return #e
11102 #define CASE_BTC_H2CCMD(e) case SET_##e: return #e
11103 
11104 static const char *id_to_polut(u32 id)
11105 {
11106 	switch (id) {
11107 	CASE_BTC_POLUT_STR(NONE);
11108 	CASE_BTC_POLUT_STR(GNT_BT_TX);
11109 	CASE_BTC_POLUT_STR(GNT_BT_RX);
11110 	CASE_BTC_POLUT_STR(GNT_WL);
11111 	CASE_BTC_POLUT_STR(BT);
11112 	CASE_BTC_POLUT_STR(ALL);
11113 	default:
11114 		return "unknown";
11115 	}
11116 }
11117 
11118 static const char *id_to_regtype(u32 id)
11119 {
11120 	switch (id) {
11121 	CASE_BTC_REGTYPE_STR(MAC);
11122 	CASE_BTC_REGTYPE_STR(BB);
11123 	CASE_BTC_REGTYPE_STR(RF);
11124 	CASE_BTC_REGTYPE_STR(BT_RF);
11125 	CASE_BTC_REGTYPE_STR(BT_MODEM);
11126 	CASE_BTC_REGTYPE_STR(BT_BLUEWIZE);
11127 	CASE_BTC_REGTYPE_STR(BT_VENDOR);
11128 	CASE_BTC_REGTYPE_STR(BT_LE);
11129 	default:
11130 		return "unknown";
11131 	}
11132 }
11133 
11134 static const char *id_to_gdbg(u32 id)
11135 {
11136 	switch (id) {
11137 	CASE_BTC_GDBG_STR(GNT_BT);
11138 	CASE_BTC_GDBG_STR(GNT_WL);
11139 	CASE_BTC_GDBG_STR(GNT_BT1);
11140 	CASE_BTC_GDBG_STR(GNT_WL1);
11141 	CASE_BTC_GDBG_STR(BCN_EARLY);
11142 	CASE_BTC_GDBG_STR(WL_NULL0);
11143 	CASE_BTC_GDBG_STR(WL_NULL1);
11144 	CASE_BTC_GDBG_STR(WL_RXISR);
11145 	CASE_BTC_GDBG_STR(TDMA_ENTRY);
11146 	CASE_BTC_GDBG_STR(A2DP_EMPTY);
11147 	CASE_BTC_GDBG_STR(BT_RETRY);
11148 	CASE_BTC_GDBG_STR(BT_RELINK);
11149 	CASE_BTC_GDBG_STR(SLOT_WL);
11150 	CASE_BTC_GDBG_STR(SLOT_BT);
11151 	CASE_BTC_GDBG_STR(WL_ERR);
11152 	CASE_BTC_GDBG_STR(WL_OK);
11153 	CASE_BTC_GDBG_STR(SLOT_B2W);
11154 	CASE_BTC_GDBG_STR(SLOT_W1);
11155 	CASE_BTC_GDBG_STR(SLOT_W2);
11156 	CASE_BTC_GDBG_STR(SLOT_W2B);
11157 	CASE_BTC_GDBG_STR(SLOT_B1);
11158 	CASE_BTC_GDBG_STR(SLOT_B2);
11159 	CASE_BTC_GDBG_STR(SLOT_B3);
11160 	CASE_BTC_GDBG_STR(SLOT_B4);
11161 	CASE_BTC_GDBG_STR(SLOT_LK);
11162 	CASE_BTC_GDBG_STR(SLOT_E2G);
11163 	CASE_BTC_GDBG_STR(SLOT_E5G);
11164 	CASE_BTC_GDBG_STR(SLOT_EBT);
11165 	CASE_BTC_GDBG_STR(SLOT_WLK);
11166 	CASE_BTC_GDBG_STR(SLOT_B1FDD);
11167 	CASE_BTC_GDBG_STR(BT_CHANGE);
11168 	CASE_BTC_GDBG_STR(WL_CCA);
11169 	default:
11170 		return "unknown";
11171 	}
11172 }
11173 
11174 static const char *steps_to_str(u16 step)
11175 {
11176 	switch (step) {
11177 	CASE_BTC_RSN_STR(NONE);
11178 	CASE_BTC_RSN_STR(NTFY_INIT);
11179 	CASE_BTC_RSN_STR(NTFY_SWBAND);
11180 	CASE_BTC_RSN_STR(NTFY_WL_STA);
11181 	CASE_BTC_RSN_STR(NTFY_RADIO_STATE);
11182 	CASE_BTC_RSN_STR(UPDATE_BT_SCBD);
11183 	CASE_BTC_RSN_STR(NTFY_WL_RFK);
11184 	CASE_BTC_RSN_STR(UPDATE_BT_INFO);
11185 	CASE_BTC_RSN_STR(NTFY_SCAN_START);
11186 	CASE_BTC_RSN_STR(NTFY_SCAN_FINISH);
11187 	CASE_BTC_RSN_STR(NTFY_SPECIFIC_PACKET);
11188 	CASE_BTC_RSN_STR(NTFY_POWEROFF);
11189 	CASE_BTC_RSN_STR(NTFY_ROLE_INFO);
11190 	CASE_BTC_RSN_STR(CMD_SET_COEX);
11191 	CASE_BTC_RSN_STR(ACT1_WORK);
11192 	CASE_BTC_RSN_STR(BT_DEVINFO_WORK);
11193 	CASE_BTC_RSN_STR(RFK_CHK_WORK);
11194 	CASE_BTC_RSN_STR(UPDATE_BT_LEAUDINFO);
11195 
11196 	CASE_BTC_ACT_STR(NONE);
11197 	CASE_BTC_ACT_STR(WL_ONLY);
11198 	CASE_BTC_ACT_STR(WL_5G);
11199 	CASE_BTC_ACT_STR(WL_OTHER);
11200 	CASE_BTC_ACT_STR(WL_IDLE);
11201 	CASE_BTC_ACT_STR(WL_NC);
11202 	CASE_BTC_ACT_STR(WL_RFK);
11203 	CASE_BTC_ACT_STR(WL_INIT);
11204 	CASE_BTC_ACT_STR(WL_OFF);
11205 	CASE_BTC_ACT_STR(FREERUN);
11206 	CASE_BTC_ACT_STR(BT_WHQL);
11207 	CASE_BTC_ACT_STR(BT_RFK);
11208 	CASE_BTC_ACT_STR(BT_OFF);
11209 	CASE_BTC_ACT_STR(BT_IDLE);
11210 	CASE_BTC_ACT_STR(BT_HFP);
11211 	CASE_BTC_ACT_STR(BT_HID);
11212 	CASE_BTC_ACT_STR(BT_A2DP);
11213 	CASE_BTC_ACT_STR(BT_A2DPSINK);
11214 	CASE_BTC_ACT_STR(BT_PAN);
11215 	CASE_BTC_ACT_STR(BT_A2DP_HID);
11216 	CASE_BTC_ACT_STR(BT_A2DP_PAN);
11217 	CASE_BTC_ACT_STR(BT_PAN_HID);
11218 	CASE_BTC_ACT_STR(BT_A2DP_PAN_HID);
11219 	CASE_BTC_ACT_STR(BT_BIS);
11220 	CASE_BTC_ACT_STR(BT_CIS);
11221 	CASE_BTC_ACT_STR(WL_25G_MCC);
11222 	CASE_BTC_ACT_STR(WL_2G_MCC);
11223 	CASE_BTC_ACT_STR(WL_2G_SCC);
11224 	CASE_BTC_ACT_STR(WL_2G_AP);
11225 	CASE_BTC_ACT_STR(WL_2G_GO);
11226 	CASE_BTC_ACT_STR(WL_2G_GC);
11227 	CASE_BTC_ACT_STR(WL_2G_NAN);
11228 
11229 	CASE_BTC_POLICY_STR(OFF_BT);
11230 	CASE_BTC_POLICY_STR(OFF_WL);
11231 	CASE_BTC_POLICY_STR(OFF_EQ0);
11232 	CASE_BTC_POLICY_STR(OFF_EQ1);
11233 	CASE_BTC_POLICY_STR(OFF_EQ2);
11234 	CASE_BTC_POLICY_STR(OFF_EQ3);
11235 	CASE_BTC_POLICY_STR(OFF_EQ4);
11236 	CASE_BTC_POLICY_STR(OFF_EQ5);
11237 	CASE_BTC_POLICY_STR(OFF_BWB0);
11238 	CASE_BTC_POLICY_STR(OFF_BWB1);
11239 	CASE_BTC_POLICY_STR(OFF_BWB2);
11240 	CASE_BTC_POLICY_STR(OFF_BWB3);
11241 	CASE_BTC_POLICY_STR(OFF_WL2);
11242 	CASE_BTC_POLICY_STR(OFFB_BWB0);
11243 	CASE_BTC_POLICY_STR(OFFE_DEF);
11244 	CASE_BTC_POLICY_STR(OFFE_DEF2);
11245 	CASE_BTC_POLICY_STR(OFFE_2GBWISOB);
11246 	CASE_BTC_POLICY_STR(OFFE_2GISOB);
11247 	CASE_BTC_POLICY_STR(OFFE_2GBWMIXB);
11248 	CASE_BTC_POLICY_STR(OFFE_WL);
11249 	CASE_BTC_POLICY_STR(OFFE_2GBWMIXB2);
11250 	CASE_BTC_POLICY_STR(FIX_TD3030);
11251 	CASE_BTC_POLICY_STR(FIX_TD5050);
11252 	CASE_BTC_POLICY_STR(FIX_TD2030);
11253 	CASE_BTC_POLICY_STR(FIX_TD4010);
11254 	CASE_BTC_POLICY_STR(FIX_TD7010);
11255 	CASE_BTC_POLICY_STR(FIX_TD2060);
11256 	CASE_BTC_POLICY_STR(FIX_TD3060);
11257 	CASE_BTC_POLICY_STR(FIX_TD2080);
11258 	CASE_BTC_POLICY_STR(FIX_TDW1B1);
11259 	CASE_BTC_POLICY_STR(FIX_TD4010ISO);
11260 	CASE_BTC_POLICY_STR(FIX_TD4010ISO_DL);
11261 	CASE_BTC_POLICY_STR(FIX_TD4010ISO_UL);
11262 	CASE_BTC_POLICY_STR(PFIX_TD3030);
11263 	CASE_BTC_POLICY_STR(PFIX_TD5050);
11264 	CASE_BTC_POLICY_STR(PFIX_TD2030);
11265 	CASE_BTC_POLICY_STR(PFIX_TD2060);
11266 	CASE_BTC_POLICY_STR(PFIX_TD3070);
11267 	CASE_BTC_POLICY_STR(PFIX_TD2080);
11268 	CASE_BTC_POLICY_STR(PFIX_TDW1B1);
11269 	CASE_BTC_POLICY_STR(AUTO_TD50B1);
11270 	CASE_BTC_POLICY_STR(AUTO_TD60B1);
11271 	CASE_BTC_POLICY_STR(AUTO_TD20B1);
11272 	CASE_BTC_POLICY_STR(AUTO_TDW1B1);
11273 	CASE_BTC_POLICY_STR(PAUTO_TD50B1);
11274 	CASE_BTC_POLICY_STR(PAUTO_TD60B1);
11275 	CASE_BTC_POLICY_STR(PAUTO_TD20B1);
11276 	CASE_BTC_POLICY_STR(PAUTO_TDW1B1);
11277 	CASE_BTC_POLICY_STR(AUTO2_TD3050);
11278 	CASE_BTC_POLICY_STR(AUTO2_TD3070);
11279 	CASE_BTC_POLICY_STR(AUTO2_TD5050);
11280 	CASE_BTC_POLICY_STR(AUTO2_TD6060);
11281 	CASE_BTC_POLICY_STR(AUTO2_TD2080);
11282 	CASE_BTC_POLICY_STR(AUTO2_TDW1B4);
11283 	CASE_BTC_POLICY_STR(PAUTO2_TD3050);
11284 	CASE_BTC_POLICY_STR(PAUTO2_TD3070);
11285 	CASE_BTC_POLICY_STR(PAUTO2_TD5050);
11286 	CASE_BTC_POLICY_STR(PAUTO2_TD6060);
11287 	CASE_BTC_POLICY_STR(PAUTO2_TD2080);
11288 	CASE_BTC_POLICY_STR(PAUTO2_TDW1B4);
11289 	default:
11290 		return "unknown step";
11291 	}
11292 }
11293 
11294 static const char *id_to_slot(u32 id)
11295 {
11296 	switch (id) {
11297 	CASE_BTC_SLOT_STR(OFF);
11298 	CASE_BTC_SLOT_STR(B2W);
11299 	CASE_BTC_SLOT_STR(W1);
11300 	CASE_BTC_SLOT_STR(W2);
11301 	CASE_BTC_SLOT_STR(W2B);
11302 	CASE_BTC_SLOT_STR(B1);
11303 	CASE_BTC_SLOT_STR(B2);
11304 	CASE_BTC_SLOT_STR(B3);
11305 	CASE_BTC_SLOT_STR(B4);
11306 	CASE_BTC_SLOT_STR(LK);
11307 	CASE_BTC_SLOT_STR(BLK);
11308 	CASE_BTC_SLOT_STR(E2G);
11309 	CASE_BTC_SLOT_STR(E5G);
11310 	CASE_BTC_SLOT_STR(EBT);
11311 	CASE_BTC_SLOT_STR(ENULL);
11312 	CASE_BTC_SLOT_STR(WLK);
11313 	CASE_BTC_SLOT_STR(W1FDD);
11314 	CASE_BTC_SLOT_STR(B1FDD);
11315 	default:
11316 		return "unknown";
11317 	}
11318 }
11319 
11320 static const char *id_to_evt(u32 id)
11321 {
11322 	switch (id) {
11323 	CASE_BTC_EVT_STR(TDMA_ENTRY);
11324 	CASE_BTC_EVT_STR(WL_TMR);
11325 	CASE_BTC_EVT_STR(B1_TMR);
11326 	CASE_BTC_EVT_STR(B2_TMR);
11327 	CASE_BTC_EVT_STR(B3_TMR);
11328 	CASE_BTC_EVT_STR(B4_TMR);
11329 	CASE_BTC_EVT_STR(W2B_TMR);
11330 	CASE_BTC_EVT_STR(B2W_TMR);
11331 	CASE_BTC_EVT_STR(BCN_EARLY);
11332 	CASE_BTC_EVT_STR(A2DP_EMPTY);
11333 	CASE_BTC_EVT_STR(LK_END);
11334 	CASE_BTC_EVT_STR(RX_ISR);
11335 	CASE_BTC_EVT_STR(RX_FC0);
11336 	CASE_BTC_EVT_STR(RX_FC1);
11337 	CASE_BTC_EVT_STR(BT_RELINK);
11338 	CASE_BTC_EVT_STR(BT_RETRY);
11339 	CASE_BTC_EVT_STR(E2G);
11340 	CASE_BTC_EVT_STR(E5G);
11341 	CASE_BTC_EVT_STR(EBT);
11342 	CASE_BTC_EVT_STR(ENULL);
11343 	CASE_BTC_EVT_STR(DRV_WLK);
11344 	CASE_BTC_EVT_STR(BCN_OK);
11345 	CASE_BTC_EVT_STR(BT_CHANGE);
11346 	CASE_BTC_EVT_STR(EBT_EXTEND);
11347 	CASE_BTC_EVT_STR(E2G_NULL1);
11348 	CASE_BTC_EVT_STR(B1FDD_TMR);
11349 	default:
11350 		return "unknown";
11351 	}
11352 }
11353 
11354 static const char *id_to_mode(u8 id)
11355 {
11356 	switch (id) {
11357 	CASE_BTC_INIT(NORMAL);
11358 	CASE_BTC_INIT(WL);
11359 	CASE_BTC_INIT(BT);
11360 	CASE_BTC_INIT(WLOFF);
11361 	default:
11362 		return "unknown";
11363 	}
11364 }
11365 
11366 static const char *id_to_ant(u32 id)
11367 {
11368 	switch (id) {
11369 	CASE_BTC_ANTPATH_STR(WPOWERON);
11370 	CASE_BTC_ANTPATH_STR(WINIT);
11371 	CASE_BTC_ANTPATH_STR(WONLY);
11372 	CASE_BTC_ANTPATH_STR(WOFF);
11373 	CASE_BTC_ANTPATH_STR(W2G);
11374 	CASE_BTC_ANTPATH_STR(FDD);
11375 	CASE_BTC_ANTPATH_STR(W25G);
11376 	CASE_BTC_ANTPATH_STR(FREERUN);
11377 	CASE_BTC_ANTPATH_STR(WRFK);
11378 	CASE_BTC_ANTPATH_STR(WRFK2);
11379 	CASE_BTC_ANTPATH_STR(PTA);
11380 	CASE_BTC_ANTPATH_STR(MAX);
11381 	default:
11382 		return "unknown";
11383 	}
11384 }
11385 
11386 static const char *id_to_h2c(u32 id)
11387 {
11388 	switch (id) {
11389 	CASE_BTC_H2CCMD(REPORT_EN);
11390 	CASE_BTC_H2CCMD(SLOT_TABLE);
11391 	CASE_BTC_H2CCMD(MREG_TABLE);
11392 	CASE_BTC_H2CCMD(CX_POLICY);
11393 	CASE_BTC_H2CCMD(GPIO_DBG);
11394 	CASE_BTC_H2CCMD(DRV_INFO);
11395 	CASE_BTC_H2CCMD(DRV_EVENT);
11396 	CASE_BTC_H2CCMD(BT_WREG_ADDR);
11397 	CASE_BTC_H2CCMD(BT_WREG_VAL);
11398 	CASE_BTC_H2CCMD(BT_RREG_ADDR);
11399 	CASE_BTC_H2CCMD(BT_WL_CH_INFO);
11400 	CASE_BTC_H2CCMD(BT_INFO_REPORT);
11401 	CASE_BTC_H2CCMD(BT_IGNORE_WLAN_ACT);
11402 	CASE_BTC_H2CCMD(BT_TX_PWR);
11403 	CASE_BTC_H2CCMD(BT_LNA_CONSTRAIN);
11404 	CASE_BTC_H2CCMD(BT_QUERY_DEV_LIST);
11405 	CASE_BTC_H2CCMD(BT_QUERY_DEV_INFO);
11406 	CASE_BTC_H2CCMD(BT_PSD_REPORT);
11407 	CASE_BTC_H2CCMD(H2C_TEST);
11408 	CASE_BTC_H2CCMD(IOFLD_RF);
11409 	CASE_BTC_H2CCMD(IOFLD_BB);
11410 	CASE_BTC_H2CCMD(IOFLD_MAC);
11411 	CASE_BTC_H2CCMD(IOFLD_SCBD);
11412 	CASE_BTC_H2CCMD(H2C_MACRO);
11413 	default:
11414 		return "unknown";
11415 	}
11416 }
11417 
11418 static
11419 int scnprintf_segment(char *buf, size_t bufsz, const char *prefix, const u16 *data,
11420 		      u8 len, u8 seg_len, u8 start_idx, u8 ring_len)
11421 {
11422 	char *p = buf, *end = buf + bufsz;
11423 	u8 cur_index;
11424 	u8 i;
11425 
11426 	for (i = 0; i < len ; i++) {
11427 		if ((i % seg_len) == 0)
11428 			p += scnprintf(p, end - p, " %-15s : ", prefix);
11429 		cur_index = (start_idx + i) % ring_len;
11430 		if (i % 3 == 0)
11431 			p += scnprintf(p, end - p, "-> %-20s",
11432 				       steps_to_str(*(data + cur_index)));
11433 		else if (i % 3 == 1)
11434 			p += scnprintf(p, end - p, "-> %-15s",
11435 				       steps_to_str(*(data + cur_index)));
11436 		else
11437 			p += scnprintf(p, end - p, "-> %-13s",
11438 				       steps_to_str(*(data + cur_index)));
11439 		if (i == (len - 1) || (i % seg_len) == (seg_len - 1))
11440 			p += scnprintf(p, end - p, "\n");
11441 	}
11442 
11443 	return p - buf;
11444 }
11445 
11446 static int _show_dm_step(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11447 {
11448 	struct rtw89_btc *btc = &rtwdev->btc;
11449 	struct rtw89_btc_dm *dm = &btc->dm;
11450 	char *p = buf, *end = buf + bufsz;
11451 	u8 start_idx;
11452 	u8 len;
11453 
11454 	len = dm->dm_step.step_ov ? RTW89_BTC_DM_MAXSTEP : dm->dm_step.step_pos;
11455 	start_idx = dm->dm_step.step_ov ? dm->dm_step.step_pos : 0;
11456 
11457 	p += scnprintf_segment(p, end - p, "[dm_steps]", dm->dm_step.step, len,
11458 			       6, start_idx, ARRAY_SIZE(dm->dm_step.step));
11459 
11460 	return p - buf;
11461 }
11462 
11463 static int _show_dm_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11464 {
11465 	struct rtw89_btc *btc = &rtwdev->btc;
11466 	struct rtw89_btc_dm *dm = &btc->dm;
11467 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
11468 	struct rtw89_btc_bt_info *bt = &btc->cx.bt0;
11469 	char *p = buf, *end = buf + bufsz;
11470 
11471 	if (!(dm->coex_info_map & BTC_COEX_INFO_DM))
11472 		return 0;
11473 
11474 	p += scnprintf(p, end - p,
11475 		       "========== [Mechanism Status %s] ==========\n",
11476 		       (btc->manual_ctrl ? "(Manual)" : "(Auto)"));
11477 
11478 	p += scnprintf(p, end - p,
11479 		       " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%s, init_mode:%s, run_cnt:%d\n",
11480 		       "[status]",
11481 		       btc->ant_type == BTC_ANT_SHARED ? "shared" : "dedicated",
11482 		       steps_to_str(dm->run_reason),
11483 		       steps_to_str(dm->run_action | BTC_ACT_EXT_BIT),
11484 		       id_to_ant(FIELD_GET(GENMASK(7, 0), dm->set_ant_path)),
11485 		       id_to_mode(wl->coex_mode),
11486 		       dm->cnt_dm[BTC_DCNT_RUN]);
11487 
11488 	p += _show_dm_step(rtwdev, p, end - p);
11489 
11490 	p += scnprintf(p, end - p,
11491 		       " %-15s : wl_only:%d, bt_only:%d, igno_bt:%d, free_run:%d, wl_ps_ctrl:%d, wl_mimo_ps:%d, ",
11492 		       "[dm_flag]", dm->wl_only, dm->bt_only, btc->ctrl.igno_bt,
11493 		       dm->freerun, btc->btc_ctrl_lps, dm->wl_mimo_ps);
11494 
11495 	p += scnprintf(p, end - p, "leak_ap:%d, fw_offload:%s%s\n",
11496 		       dm->leak_ap,
11497 		       (BTC_CX_FW_OFFLOAD ? "Y" : "N"),
11498 		       (dm->wl_fw_cx_offload == BTC_CX_FW_OFFLOAD ?
11499 			"" : "(Mismatch!!)"));
11500 
11501 	p += scnprintf(p, end - p,
11502 		       " %-15s : wl[rssi_lvl:%d/para:%d/tx_pwr:[%d %d]/rx_lvl:[%d %d]/lna2:%d/stb_chg:%d]\n",
11503 		       "[dm_rf_ctrl]",
11504 		       wl->rssi_level, dm->trx_para_level,
11505 		       dm->rf_trx_para.wl_tx_power[RTW89_PHY_0],
11506 		       dm->rf_trx_para.wl_tx_power[RTW89_PHY_1],
11507 		       dm->rf_trx_para.wl_rx_gain[RTW89_PHY_0],
11508 		       dm->rf_trx_para.wl_rx_gain[RTW89_PHY_1],
11509 		       dm->wl_lna2, dm->wl_stb_chg);
11510 
11511 	p += scnprintf(p, end - p,
11512 		       " %-15s : pre_agc:%d, btg_rx:%d\n",
11513 		       "[dm_bb_ctrl]", dm->wl_pre_agc, dm->wl_btg_rx);
11514 
11515 	if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT)
11516 		p += scnprintf(p, end - p,
11517 			       " %-15s : bt_en_state:0x%x, shadow[done:0x%x/ack:0x%x]\n",
11518 			       "[dm_bttrx_en]", dm->ost_info.bt_enable_state,
11519 			       dm->bttrx_en_done, dm->bttrx_en_ack);
11520 
11521 	p += scnprintf(p, end - p,
11522 		       " %-15s : wl_tx_limit[en:%d/max_t:%dus/max_retry:%d], bt_slot_reg:%d-TU, bt_scan_rx_low_pri:%d\n",
11523 		       "[dm_ctrl]", dm->wl_tx_limit.enable,
11524 		       dm->wl_tx_limit.tx_time,
11525 		       dm->wl_tx_limit.tx_retry, btc->bt_req_len[RTW89_PHY_0],
11526 		       bt->scan_rx_low_pri);
11527 
11528 	return p - buf;
11529 }
11530 
11531 static int _show_error(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11532 {
11533 	struct rtw89_btc *btc = &rtwdev->btc;
11534 	const struct rtw89_btc_ver *ver = btc->ver;
11535 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11536 	union rtw89_btc_fbtc_cysta_info *pcysta;
11537 	char *p = buf, *end = buf + bufsz;
11538 	u32 except_cnt, exception_map;
11539 
11540 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
11541 	if (ver->fcxcysta == 2) {
11542 		pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2;
11543 		except_cnt = le32_to_cpu(pcysta->v2.except_cnt);
11544 		exception_map = le32_to_cpu(pcysta->v2.exception);
11545 	} else if (ver->fcxcysta == 3) {
11546 		pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3;
11547 		except_cnt = le32_to_cpu(pcysta->v3.except_cnt);
11548 		exception_map = le32_to_cpu(pcysta->v3.except_map);
11549 	} else if (ver->fcxcysta == 4) {
11550 		pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4;
11551 		except_cnt = pcysta->v4.except_cnt;
11552 		exception_map = le32_to_cpu(pcysta->v4.except_map);
11553 	} else if (ver->fcxcysta == 5) {
11554 		pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5;
11555 		except_cnt = pcysta->v5.except_cnt;
11556 		exception_map = le32_to_cpu(pcysta->v5.except_map);
11557 	} else if (ver->fcxcysta == 7) {
11558 		pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7;
11559 		except_cnt = pcysta->v7.except_cnt;
11560 		exception_map = le32_to_cpu(pcysta->v7.except_map);
11561 	} else if (ver->fcxcysta == 8) {
11562 		pcysta->v8 = pfwinfo->rpt_fbtc_cysta.finfo.v8;
11563 		except_cnt = pcysta->v8.except_cnt;
11564 		exception_map = le32_to_cpu(pcysta->v8.except_map);
11565 	} else {
11566 		return 0;
11567 	}
11568 
11569 	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 && except_cnt == 0 &&
11570 	    !pfwinfo->len_mismch && !pfwinfo->fver_mismch)
11571 		return 0;
11572 
11573 	p += scnprintf(p, end - p, " %-15s : ", "[error]");
11574 
11575 	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]) {
11576 		p += scnprintf(p, end - p,
11577 			       "overflow-cnt: %d, ",
11578 			       pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]);
11579 	}
11580 
11581 	if (pfwinfo->len_mismch) {
11582 		p += scnprintf(p, end - p,
11583 			       "len-mismatch: 0x%x, ",
11584 			       pfwinfo->len_mismch);
11585 	}
11586 
11587 	if (pfwinfo->fver_mismch) {
11588 		p += scnprintf(p, end - p,
11589 			       "fver-mismatch: 0x%x, ",
11590 			       pfwinfo->fver_mismch);
11591 	}
11592 
11593 	/* cycle statistics exceptions */
11594 	if (exception_map || except_cnt) {
11595 		p += scnprintf(p, end - p,
11596 			       "exception-type: 0x%x, exception-cnt = %d",
11597 			       exception_map, except_cnt);
11598 	}
11599 	p += scnprintf(p, end - p, "\n");
11600 
11601 	return p - buf;
11602 }
11603 
11604 static int _show_fbtc_tdma(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11605 {
11606 	struct rtw89_btc *btc = &rtwdev->btc;
11607 	const struct rtw89_btc_ver *ver = btc->ver;
11608 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11609 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
11610 	struct rtw89_btc_fbtc_tdma *t = NULL;
11611 	char *p = buf, *end = buf + bufsz;
11612 
11613 	pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
11614 	if (!pcinfo->valid)
11615 		return 0;
11616 
11617 	if (ver->fcxtdma == 1)
11618 		t = &pfwinfo->rpt_fbtc_tdma.finfo.v1;
11619 	else
11620 		t = &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma;
11621 
11622 	p += scnprintf(p, end - p,
11623 		       " %-15s : ", "[tdma_policy]");
11624 	p += scnprintf(p, end - p,
11625 		       "type:%d, rx_flow_ctrl:%d, txflctrl:%d, ",
11626 		       (u32)t->type,
11627 		       t->rxflctrl, t->txflctrl);
11628 
11629 	p += scnprintf(p, end - p,
11630 		       "bind:%d, leak_n:%d, ext_ctrl:%d, ",
11631 		       t->bind, t->leak_n, t->ext_ctrl);
11632 
11633 	p += scnprintf(p, end - p,
11634 		       "policy_type:%d\n",
11635 		       (u32)btc->policy_type);
11636 
11637 	return p - buf;
11638 }
11639 
11640 static int _show_fbtc_slots(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11641 {
11642 	struct rtw89_btc *btc = &rtwdev->btc;
11643 	const struct rtw89_btc_ver *ver = btc->ver;
11644 	struct rtw89_btc_dm *dm = &btc->dm;
11645 	char *p = buf, *end = buf + bufsz;
11646 	u16 dur, cxtype;
11647 	u32 tbl;
11648 	u8 i = 0;
11649 
11650 	for (i = 0; i < CXST_MAX; i++) {
11651 		if (ver->fcxslots == 1) {
11652 			dur = le16_to_cpu(dm->slot_now.v1[i].dur);
11653 			tbl = le32_to_cpu(dm->slot_now.v1[i].cxtbl);
11654 			cxtype = le16_to_cpu(dm->slot_now.v1[i].cxtype);
11655 		} else if (ver->fcxslots == 2 || ver->fcxslots == 7) {
11656 			dur = le16_to_cpu(dm->slot_now.v7[i].dur);
11657 			tbl = le32_to_cpu(dm->slot_now.v7[i].cxtbl);
11658 			cxtype = le16_to_cpu(dm->slot_now.v7[i].cxtype);
11659 		} else {
11660 			return 0;
11661 		}
11662 
11663 		if (i % 5 == 0)
11664 			p += scnprintf(p, end - p,
11665 				       " %-15s : %5s[%03d/0x%x/%d]",
11666 				       "[slot_list]",
11667 				       id_to_slot((u32)i),
11668 				       dur, tbl, cxtype);
11669 		else
11670 			p += scnprintf(p, end - p,
11671 				       ", %5s[%03d/0x%x/%d]",
11672 				       id_to_slot((u32)i),
11673 				       dur, tbl, cxtype);
11674 
11675 		if (i % 5 == 4)
11676 			p += scnprintf(p, end - p, "\n");
11677 	}
11678 
11679 	return p - buf;
11680 }
11681 
11682 static int _show_fbtc_cysta_v2(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11683 {
11684 	struct rtw89_btc *btc = &rtwdev->btc;
11685 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11686 	struct rtw89_btc_dm *dm = &btc->dm;
11687 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
11688 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
11689 	struct rtw89_btc_fbtc_cysta_v2 *pcysta_le32 = NULL;
11690 	union rtw89_btc_fbtc_rxflct r;
11691 	u16 cycle, c_begin, c_end, store_index;
11692 	char *p = buf, *end = buf + bufsz;
11693 	u8 i, cnt = 0, slot_pair;
11694 
11695 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
11696 	if (!pcinfo->valid)
11697 		return 0;
11698 
11699 	pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo.v2;
11700 	p += scnprintf(p, end - p,
11701 		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
11702 		       "[cycle_cnt]",
11703 		       le16_to_cpu(pcysta_le32->cycles),
11704 		       le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_ALL]),
11705 		       le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_ALL_OK]),
11706 		       le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_BT_SLOT]),
11707 		       le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_BT_OK]));
11708 
11709 	for (i = 0; i < CXST_MAX; i++) {
11710 		if (!le32_to_cpu(pcysta_le32->slot_cnt[i]))
11711 			continue;
11712 		p += scnprintf(p, end - p, ", %s:%d", id_to_slot((u32)i),
11713 			       le32_to_cpu(pcysta_le32->slot_cnt[i]));
11714 	}
11715 
11716 	if (dm->tdma_now.rxflctrl) {
11717 		p += scnprintf(p, end - p, ", leak_rx:%d",
11718 			       le32_to_cpu(pcysta_le32->leakrx_cnt));
11719 	}
11720 
11721 	if (le32_to_cpu(pcysta_le32->collision_cnt)) {
11722 		p += scnprintf(p, end - p, ", collision:%d",
11723 			       le32_to_cpu(pcysta_le32->collision_cnt));
11724 	}
11725 
11726 	if (le32_to_cpu(pcysta_le32->skip_cnt)) {
11727 		p += scnprintf(p, end - p, ", skip:%d",
11728 			       le32_to_cpu(pcysta_le32->skip_cnt));
11729 	}
11730 	p += scnprintf(p, end - p, "\n");
11731 
11732 	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
11733 		       "[cycle_time]",
11734 		       le16_to_cpu(pcysta_le32->tavg_cycle[CXT_WL]),
11735 		       le16_to_cpu(pcysta_le32->tavg_cycle[CXT_BT]),
11736 		       le16_to_cpu(pcysta_le32->tavg_lk) / 1000,
11737 		       le16_to_cpu(pcysta_le32->tavg_lk) % 1000);
11738 	p += scnprintf(p, end - p, ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
11739 		       le16_to_cpu(pcysta_le32->tmax_cycle[CXT_WL]),
11740 		       le16_to_cpu(pcysta_le32->tmax_cycle[CXT_BT]),
11741 		       le16_to_cpu(pcysta_le32->tmax_lk) / 1000,
11742 		       le16_to_cpu(pcysta_le32->tmax_lk) % 1000);
11743 	p += scnprintf(p, end - p, ", maxdiff_t[wl:%d/bt:%d]\n",
11744 		       le16_to_cpu(pcysta_le32->tmaxdiff_cycle[CXT_WL]),
11745 		       le16_to_cpu(pcysta_le32->tmaxdiff_cycle[CXT_BT]));
11746 
11747 	if (le16_to_cpu(pcysta_le32->cycles) <= 1)
11748 		goto out;
11749 
11750 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
11751 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
11752 
11753 	if (le16_to_cpu(pcysta_le32->cycles) <= slot_pair)
11754 		c_begin = 1;
11755 	else
11756 		c_begin = le16_to_cpu(pcysta_le32->cycles) - slot_pair + 1;
11757 
11758 	c_end = le16_to_cpu(pcysta_le32->cycles);
11759 
11760 	for (cycle = c_begin; cycle <= c_end; cycle++) {
11761 		cnt++;
11762 		store_index = ((cycle - 1) % slot_pair) * 2;
11763 
11764 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 1)
11765 			p += scnprintf(p, end - p,
11766 				       " %-15s : ->b%02d->w%02d",
11767 				       "[cycle_step]",
11768 				       le16_to_cpu(pcysta_le32->tslot_cycle[store_index]),
11769 				       le16_to_cpu(pcysta_le32->tslot_cycle[store_index + 1]));
11770 		else
11771 			p += scnprintf(p, end - p,
11772 				       "->b%02d->w%02d",
11773 				       le16_to_cpu(pcysta_le32->tslot_cycle[store_index]),
11774 				       le16_to_cpu(pcysta_le32->tslot_cycle[store_index + 1]));
11775 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end)
11776 			p += scnprintf(p, end - p, "\n");
11777 	}
11778 
11779 	if (a2dp->exist) {
11780 		p += scnprintf(p, end - p,
11781 			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
11782 			       "[a2dp_t_sta]",
11783 			       le16_to_cpu(pcysta_le32->a2dpept),
11784 			       le16_to_cpu(pcysta_le32->a2dpeptto));
11785 
11786 		p += scnprintf(p, end - p,
11787 			       ", avg_t:%d, max_t:%d",
11788 			       le16_to_cpu(pcysta_le32->tavg_a2dpept),
11789 			       le16_to_cpu(pcysta_le32->tmax_a2dpept));
11790 		r.val = dm->tdma_now.rxflctrl;
11791 
11792 		if (r.type && r.tgln_n) {
11793 			p += scnprintf(p, end - p,
11794 				       ", cycle[PSTDMA:%d/TDMA:%d], ",
11795 				       le16_to_cpu(pcysta_le32->cycles_a2dp[CXT_FLCTRL_ON]),
11796 				       le16_to_cpu(pcysta_le32->cycles_a2dp[CXT_FLCTRL_OFF]));
11797 
11798 			p += scnprintf(p, end - p,
11799 				       "avg_t[PSTDMA:%d/TDMA:%d], ",
11800 				       le16_to_cpu(pcysta_le32->tavg_a2dp[CXT_FLCTRL_ON]),
11801 				       le16_to_cpu(pcysta_le32->tavg_a2dp[CXT_FLCTRL_OFF]));
11802 
11803 			p += scnprintf(p, end - p,
11804 				       "max_t[PSTDMA:%d/TDMA:%d]",
11805 				       le16_to_cpu(pcysta_le32->tmax_a2dp[CXT_FLCTRL_ON]),
11806 				       le16_to_cpu(pcysta_le32->tmax_a2dp[CXT_FLCTRL_OFF]));
11807 		}
11808 		p += scnprintf(p, end - p, "\n");
11809 	}
11810 
11811 out:
11812 	return p - buf;
11813 }
11814 
11815 static int _show_fbtc_cysta_v3(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11816 {
11817 	struct rtw89_btc *btc = &rtwdev->btc;
11818 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
11819 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11820 	struct rtw89_btc_dm *dm = &btc->dm;
11821 	struct rtw89_btc_fbtc_a2dp_trx_stat *a2dp_trx;
11822 	struct rtw89_btc_fbtc_cysta_v3 *pcysta;
11823 	struct rtw89_btc_rpt_cmn_info *pcinfo;
11824 	u8 i, cnt = 0, slot_pair, divide_cnt;
11825 	u16 cycle, c_begin, c_end, store_index;
11826 	char *p = buf, *end = buf + bufsz;
11827 
11828 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
11829 	if (!pcinfo->valid)
11830 		return 0;
11831 
11832 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v3;
11833 	p += scnprintf(p, end - p,
11834 		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
11835 		       "[cycle_cnt]",
11836 		       le16_to_cpu(pcysta->cycles),
11837 		       le32_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
11838 		       le32_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
11839 		       le32_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
11840 		       le32_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
11841 
11842 	for (i = 0; i < CXST_MAX; i++) {
11843 		if (!le32_to_cpu(pcysta->slot_cnt[i]))
11844 			continue;
11845 
11846 		p += scnprintf(p, end - p, ", %s:%d", id_to_slot(i),
11847 			       le32_to_cpu(pcysta->slot_cnt[i]));
11848 	}
11849 
11850 	if (dm->tdma_now.rxflctrl)
11851 		p += scnprintf(p, end - p, ", leak_rx:%d",
11852 			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
11853 
11854 	if (le32_to_cpu(pcysta->collision_cnt))
11855 		p += scnprintf(p, end - p, ", collision:%d",
11856 			       le32_to_cpu(pcysta->collision_cnt));
11857 
11858 	if (le32_to_cpu(pcysta->skip_cnt))
11859 		p += scnprintf(p, end - p, ", skip:%d",
11860 			       le32_to_cpu(pcysta->skip_cnt));
11861 
11862 	p += scnprintf(p, end - p, "\n");
11863 
11864 	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
11865 		       "[cycle_time]",
11866 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
11867 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
11868 		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
11869 		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
11870 	p += scnprintf(p, end - p,
11871 		       ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
11872 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
11873 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
11874 		       le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
11875 		       le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
11876 	p += scnprintf(p, end - p,
11877 		       ", maxdiff_t[wl:%d/bt:%d]\n",
11878 		       le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_WL]),
11879 		       le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_BT]));
11880 
11881 	cycle = le16_to_cpu(pcysta->cycles);
11882 	if (cycle <= 1)
11883 		goto out;
11884 
11885 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
11886 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
11887 
11888 	if (cycle <= slot_pair)
11889 		c_begin = 1;
11890 	else
11891 		c_begin = cycle - slot_pair + 1;
11892 
11893 	c_end = cycle;
11894 
11895 	if (a2dp->exist)
11896 		divide_cnt = 3;
11897 	else
11898 		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
11899 
11900 	for (cycle = c_begin; cycle <= c_end; cycle++) {
11901 		cnt++;
11902 		store_index = ((cycle - 1) % slot_pair) * 2;
11903 
11904 		if (cnt % divide_cnt == 1)
11905 			p += scnprintf(p, end - p, " %-15s : ",
11906 				       "[cycle_step]");
11907 
11908 		p += scnprintf(p, end - p, "->b%02d",
11909 			       le16_to_cpu(pcysta->slot_step_time[store_index]));
11910 		if (a2dp->exist) {
11911 			a2dp_trx = &pcysta->a2dp_trx[store_index];
11912 			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
11913 				       a2dp_trx->empty_cnt,
11914 				       a2dp_trx->retry_cnt,
11915 				       a2dp_trx->tx_rate ? 3 : 2,
11916 				       a2dp_trx->tx_cnt,
11917 				       a2dp_trx->ack_cnt,
11918 				       a2dp_trx->nack_cnt);
11919 		}
11920 		p += scnprintf(p, end - p, "->w%02d",
11921 			       le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
11922 		if (a2dp->exist) {
11923 			a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
11924 			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
11925 				       a2dp_trx->empty_cnt,
11926 				       a2dp_trx->retry_cnt,
11927 				       a2dp_trx->tx_rate ? 3 : 2,
11928 				       a2dp_trx->tx_cnt,
11929 				       a2dp_trx->ack_cnt,
11930 				       a2dp_trx->nack_cnt);
11931 		}
11932 		if (cnt % divide_cnt == 0 || cnt == c_end)
11933 			p += scnprintf(p, end - p, "\n");
11934 	}
11935 
11936 	if (a2dp->exist) {
11937 		p += scnprintf(p, end - p,
11938 			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
11939 			       "[a2dp_t_sta]",
11940 			       le16_to_cpu(pcysta->a2dp_ept.cnt),
11941 			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
11942 
11943 		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d\n",
11944 			       le16_to_cpu(pcysta->a2dp_ept.tavg),
11945 			       le16_to_cpu(pcysta->a2dp_ept.tmax));
11946 	}
11947 
11948 out:
11949 	return p - buf;
11950 }
11951 
11952 static int _show_fbtc_cysta_v4(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11953 {
11954 	struct rtw89_btc *btc = &rtwdev->btc;
11955 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
11956 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11957 	struct rtw89_btc_dm *dm = &btc->dm;
11958 	struct rtw89_btc_fbtc_a2dp_trx_stat_v4 *a2dp_trx;
11959 	struct rtw89_btc_fbtc_cysta_v4 *pcysta;
11960 	struct rtw89_btc_rpt_cmn_info *pcinfo;
11961 	u8 i, cnt = 0, slot_pair, divide_cnt;
11962 	u16 cycle, c_begin, c_end, store_index;
11963 	char *p = buf, *end = buf + bufsz;
11964 
11965 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
11966 	if (!pcinfo->valid)
11967 		return 0;
11968 
11969 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v4;
11970 	p += scnprintf(p, end - p,
11971 		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
11972 		       "[cycle_cnt]",
11973 		       le16_to_cpu(pcysta->cycles),
11974 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
11975 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
11976 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
11977 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
11978 
11979 	for (i = 0; i < CXST_MAX; i++) {
11980 		if (!le16_to_cpu(pcysta->slot_cnt[i]))
11981 			continue;
11982 
11983 		p += scnprintf(p, end - p, ", %s:%d", id_to_slot(i),
11984 			       le16_to_cpu(pcysta->slot_cnt[i]));
11985 	}
11986 
11987 	if (dm->tdma_now.rxflctrl)
11988 		p += scnprintf(p, end - p, ", leak_rx:%d",
11989 			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
11990 
11991 	if (pcysta->collision_cnt)
11992 		p += scnprintf(p, end - p, ", collision:%d",
11993 			       pcysta->collision_cnt);
11994 
11995 	if (le16_to_cpu(pcysta->skip_cnt))
11996 		p += scnprintf(p, end - p, ", skip:%d",
11997 			       le16_to_cpu(pcysta->skip_cnt));
11998 
11999 	p += scnprintf(p, end - p, "\n");
12000 
12001 	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
12002 		       "[cycle_time]",
12003 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
12004 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
12005 		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
12006 		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
12007 	p += scnprintf(p, end - p,
12008 		       ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
12009 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
12010 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
12011 		       le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
12012 		       le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
12013 	p += scnprintf(p, end - p,
12014 		       ", maxdiff_t[wl:%d/bt:%d]\n",
12015 		       le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_WL]),
12016 		       le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_BT]));
12017 
12018 	cycle = le16_to_cpu(pcysta->cycles);
12019 	if (cycle <= 1)
12020 		goto out;
12021 
12022 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
12023 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
12024 
12025 	if (cycle <= slot_pair)
12026 		c_begin = 1;
12027 	else
12028 		c_begin = cycle - slot_pair + 1;
12029 
12030 	c_end = cycle;
12031 
12032 	if (a2dp->exist)
12033 		divide_cnt = 3;
12034 	else
12035 		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
12036 
12037 	for (cycle = c_begin; cycle <= c_end; cycle++) {
12038 		cnt++;
12039 		store_index = ((cycle - 1) % slot_pair) * 2;
12040 
12041 		if (cnt % divide_cnt == 1)
12042 			p += scnprintf(p, end - p, " %-15s : ",
12043 				       "[cycle_step]");
12044 
12045 		p += scnprintf(p, end - p, "->b%02d",
12046 			       le16_to_cpu(pcysta->slot_step_time[store_index]));
12047 		if (a2dp->exist) {
12048 			a2dp_trx = &pcysta->a2dp_trx[store_index];
12049 			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
12050 				       a2dp_trx->empty_cnt,
12051 				       a2dp_trx->retry_cnt,
12052 				       a2dp_trx->tx_rate ? 3 : 2,
12053 				       a2dp_trx->tx_cnt,
12054 				       a2dp_trx->ack_cnt,
12055 				       a2dp_trx->nack_cnt);
12056 		}
12057 		p += scnprintf(p, end - p, "->w%02d",
12058 			       le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
12059 		if (a2dp->exist) {
12060 			a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
12061 			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
12062 				       a2dp_trx->empty_cnt,
12063 				       a2dp_trx->retry_cnt,
12064 				       a2dp_trx->tx_rate ? 3 : 2,
12065 				       a2dp_trx->tx_cnt,
12066 				       a2dp_trx->ack_cnt,
12067 				       a2dp_trx->nack_cnt);
12068 		}
12069 		if (cnt % divide_cnt == 0 || cnt == c_end)
12070 			p += scnprintf(p, end - p, "\n");
12071 	}
12072 
12073 	if (a2dp->exist) {
12074 		p += scnprintf(p, end - p,
12075 			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
12076 			       "[a2dp_t_sta]",
12077 			       le16_to_cpu(pcysta->a2dp_ept.cnt),
12078 			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
12079 
12080 		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d\n",
12081 			       le16_to_cpu(pcysta->a2dp_ept.tavg),
12082 			       le16_to_cpu(pcysta->a2dp_ept.tmax));
12083 	}
12084 
12085 out:
12086 	return p - buf;
12087 }
12088 
12089 static int _show_fbtc_cysta_v5(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12090 {
12091 	struct rtw89_btc *btc = &rtwdev->btc;
12092 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
12093 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
12094 	struct rtw89_btc_dm *dm = &btc->dm;
12095 	struct rtw89_btc_fbtc_a2dp_trx_stat_v4 *a2dp_trx;
12096 	struct rtw89_btc_fbtc_cysta_v5 *pcysta;
12097 	struct rtw89_btc_rpt_cmn_info *pcinfo;
12098 	u8 i, cnt = 0, slot_pair, divide_cnt;
12099 	u16 cycle, c_begin, c_end, store_index;
12100 	char *p = buf, *end = buf + bufsz;
12101 
12102 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
12103 	if (!pcinfo->valid)
12104 		return 0;
12105 
12106 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v5;
12107 	p += scnprintf(p, end - p,
12108 		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
12109 		       "[cycle_cnt]",
12110 		       le16_to_cpu(pcysta->cycles),
12111 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
12112 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
12113 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
12114 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
12115 
12116 	for (i = 0; i < CXST_MAX; i++) {
12117 		if (!le16_to_cpu(pcysta->slot_cnt[i]))
12118 			continue;
12119 
12120 		p += scnprintf(p, end - p, ", %s:%d", id_to_slot(i),
12121 			       le16_to_cpu(pcysta->slot_cnt[i]));
12122 	}
12123 
12124 	if (dm->tdma_now.rxflctrl)
12125 		p += scnprintf(p, end - p, ", leak_rx:%d",
12126 			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
12127 
12128 	if (pcysta->collision_cnt)
12129 		p += scnprintf(p, end - p, ", collision:%d",
12130 			       pcysta->collision_cnt);
12131 
12132 	if (le16_to_cpu(pcysta->skip_cnt))
12133 		p += scnprintf(p, end - p, ", skip:%d",
12134 			       le16_to_cpu(pcysta->skip_cnt));
12135 
12136 	p += scnprintf(p, end - p, "\n");
12137 
12138 	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
12139 		       "[cycle_time]",
12140 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
12141 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
12142 		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
12143 		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
12144 	p += scnprintf(p, end - p,
12145 		       ", max_t[wl:%d/bt:%d/lk:%d.%03d]\n",
12146 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
12147 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
12148 		       le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
12149 		       le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
12150 
12151 	cycle = le16_to_cpu(pcysta->cycles);
12152 	if (cycle <= 1)
12153 		goto out;
12154 
12155 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
12156 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
12157 
12158 	if (cycle <= slot_pair)
12159 		c_begin = 1;
12160 	else
12161 		c_begin = cycle - slot_pair + 1;
12162 
12163 	c_end = cycle;
12164 
12165 	if (a2dp->exist)
12166 		divide_cnt = 3;
12167 	else
12168 		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
12169 
12170 	if (c_begin > c_end)
12171 		goto out;
12172 
12173 	for (cycle = c_begin; cycle <= c_end; cycle++) {
12174 		cnt++;
12175 		store_index = ((cycle - 1) % slot_pair) * 2;
12176 
12177 		if (cnt % divide_cnt == 1)
12178 			p += scnprintf(p, end - p, " %-15s : ",
12179 				       "[cycle_step]");
12180 
12181 		p += scnprintf(p, end - p, "->b%02d",
12182 			       le16_to_cpu(pcysta->slot_step_time[store_index]));
12183 		if (a2dp->exist) {
12184 			a2dp_trx = &pcysta->a2dp_trx[store_index];
12185 			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
12186 				       a2dp_trx->empty_cnt,
12187 				       a2dp_trx->retry_cnt,
12188 				       a2dp_trx->tx_rate ? 3 : 2,
12189 				       a2dp_trx->tx_cnt,
12190 				       a2dp_trx->ack_cnt,
12191 				       a2dp_trx->nack_cnt);
12192 		}
12193 		p += scnprintf(p, end - p, "->w%02d",
12194 			       le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
12195 		if (a2dp->exist) {
12196 			a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
12197 			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
12198 				       a2dp_trx->empty_cnt,
12199 				       a2dp_trx->retry_cnt,
12200 				       a2dp_trx->tx_rate ? 3 : 2,
12201 				       a2dp_trx->tx_cnt,
12202 				       a2dp_trx->ack_cnt,
12203 				       a2dp_trx->nack_cnt);
12204 		}
12205 		if (cnt % divide_cnt == 0 || cnt == c_end)
12206 			p += scnprintf(p, end - p, "\n");
12207 	}
12208 
12209 	if (a2dp->exist) {
12210 		p += scnprintf(p, end - p,
12211 			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
12212 			       "[a2dp_t_sta]",
12213 			       le16_to_cpu(pcysta->a2dp_ept.cnt),
12214 			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
12215 
12216 		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d\n",
12217 			       le16_to_cpu(pcysta->a2dp_ept.tavg),
12218 			       le16_to_cpu(pcysta->a2dp_ept.tmax));
12219 	}
12220 
12221 out:
12222 	return p - buf;
12223 }
12224 
12225 static int _show_fbtc_cysta_v105(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12226 {
12227 	struct rtw89_btc *btc = &rtwdev->btc;
12228 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt0.link_info.a2dp_desc;
12229 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
12230 	struct rtw89_btc_dm *dm = &btc->dm;
12231 	struct rtw89_btc_fbtc_a2dp_trx_stat_v4 *a2dp_trx;
12232 	struct rtw89_btc_fbtc_cysta_v105 *pcysta;
12233 	struct rtw89_btc_rpt_cmn_info *pcinfo;
12234 	u8 i, cnt = 0, slot_pair, divide_cnt;
12235 	u16 cycle, c_begin, c_end, store_index;
12236 	char *p = buf, *end = buf + bufsz;
12237 
12238 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
12239 	if (!pcinfo->valid)
12240 		return 0;
12241 
12242 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v105;
12243 	p += scnprintf(p, end - p,
12244 		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
12245 		       "[cycle_cnt]",
12246 		       le16_to_cpu(pcysta->cycles),
12247 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
12248 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
12249 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
12250 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
12251 
12252 	for (i = 0; i < CXST_MAX; i++) {
12253 		if (!le16_to_cpu(pcysta->slot_cnt[i]))
12254 			continue;
12255 
12256 		p += scnprintf(p, end - p, ", %s:%d", id_to_slot(i),
12257 			       le16_to_cpu(pcysta->slot_cnt[i]));
12258 	}
12259 
12260 	if (dm->tdma_now.rxflctrl)
12261 		p += scnprintf(p, end - p, ", leak_rx:%d",
12262 			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
12263 
12264 	if (pcysta->collision_cnt)
12265 		p += scnprintf(p, end - p, ", collision:%d",
12266 			       pcysta->collision_cnt);
12267 
12268 	if (le16_to_cpu(pcysta->skip_cnt))
12269 		p += scnprintf(p, end - p, ", skip:%d",
12270 			       le16_to_cpu(pcysta->skip_cnt));
12271 
12272 	p += scnprintf(p, end - p, "\n");
12273 
12274 	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
12275 		       "[cycle_time]",
12276 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
12277 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
12278 		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
12279 		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
12280 	p += scnprintf(p, end - p,
12281 		       ", max_t[wl:%d/bt:%d/lk:%d.%03d]\n",
12282 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
12283 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
12284 		       le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
12285 		       le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
12286 
12287 	cycle = le16_to_cpu(pcysta->cycles);
12288 	if (cycle <= 1)
12289 		goto out;
12290 
12291 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
12292 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
12293 
12294 	if (cycle <= slot_pair)
12295 		c_begin = 1;
12296 	else
12297 		c_begin = cycle - slot_pair + 1;
12298 
12299 	c_end = cycle;
12300 
12301 	if (a2dp->exist)
12302 		divide_cnt = 3;
12303 	else
12304 		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
12305 
12306 	if (c_begin > c_end)
12307 		goto out;
12308 
12309 	for (cycle = c_begin; cycle <= c_end; cycle++) {
12310 		cnt++;
12311 		store_index = ((cycle - 1) % slot_pair) * 2;
12312 
12313 		if (cnt % divide_cnt == 1)
12314 			p += scnprintf(p, end - p, " %-15s : ",
12315 				       "[cycle_step]");
12316 
12317 		p += scnprintf(p, end - p, "->b%02d",
12318 			       le16_to_cpu(pcysta->slot_step_time[store_index]));
12319 		if (a2dp->exist) {
12320 			a2dp_trx = &pcysta->a2dp_trx[store_index];
12321 			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
12322 				       a2dp_trx->empty_cnt,
12323 				       a2dp_trx->retry_cnt,
12324 				       a2dp_trx->tx_rate ? 3 : 2,
12325 				       a2dp_trx->tx_cnt,
12326 				       a2dp_trx->ack_cnt,
12327 				       a2dp_trx->nack_cnt);
12328 		}
12329 		p += scnprintf(p, end - p, "->w%02d",
12330 			       le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
12331 		if (a2dp->exist) {
12332 			a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
12333 			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
12334 				       a2dp_trx->empty_cnt,
12335 				       a2dp_trx->retry_cnt,
12336 				       a2dp_trx->tx_rate ? 3 : 2,
12337 				       a2dp_trx->tx_cnt,
12338 				       a2dp_trx->ack_cnt,
12339 				       a2dp_trx->nack_cnt);
12340 		}
12341 		if (cnt % divide_cnt == 0 || cnt == c_end)
12342 			p += scnprintf(p, end - p, "\n");
12343 	}
12344 
12345 	if (a2dp->exist) {
12346 		p += scnprintf(p, end - p,
12347 			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
12348 			       "[a2dp_t_sta]",
12349 			       le16_to_cpu(pcysta->a2dp_ept.cnt),
12350 			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
12351 
12352 		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d\n",
12353 			       le16_to_cpu(pcysta->a2dp_ept.tavg),
12354 			       le16_to_cpu(pcysta->a2dp_ept.tmax));
12355 	}
12356 
12357 out:
12358 	return p - buf;
12359 }
12360 
12361 static int _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12362 {
12363 	struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt0;
12364 	struct rtw89_btc_bt_a2dp_desc *a2dp = &bt->link_info.a2dp_desc;
12365 	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
12366 	struct rtw89_btc_fbtc_cysta_v7 *pcysta = NULL;
12367 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
12368 	struct rtw89_btc_rpt_cmn_info *pcinfo;
12369 	char *p = buf, *end = buf + bufsz;
12370 	u16 cycle, c_begin, c_end, s_id;
12371 	u8 i, cnt = 0, divide_cnt;
12372 	u8 slot_pair;
12373 
12374 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
12375 	if (!pcinfo->valid)
12376 		return 0;
12377 
12378 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v7;
12379 	p += scnprintf(p, end - p, "\n %-15s : cycle:%d", "[slot_stat]",
12380 		       le16_to_cpu(pcysta->cycles));
12381 
12382 	for (i = 0; i < CXST_MAX; i++) {
12383 		if (!le16_to_cpu(pcysta->slot_cnt[i]))
12384 			continue;
12385 		p += scnprintf(p, end - p, ", %s:%d",
12386 			       id_to_slot(i),
12387 			       le16_to_cpu(pcysta->slot_cnt[i]));
12388 	}
12389 
12390 	if (dm->tdma_now.rxflctrl)
12391 		p += scnprintf(p, end - p, ", leak_rx:%d",
12392 			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
12393 
12394 	if (pcysta->collision_cnt)
12395 		p += scnprintf(p, end - p, ", collision:%d",
12396 			       pcysta->collision_cnt);
12397 
12398 	if (pcysta->skip_cnt)
12399 		p += scnprintf(p, end - p, ", skip:%d",
12400 			       le16_to_cpu(pcysta->skip_cnt));
12401 
12402 	p += scnprintf(p, end - p,
12403 		       "\n %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
12404 		       "[cycle_stat]",
12405 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
12406 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
12407 		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
12408 		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
12409 	p += scnprintf(p, end - p,
12410 		       ", max_t[wl:%d/bt:%d(>%dms:%d)/lk:%d.%03d]",
12411 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
12412 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
12413 		       dm->bt_slot_flood, dm->cnt_dm[BTC_DCNT_BT_SLOT_FLOOD],
12414 		       le16_to_cpu(pcysta->leak_slot.tamx) / 1000,
12415 		       le16_to_cpu(pcysta->leak_slot.tamx) % 1000);
12416 	p += scnprintf(p, end - p, ", bcn[all:%d/ok:%d/in_bt:%d/in_bt_ok:%d]",
12417 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
12418 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
12419 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
12420 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
12421 
12422 	if (a2dp->exist) {
12423 		p += scnprintf(p, end - p,
12424 			       "\n %-15s : a2dp_ept:%d, a2dp_late:%d(streak 2S:%d/max:%d)",
12425 			       "[a2dp_stat]",
12426 			       le16_to_cpu(pcysta->a2dp_ept.cnt),
12427 			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout),
12428 			       a2dp->no_empty_streak_2s,
12429 			       a2dp->no_empty_streak_max);
12430 
12431 		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
12432 			       le16_to_cpu(pcysta->a2dp_ept.tavg),
12433 			       le16_to_cpu(pcysta->a2dp_ept.tmax));
12434 	}
12435 
12436 	if (le16_to_cpu(pcysta->cycles) <= 1)
12437 		goto out;
12438 
12439 	/* 1 cycle = 1 wl-slot + 1 bt-slot */
12440 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
12441 
12442 	if (le16_to_cpu(pcysta->cycles) <= slot_pair)
12443 		c_begin = 1;
12444 	else
12445 		c_begin = le16_to_cpu(pcysta->cycles) - slot_pair + 1;
12446 
12447 	c_end = le16_to_cpu(pcysta->cycles);
12448 
12449 	if (a2dp->exist)
12450 		divide_cnt = 2;
12451 	else
12452 		divide_cnt = 6;
12453 
12454 	if (c_begin > c_end)
12455 		goto out;
12456 
12457 	for (cycle = c_begin; cycle <= c_end; cycle++) {
12458 		cnt++;
12459 		s_id = ((cycle - 1) % slot_pair) * 2;
12460 
12461 		if (cnt % divide_cnt == 1) {
12462 			if (a2dp->exist)
12463 				p += scnprintf(p, end - p, "\n %-15s : ",
12464 					       "[slotT_wermtan]");
12465 			else
12466 				p += scnprintf(p, end - p, "\n %-15s : ",
12467 					       "[slotT_rxerr]");
12468 		}
12469 
12470 		p += scnprintf(p, end - p, "->b%d",
12471 			       le16_to_cpu(pcysta->slot_step_time[s_id]));
12472 
12473 		if (a2dp->exist)
12474 			p += scnprintf(p, end - p, "(%d/%d/%d/%dM/%d/%d/%d)",
12475 				       pcysta->wl_rx_err_ratio[s_id],
12476 				       pcysta->a2dp_trx[s_id].empty_cnt,
12477 				       pcysta->a2dp_trx[s_id].retry_cnt,
12478 				       (pcysta->a2dp_trx[s_id].tx_rate ? 3 : 2),
12479 				       pcysta->a2dp_trx[s_id].tx_cnt,
12480 				       pcysta->a2dp_trx[s_id].ack_cnt,
12481 				       pcysta->a2dp_trx[s_id].nack_cnt);
12482 		else
12483 			p += scnprintf(p, end - p, "(%d)",
12484 				       pcysta->wl_rx_err_ratio[s_id]);
12485 
12486 		p += scnprintf(p, end - p, "->w%d",
12487 			       le16_to_cpu(pcysta->slot_step_time[s_id + 1]));
12488 
12489 		if (a2dp->exist)
12490 			p += scnprintf(p, end - p, "(%d/%d/%d/%dM/%d/%d/%d)",
12491 				       pcysta->wl_rx_err_ratio[s_id + 1],
12492 				       pcysta->a2dp_trx[s_id + 1].empty_cnt,
12493 				       pcysta->a2dp_trx[s_id + 1].retry_cnt,
12494 				       (pcysta->a2dp_trx[s_id + 1].tx_rate ? 3 : 2),
12495 				       pcysta->a2dp_trx[s_id + 1].tx_cnt,
12496 				       pcysta->a2dp_trx[s_id + 1].ack_cnt,
12497 				       pcysta->a2dp_trx[s_id + 1].nack_cnt);
12498 		else
12499 			p += scnprintf(p, end - p, "(%d)",
12500 				       pcysta->wl_rx_err_ratio[s_id + 1]);
12501 	}
12502 
12503 out:
12504 	return p - buf;
12505 }
12506 
12507 static int _show_fbtc_cysta_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12508 {
12509 	struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt0;
12510 	struct rtw89_btc_bt_a2dp_desc *a2dp = &bt->link_info.a2dp_desc;
12511 	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
12512 	struct rtw89_btc_fbtc_cysta_v8 *pcysta = NULL;
12513 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
12514 	struct rtw89_btc_rpt_cmn_info *pcinfo;
12515 	char *p = buf, *end = buf + bufsz;
12516 	u16 cycle, c_begin, c_end, s_id;
12517 	u8 i, cnt = 0, divide_cnt;
12518 	u8 slot_pair;
12519 
12520 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
12521 	if (!pcinfo->valid)
12522 		return 0;
12523 
12524 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v8;
12525 	p += scnprintf(p, end - p, "\n %-15s : cycle:%d", "[slot_stat]",
12526 		       le16_to_cpu(pcysta->cycles));
12527 
12528 	for (i = 0; i < CXST_MAX; i++) {
12529 		if (!le16_to_cpu(pcysta->slot_cnt[i]))
12530 			continue;
12531 		p += scnprintf(p, end - p, ", %s:%d",
12532 			       id_to_slot(i),
12533 			       le16_to_cpu(pcysta->slot_cnt[i]));
12534 	}
12535 
12536 	if (dm->tdma_now.rxflctrl)
12537 		p += scnprintf(p, end - p, ", leak_rx:%d",
12538 			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
12539 
12540 	if (pcysta->collision_cnt)
12541 		p += scnprintf(p, end - p, ", collision:%d",
12542 			       pcysta->collision_cnt);
12543 
12544 	if (pcysta->skip_cnt)
12545 		p += scnprintf(p, end - p, ", skip:%d",
12546 			       le16_to_cpu(pcysta->skip_cnt));
12547 
12548 	p += scnprintf(p, end - p,
12549 		       "\n %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
12550 		       "[cycle_stat]",
12551 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
12552 		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
12553 		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
12554 		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
12555 	p += scnprintf(p, end - p,
12556 		       ", max_t[wl:%d/bt:%d(>%dms:%d)/lk:%d.%03d]",
12557 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
12558 		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
12559 		       dm->bt_slot_flood, dm->cnt_dm[BTC_DCNT_BT_SLOT_FLOOD],
12560 		       le16_to_cpu(pcysta->leak_slot.tamx) / 1000,
12561 		       le16_to_cpu(pcysta->leak_slot.tamx) % 1000);
12562 	p += scnprintf(p, end - p, ", bcn[all:%d/ok:%d/in_bt:%d/in_bt_ok:%d]",
12563 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
12564 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
12565 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
12566 		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
12567 
12568 	if (a2dp->exist) {
12569 		p += scnprintf(p, end - p,
12570 			       "\n %-15s : a2dp_ept:%d, a2dp_late:%d(streak 2S:%d/max:%d)",
12571 			       "[a2dp_stat]",
12572 			       le16_to_cpu(pcysta->a2dp_ept.cnt),
12573 			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout),
12574 			       a2dp->no_empty_streak_2s,
12575 			       a2dp->no_empty_streak_max);
12576 
12577 		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
12578 			       le16_to_cpu(pcysta->a2dp_ept.tavg),
12579 			       le16_to_cpu(pcysta->a2dp_ept.tmax));
12580 	}
12581 
12582 	if (le16_to_cpu(pcysta->cycles) <= 1)
12583 		goto out;
12584 
12585 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
12586 
12587 	if (le16_to_cpu(pcysta->cycles) <= slot_pair)
12588 		c_begin = 1;
12589 	else
12590 		c_begin = le16_to_cpu(pcysta->cycles) - slot_pair + 1;
12591 
12592 	c_end = le16_to_cpu(pcysta->cycles);
12593 
12594 	if (a2dp->exist)
12595 		divide_cnt = 2;
12596 	else
12597 		divide_cnt = 6;
12598 
12599 	if (c_begin > c_end)
12600 		goto out;
12601 
12602 	for (cycle = c_begin; cycle <= c_end; cycle++) {
12603 		cnt++;
12604 		s_id = ((cycle - 1) % slot_pair) * 2;
12605 
12606 		if (cnt % divide_cnt == 1) {
12607 			if (a2dp->exist)
12608 				p += scnprintf(p, end - p, "\n %-15s : ",
12609 					       "[slotT_wermtan]");
12610 			else
12611 				p += scnprintf(p, end - p, "\n %-15s : ",
12612 					       "[slotT_rxerr]");
12613 		}
12614 
12615 		p += scnprintf(p, end - p, "->b%d",
12616 			       le16_to_cpu(pcysta->slot_step_time[s_id]));
12617 
12618 		if (a2dp->exist)
12619 			p += scnprintf(p, end - p, "(%d/%d/%d/%dM/%d/%d/%d)",
12620 				       pcysta->wl_rx_err_ratio[s_id],
12621 				       pcysta->a2dp_trx[s_id].empty_cnt,
12622 				       pcysta->a2dp_trx[s_id].retry_cnt,
12623 				       (pcysta->a2dp_trx[s_id].tx_rate ? 3 : 2),
12624 				       pcysta->a2dp_trx[s_id].tx_cnt,
12625 				       pcysta->a2dp_trx[s_id].ack_cnt,
12626 				       pcysta->a2dp_trx[s_id].nack_cnt);
12627 		else
12628 			p += scnprintf(p, end - p, "(%d)",
12629 				       pcysta->wl_rx_err_ratio[s_id]);
12630 
12631 		p += scnprintf(p, end - p, "->w%d",
12632 			       le16_to_cpu(pcysta->slot_step_time[s_id + 1]));
12633 
12634 		if (a2dp->exist)
12635 			p += scnprintf(p, end - p, "(%d/%d/%d/%dM/%d/%d/%d)",
12636 				       pcysta->wl_rx_err_ratio[s_id + 1],
12637 				       pcysta->a2dp_trx[s_id + 1].empty_cnt,
12638 				       pcysta->a2dp_trx[s_id + 1].retry_cnt,
12639 				       (pcysta->a2dp_trx[s_id + 1].tx_rate ? 3 : 2),
12640 				       pcysta->a2dp_trx[s_id + 1].tx_cnt,
12641 				       pcysta->a2dp_trx[s_id + 1].ack_cnt,
12642 				       pcysta->a2dp_trx[s_id + 1].nack_cnt);
12643 		else
12644 			p += scnprintf(p, end - p, "(%d)",
12645 				       pcysta->wl_rx_err_ratio[s_id + 1]);
12646 	}
12647 
12648 out:
12649 	return p - buf;
12650 }
12651 
12652 static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12653 {
12654 	struct rtw89_btc *btc = &rtwdev->btc;
12655 	const struct rtw89_btc_ver *ver = btc->ver;
12656 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
12657 	struct rtw89_btc_rpt_cmn_info *pcinfo;
12658 	union rtw89_btc_fbtc_cynullsta_info *ns;
12659 	char *p = buf, *end = buf + bufsz;
12660 	u8 i = 0;
12661 
12662 	if (!btc->dm.tdma_now.rxflctrl)
12663 		return 0;
12664 
12665 	pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
12666 	if (!pcinfo->valid)
12667 		return 0;
12668 
12669 	ns = &pfwinfo->rpt_fbtc_nullsta.finfo;
12670 	if (ver->fcxnullsta == 1) {
12671 		for (i = 0; i < 2; i++) {
12672 			p += scnprintf(p, end - p, "\n %-15s : ", "[NULL-STA]");
12673 			p += scnprintf(p, end - p, "null-%d", i);
12674 			p += scnprintf(p, end - p, "[ok:%d/",
12675 				       le32_to_cpu(ns->v1.result[i][1]));
12676 			p += scnprintf(p, end - p, "fail:%d/",
12677 				       le32_to_cpu(ns->v1.result[i][0]));
12678 			p += scnprintf(p, end - p, "on_time:%d/",
12679 				       le32_to_cpu(ns->v1.result[i][2]));
12680 			p += scnprintf(p, end - p, "retry:%d/",
12681 				       le32_to_cpu(ns->v1.result[i][3]));
12682 			p += scnprintf(p, end - p, "avg_t:%d.%03d/",
12683 				       le32_to_cpu(ns->v1.avg_t[i]) / 1000,
12684 				       le32_to_cpu(ns->v1.avg_t[i]) % 1000);
12685 			p += scnprintf(p, end - p, "max_t:%d.%03d]",
12686 				       le32_to_cpu(ns->v1.max_t[i]) / 1000,
12687 				       le32_to_cpu(ns->v1.max_t[i]) % 1000);
12688 		}
12689 	} else if (ver->fcxnullsta == 7) {
12690 		for (i = 0; i < 2; i++) {
12691 			p += scnprintf(p, end - p, "\n %-15s : ", "[NULL-STA]");
12692 			p += scnprintf(p, end - p, "null-%d", i);
12693 			p += scnprintf(p, end - p, "[Tx:%d/",
12694 				       le32_to_cpu(ns->v7.result[i][4]));
12695 			p += scnprintf(p, end - p, "[ok:%d/",
12696 				       le32_to_cpu(ns->v7.result[i][1]));
12697 			p += scnprintf(p, end - p, "fail:%d/",
12698 				       le32_to_cpu(ns->v7.result[i][0]));
12699 			p += scnprintf(p, end - p, "on_time:%d/",
12700 				       le32_to_cpu(ns->v7.result[i][2]));
12701 			p += scnprintf(p, end - p, "retry:%d/",
12702 				       le32_to_cpu(ns->v7.result[i][3]));
12703 			p += scnprintf(p, end - p, "avg_t:%d.%03d/",
12704 				       le32_to_cpu(ns->v7.tavg[i]) / 1000,
12705 				       le32_to_cpu(ns->v7.tavg[i]) % 1000);
12706 			p += scnprintf(p, end - p, "max_t:%d.%03d]",
12707 				       le32_to_cpu(ns->v7.tmax[i]) / 1000,
12708 				       le32_to_cpu(ns->v7.tmax[i]) % 1000);
12709 		}
12710 	} else {
12711 		for (i = 0; i < 2; i++) {
12712 			p += scnprintf(p, end - p, "\n %-15s : ", "[NULL-STA]");
12713 			p += scnprintf(p, end - p, "null-%d", i);
12714 			p += scnprintf(p, end - p, "[Tx:%d/",
12715 				       le32_to_cpu(ns->v2.result[i][4]));
12716 			p += scnprintf(p, end - p, "[ok:%d/",
12717 				       le32_to_cpu(ns->v2.result[i][1]));
12718 			p += scnprintf(p, end - p, "fail:%d/",
12719 				       le32_to_cpu(ns->v2.result[i][0]));
12720 			p += scnprintf(p, end - p, "on_time:%d/",
12721 				       le32_to_cpu(ns->v2.result[i][2]));
12722 			p += scnprintf(p, end - p, "retry:%d/",
12723 				       le32_to_cpu(ns->v2.result[i][3]));
12724 			p += scnprintf(p, end - p, "avg_t:%d.%03d/",
12725 				       le32_to_cpu(ns->v2.avg_t[i]) / 1000,
12726 				       le32_to_cpu(ns->v2.avg_t[i]) % 1000);
12727 			p += scnprintf(p, end - p, "max_t:%d.%03d]",
12728 				       le32_to_cpu(ns->v2.max_t[i]) / 1000,
12729 				       le32_to_cpu(ns->v2.max_t[i]) % 1000);
12730 		}
12731 	}
12732 
12733 	return p - buf;
12734 }
12735 
12736 static int _show_fbtc_step_v2(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12737 {
12738 	struct rtw89_btc *btc = &rtwdev->btc;
12739 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
12740 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
12741 	struct rtw89_btc_fbtc_steps_v2 *pstep = NULL;
12742 	const struct rtw89_btc_ver *ver = btc->ver;
12743 	char *p = buf, *end = buf + bufsz;
12744 	u8 type, val, cnt = 0, state = 0;
12745 	bool outloop = false;
12746 	u16 i, diff_t, n_start = 0, n_stop = 0;
12747 	u16 pos_old, pos_new, trace_step;
12748 
12749 	pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
12750 	if (!pcinfo->valid)
12751 		return 0;
12752 
12753 	pstep = &pfwinfo->rpt_fbtc_step.finfo.v2;
12754 	pos_old = le16_to_cpu(pstep->pos_old);
12755 	pos_new = le16_to_cpu(pstep->pos_new);
12756 
12757 	if (pcinfo->req_fver != pstep->fver)
12758 		return 0;
12759 
12760 	/* store step info by using ring instead of FIFO*/
12761 	do {
12762 		switch (state) {
12763 		case 0:
12764 			if (ver->fcxctrl == 7 || ver->fcxctrl == 1)
12765 				trace_step = 50;
12766 			else
12767 				trace_step = btc->ctrl.trace_step;
12768 
12769 			n_start = pos_old;
12770 			if (pos_new >=  pos_old)
12771 				n_stop = pos_new;
12772 			else
12773 				n_stop = trace_step - 1;
12774 
12775 			state = 1;
12776 			break;
12777 		case 1:
12778 			for (i = n_start; i <= n_stop; i++) {
12779 				type = pstep->step[i].type;
12780 				val = pstep->step[i].val;
12781 				diff_t = le16_to_cpu(pstep->step[i].difft);
12782 
12783 				if (type == CXSTEP_NONE || type >= CXSTEP_MAX)
12784 					continue;
12785 
12786 				if (cnt % 10 == 0)
12787 					p += scnprintf(p, end - p,
12788 						       " %-15s : ", "[steps]");
12789 
12790 				p += scnprintf(p, end - p,
12791 					       "-> %s(%02d)(%02d)",
12792 					       (type == CXSTEP_SLOT ? "SLT" :
12793 						"EVT"), (u32)val, diff_t);
12794 				if (cnt % 10 == 9)
12795 					p += scnprintf(p, end - p, "\n");
12796 				cnt++;
12797 			}
12798 
12799 			state = 2;
12800 			break;
12801 		case 2:
12802 			if (pos_new <  pos_old && n_start != 0) {
12803 				n_start = 0;
12804 				n_stop = pos_new;
12805 				state = 1;
12806 			} else {
12807 				outloop = true;
12808 			}
12809 			break;
12810 		}
12811 	} while (!outloop);
12812 
12813 	return p - buf;
12814 }
12815 
12816 static int _show_fbtc_step_v3(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12817 {
12818 	struct rtw89_btc *btc = &rtwdev->btc;
12819 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
12820 	struct rtw89_btc_rpt_cmn_info *pcinfo;
12821 	struct rtw89_btc_fbtc_steps_v3 *pstep;
12822 	u32 i, n_begin, n_end, array_idx, cnt = 0;
12823 	char *p = buf, *end = buf + bufsz;
12824 	u8 type, val;
12825 	u16 diff_t;
12826 
12827 	if ((pfwinfo->rpt_en_map &
12828 	     rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_FW_STEP_INFO)) == 0)
12829 		return 0;
12830 
12831 	pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
12832 	if (!pcinfo->valid)
12833 		return 0;
12834 
12835 	pstep = &pfwinfo->rpt_fbtc_step.finfo.v3;
12836 	if (pcinfo->req_fver != pstep->fver)
12837 		return 0;
12838 
12839 	if (le32_to_cpu(pstep->cnt) <= FCXDEF_STEP)
12840 		n_begin = 1;
12841 	else
12842 		n_begin = le32_to_cpu(pstep->cnt) - FCXDEF_STEP + 1;
12843 
12844 	n_end = le32_to_cpu(pstep->cnt);
12845 
12846 	if (n_begin > n_end)
12847 		return 0;
12848 
12849 	/* restore step info by using ring instead of FIFO */
12850 	for (i = n_begin; i <= n_end; i++) {
12851 		array_idx = (i - 1) % FCXDEF_STEP;
12852 		type = pstep->step[array_idx].type;
12853 		val = pstep->step[array_idx].val;
12854 		diff_t = le16_to_cpu(pstep->step[array_idx].difft);
12855 
12856 		if (type == CXSTEP_NONE || type >= CXSTEP_MAX)
12857 			continue;
12858 
12859 		if (cnt % 10 == 0)
12860 			p += scnprintf(p, end - p, " %-15s : ", "[steps]");
12861 
12862 		p += scnprintf(p, end - p, "-> %s(%02d)",
12863 			       (type == CXSTEP_SLOT ?
12864 				id_to_slot((u32)val) :
12865 				id_to_evt((u32)val)), diff_t);
12866 
12867 		if (cnt % 10 == 9)
12868 			p += scnprintf(p, end - p, "\n");
12869 
12870 		cnt++;
12871 	}
12872 
12873 	return p - buf;
12874 }
12875 
12876 static int _show_fw_dm_msg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12877 {
12878 	struct rtw89_btc *btc = &rtwdev->btc;
12879 	const struct rtw89_btc_ver *ver = btc->ver;
12880 	char *p = buf, *end = buf + bufsz;
12881 
12882 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM))
12883 		goto out;
12884 
12885 	p += _show_error(rtwdev, p, end - p);
12886 	p += _show_fbtc_tdma(rtwdev, p, end - p);
12887 	p += _show_fbtc_slots(rtwdev, p, end - p);
12888 
12889 	if (ver->fcxcysta == 2)
12890 		p += _show_fbtc_cysta_v2(rtwdev, p, end - p);
12891 	else if (ver->fcxcysta == 3)
12892 		p += _show_fbtc_cysta_v3(rtwdev, p, end - p);
12893 	else if (ver->fcxcysta == 4)
12894 		p += _show_fbtc_cysta_v4(rtwdev, p, end - p);
12895 	else if (ver->fcxcysta == 5)
12896 		p += _show_fbtc_cysta_v5(rtwdev, p, end - p);
12897 	else if (ver->fcxcysta == 105)
12898 		p += _show_fbtc_cysta_v105(rtwdev, p, end - p);
12899 	else if (ver->fcxcysta == 7)
12900 		p += _show_fbtc_cysta_v7(rtwdev, p, end - p);
12901 	else if (ver->fcxcysta == 8)
12902 		p += _show_fbtc_cysta_v8(rtwdev, p, end - p);
12903 
12904 	p += _show_fbtc_nullsta(rtwdev, p, end - p);
12905 
12906 	if (ver->fcxstep == 2)
12907 		p += _show_fbtc_step_v2(rtwdev, p, end - p);
12908 	else if (ver->fcxstep == 3)
12909 		p += _show_fbtc_step_v3(rtwdev, p, end - p);
12910 
12911 out:
12912 	return p - buf;
12913 }
12914 
12915 static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt_cfg)
12916 {
12917 	const struct rtw89_chip_info *chip = rtwdev->chip;
12918 	struct rtw89_mac_ax_wl_act *bt;
12919 	struct rtw89_mac_ax_gnt *gnt;
12920 	u32 val, status;
12921 
12922 	if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B ||
12923 	    chip->chip_id == RTL8851B || chip->chip_id == RTL8852BT) {
12924 		rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val);
12925 		rtw89_mac_read_lte(rtwdev, R_AX_GNT_VAL, &status);
12926 
12927 		gnt = &gnt_cfg->band[0];
12928 		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S0_SW_CTRL);
12929 		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S0_STA);
12930 		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S0_SW_CTRL);
12931 		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S0_STA);
12932 
12933 		gnt = &gnt_cfg->band[1];
12934 		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S1_SW_CTRL);
12935 		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S1_STA);
12936 		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S1_SW_CTRL);
12937 		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S1_STA);
12938 	} else if (chip->chip_id == RTL8852C) {
12939 		val = rtw89_read32(rtwdev, R_AX_GNT_SW_CTRL);
12940 		status = rtw89_read32(rtwdev, R_AX_GNT_VAL_V1);
12941 
12942 		gnt = &gnt_cfg->band[0];
12943 		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S0_SWCTRL);
12944 		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S0);
12945 		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S0_SWCTRL);
12946 		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S0);
12947 
12948 		gnt = &gnt_cfg->band[1];
12949 		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S1_SWCTRL);
12950 		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S1);
12951 		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S1_SWCTRL);
12952 		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S1);
12953 
12954 		bt = &gnt_cfg->bt[0];
12955 		bt->wlan_act_en = !!(val & B_BE_WL_ACT_SWCTRL);
12956 		bt->wlan_act = !!(status & B_BE_WL_ACT_VAL);
12957 
12958 		bt = &gnt_cfg->bt[1];
12959 		bt->wlan_act_en = !!(val & B_BE_WL_ACT2_SWCTRL);
12960 		bt->wlan_act = !!(status & B_BE_WL_ACT2_VAL);
12961 	} else if (chip->chip_id == RTL8922A) {
12962 		val = rtw89_read32(rtwdev, R_BE_GNT_SW_CTRL);
12963 		status = rtw89_read32(rtwdev, R_BE_PTA_GNT_VAL);
12964 
12965 		gnt = &gnt_cfg->band[0];
12966 		gnt->gnt_bt_sw_en = !!(val & B_BE_GNT_BT_BB0_SWCTRL);
12967 		gnt->gnt_bt = !!(status & B_BE_GNT_BT_BB0_VAL);
12968 		gnt->gnt_wl_sw_en = !!(val & B_BE_GNT_WL_BB0_SWCTRL);
12969 		gnt->gnt_wl = !!(status & B_BE_GNT_WL_BB0_VAL);
12970 
12971 		gnt = &gnt_cfg->band[1];
12972 		gnt->gnt_bt_sw_en = !!(val & B_BE_GNT_BT_BB1_SWCTRL);
12973 		gnt->gnt_bt = !!(status & B_BE_GNT_BT_BB1_VAL);
12974 		gnt->gnt_wl_sw_en = !!(val & B_BE_GNT_WL_BB1_SWCTRL);
12975 		gnt->gnt_wl = !!(status & B_BE_GNT_WL_BB1_VAL);
12976 
12977 		bt = &gnt_cfg->bt[0];
12978 		bt->wlan_act_en = !!(val & B_BE_WL_ACT_SWCTRL);
12979 		bt->wlan_act = !!(status & B_BE_WL_ACT_VAL);
12980 
12981 		bt = &gnt_cfg->bt[1];
12982 		bt->wlan_act_en = !!(val & B_BE_WL_ACT2_SWCTRL);
12983 		bt->wlan_act = !!(status & B_BE_WL_ACT2_VAL);
12984 	} else if (chip->chip_id == RTL8922D) {
12985 		/* Get from firmware */
12986 		return;
12987 	}
12988 }
12989 
12990 static int _show_gpio_dbg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
12991 {
12992 	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
12993 	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
12994 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
12995 	union rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
12996 	char *p = buf, *end = buf + bufsz;
12997 	u32 en_map_raw, en_map;
12998 	u8 *gpio_map, i, sig;
12999 
13000 	pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
13001 	gdbg = &rtwdev->btc.fwinfo.rpt_fbtc_gpio_dbg.finfo;
13002 	if (!pcinfo->valid) {
13003 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
13004 			    "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n",
13005 			    __func__);
13006 		goto out;
13007 	}
13008 
13009 	if (ver->fcxgpiodbg == 7 || ver->fcxgpiodbg == 8) {
13010 		en_map_raw = le32_to_cpu(gdbg->v7.en_map);
13011 		gpio_map = gdbg->v7.gpio_map;
13012 	} else {
13013 		en_map_raw = le32_to_cpu(gdbg->v1.en_map);
13014 		gpio_map = gdbg->v1.gpio_map;
13015 	}
13016 
13017 	en_map = _convert_gpio_enmap_from_ver(rtwdev, en_map_raw);
13018 	if (!en_map)
13019 		goto out;
13020 
13021 	p += scnprintf(p, end - p, "\n %-15s : enable_map:0x%08x",
13022 		       "[gpio_dbg]", en_map);
13023 
13024 	for (i = 0; i < BTC_DBG_NUM; i++) {
13025 		if (!(en_map & BIT(i)))
13026 			continue;
13027 
13028 		sig = ver->fcxgpiodbg >= 8 ? i : _get_gpiosig_for_ver(rtwdev, i);
13029 		if (sig >= BTC_DBG_NUM)
13030 			continue;
13031 
13032 		p += scnprintf(p, end - p, ", %s->GPIO%d", id_to_gdbg(i),
13033 			       gpio_map[sig]);
13034 	}
13035 
13036 out:
13037 	return p - buf;
13038 }
13039 
13040 static int _show_mreg_v1(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13041 {
13042 	const struct rtw89_chip_info *chip = rtwdev->chip;
13043 	struct rtw89_btc *btc = &rtwdev->btc;
13044 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
13045 	struct rtw89_btc_fbtc_mreg_val_v1 *pmreg = NULL;
13046 	struct rtw89_btc_bt_info *bt0 = &btc->cx.bt0;
13047 	struct rtw89_btc_bt_info *bt1 = &btc->cx.bt1;
13048 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
13049 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
13050 	struct rtw89_mac_ax_coex_gnt gnt_cfg = {};
13051 	struct rtw89_mac_ax_gnt gnt;
13052 	char *p = buf, *end = buf + bufsz;
13053 	u8 i = 0, type = 0, cnt = 0;
13054 	u32 val, offset;
13055 
13056 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_MREG))
13057 		return 0;
13058 
13059 	p += scnprintf(p, end - p, "========== [HW Status] ==========\n");
13060 
13061 	p += scnprintf(p, end - p,
13062 		       " %-15s : WL->BT0:0x%08x(cnt:%d), BT0->WL:0x%08x(total:%d, bt_update:%d)\n",
13063 		       "[scoreboard]", wl->scbd[BTC_BT_1ST],
13064 		       wl->wcnt[BTC_WCNT_SCBDUPDATE],
13065 		       bt0->scbd, bt0->bcnt[BTC_BCNT_SCBDREAD],
13066 		       bt0->bcnt[BTC_BCNT_SCBDUPDATE]);
13067 
13068 	if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
13069 		p += scnprintf(p, end - p,
13070 			       " %-15s : WL->BT1:0x%08x(cnt:%d), BT1->WL:0x%08x(total:%d, bt_update:%d)\n",
13071 			       "[scoreboard]", wl->scbd[BTC_BT_2ND],
13072 			       wl->wcnt[BTC_WCNT_SCBDUPDATE2],
13073 			       bt1->scbd, bt1->bcnt[BTC_BCNT_SCBDREAD],
13074 			       bt1->bcnt[BTC_BCNT_SCBDUPDATE]);
13075 	}
13076 
13077 	btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
13078 	_get_gnt(rtwdev, &gnt_cfg);
13079 
13080 	gnt = gnt_cfg.band[0];
13081 	p += scnprintf(p, end - p,
13082 		       " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
13083 		       "[gnt_status]",
13084 		       chip->chip_id == RTL8852C ? "HW" :
13085 		       btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
13086 		       gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
13087 		       gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
13088 
13089 	gnt = gnt_cfg.band[1];
13090 	p += scnprintf(p, end - p, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
13091 		       gnt.gnt_wl_sw_en ? "SW" : "HW",
13092 		       gnt.gnt_wl,
13093 		       gnt.gnt_bt_sw_en ? "SW" : "HW",
13094 		       gnt.gnt_bt);
13095 
13096 	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
13097 	if (!pcinfo->valid) {
13098 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
13099 			    "[BTC], %s(): stop due rpt_fbtc_mregval.cinfo\n",
13100 			    __func__);
13101 		goto out;
13102 	}
13103 
13104 	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo.v1;
13105 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
13106 		    "[BTC], %s(): rpt_fbtc_mregval reg_num = %d\n",
13107 		    __func__, pmreg->reg_num);
13108 
13109 	for (i = 0; i < pmreg->reg_num; i++) {
13110 		type = (u8)le16_to_cpu(chip->mon_reg[i].type);
13111 		offset = le32_to_cpu(chip->mon_reg[i].offset);
13112 		val = le32_to_cpu(pmreg->mreg_val[i]);
13113 
13114 		if (cnt % 6 == 0)
13115 			p += scnprintf(p, end - p,
13116 				       " %-15s : %d_0x%04x=0x%08x",
13117 				       "[reg]", (u32)type, offset, val);
13118 		else
13119 			p += scnprintf(p, end - p, ", %d_0x%04x=0x%08x",
13120 				       (u32)type,
13121 				       offset, val);
13122 		if (cnt % 6 == 5)
13123 			p += scnprintf(p, end - p, "\n");
13124 		cnt++;
13125 
13126 		if (i >= pmreg->reg_num)
13127 			p += scnprintf(p, end - p, "\n");
13128 	}
13129 
13130 out:
13131 	return p - buf;
13132 }
13133 
13134 static int _show_mreg_v2(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13135 {
13136 	const struct rtw89_chip_info *chip = rtwdev->chip;
13137 	struct rtw89_btc *btc = &rtwdev->btc;
13138 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
13139 	struct rtw89_btc_fbtc_mreg_val_v2 *pmreg = NULL;
13140 	struct rtw89_btc_bt_info *bt0 = &btc->cx.bt0;
13141 	struct rtw89_btc_bt_info *bt1 = &btc->cx.bt1;
13142 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
13143 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
13144 	struct rtw89_mac_ax_coex_gnt gnt_cfg = {};
13145 	struct rtw89_mac_ax_gnt gnt;
13146 	char *p = buf, *end = buf + bufsz;
13147 	u8 i = 0, type = 0, cnt = 0;
13148 	u32 val, offset;
13149 
13150 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_MREG))
13151 		return 0;
13152 
13153 	p += scnprintf(p, end - p, "========== [HW Status] ==========\n");
13154 
13155 	p += scnprintf(p, end - p,
13156 		       " %-15s : WL->BT0:0x%08x(cnt:%d), BT0->WL:0x%08x(total:%d, bt_update:%d)\n",
13157 		       "[scoreboard]", wl->scbd[BTC_BT_1ST],
13158 		       wl->wcnt[BTC_WCNT_SCBDUPDATE],
13159 		       bt0->scbd, bt0->bcnt[BTC_BCNT_SCBDREAD],
13160 		       bt0->bcnt[BTC_BCNT_SCBDUPDATE]);
13161 
13162 	if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
13163 		p += scnprintf(p, end - p,
13164 			       " %-15s : WL->BT1:0x%08x(cnt:%d), BT1->WL:0x%08x(total:%d, bt_update:%d)\n",
13165 			       "[scoreboard]", wl->scbd[BTC_BT_2ND],
13166 			       wl->wcnt[BTC_WCNT_SCBDUPDATE2],
13167 			       bt1->scbd, bt1->bcnt[BTC_BCNT_SCBDREAD],
13168 			       bt1->bcnt[BTC_BCNT_SCBDUPDATE]);
13169 	}
13170 
13171 	btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
13172 	_get_gnt(rtwdev, &gnt_cfg);
13173 
13174 	gnt = gnt_cfg.band[0];
13175 	p += scnprintf(p, end - p,
13176 		       " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], polut_type:%s",
13177 		       "[gnt_status]",
13178 		       chip->chip_id == RTL8852C ? "HW" :
13179 		       btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
13180 		       gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
13181 		       gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt,
13182 		       id_to_polut(wl->bt_polut_type[wl->pta_req_mac]));
13183 
13184 	gnt = gnt_cfg.band[1];
13185 	p += scnprintf(p, end - p, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
13186 		       gnt.gnt_wl_sw_en ? "SW" : "HW",
13187 		       gnt.gnt_wl,
13188 		       gnt.gnt_bt_sw_en ? "SW" : "HW",
13189 		       gnt.gnt_bt);
13190 
13191 	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
13192 	if (!pcinfo->valid) {
13193 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
13194 			    "[BTC], %s(): stop due rpt_fbtc_mregval.cinfo\n",
13195 			    __func__);
13196 		goto out;
13197 	}
13198 
13199 	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo.v2;
13200 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
13201 		    "[BTC], %s(): rpt_fbtc_mregval reg_num = %d\n",
13202 		    __func__, pmreg->reg_num);
13203 
13204 	for (i = 0; i < pmreg->reg_num; i++) {
13205 		type = (u8)le16_to_cpu(chip->mon_reg[i].type);
13206 		offset = le32_to_cpu(chip->mon_reg[i].offset);
13207 		val = le32_to_cpu(pmreg->mreg_val[i]);
13208 
13209 		if (cnt % 6 == 0)
13210 			p += scnprintf(p, end - p,
13211 				       " %-15s : %d_0x%04x=0x%08x",
13212 				       "[reg]", (u32)type, offset, val);
13213 		else
13214 			p += scnprintf(p, end - p, ", %d_0x%04x=0x%08x",
13215 				       (u32)type,
13216 				       offset, val);
13217 		if (cnt % 6 == 5)
13218 			p += scnprintf(p, end - p, "\n");
13219 		cnt++;
13220 
13221 		if (i >= pmreg->reg_num)
13222 			p += scnprintf(p, end - p, "\n");
13223 	}
13224 
13225 out:
13226 	return p - buf;
13227 }
13228 
13229 static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13230 {
13231 	struct rtw89_btc *btc = &rtwdev->btc;
13232 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
13233 	struct rtw89_btc_fbtc_mreg_val_v7 *pmreg = NULL;
13234 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
13235 	struct rtw89_btc_cx *cx = &btc->cx;
13236 	struct rtw89_btc_bt_info *bt0 = &cx->bt0;
13237 	struct rtw89_btc_bt_info *bt1 = &cx->bt1;
13238 	struct rtw89_btc_wl_info *wl = &cx->wl;
13239 	struct rtw89_btc_dm *dm = &btc->dm;
13240 	char *p = buf, *end = buf + bufsz;
13241 	u8 i, type, cnt = 0;
13242 	u32 val, offset;
13243 
13244 	if (!(dm->coex_info_map & BTC_COEX_INFO_MREG))
13245 		return 0;
13246 
13247 	p += scnprintf(p, end - p, "\n========== [HW Status] ==========\n");
13248 
13249 	p += scnprintf(p, end - p,
13250 		       " %-15s : WL->BT0:0x%08x(cnt:%d), BT0->WL:0x%08x(total:%d, bt_update:%d)\n",
13251 		       "[scoreboard]", wl->scbd[BTC_BT_1ST],
13252 		       wl->wcnt[BTC_WCNT_SCBDUPDATE],
13253 		       bt0->scbd, bt0->bcnt[BTC_BCNT_SCBDREAD],
13254 		       bt0->bcnt[BTC_BCNT_SCBDUPDATE]);
13255 
13256 	if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
13257 		p += scnprintf(p, end - p,
13258 			       " %-15s : WL->BT1:0x%08x(cnt:%d), BT1->WL:0x%08x(total:%d, bt_update:%d)\n",
13259 			       "[scoreboard]", wl->scbd[BTC_BT_2ND],
13260 			       wl->wcnt[BTC_WCNT_SCBDUPDATE2],
13261 			       bt1->scbd, bt1->bcnt[BTC_BCNT_SCBDREAD],
13262 			       bt1->bcnt[BTC_BCNT_SCBDUPDATE]);
13263 	}
13264 
13265 	/* To avoid I/O if WL LPS or power-off  */
13266 	dm->pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
13267 
13268 	p += scnprintf(p, end - p,
13269 		       " %-15s : pta_owner:%s, pta_req_mac:MAC%d, rf_gnt_source: polut_type:%s\n",
13270 		       "[gnt_status]",
13271 		       rtwdev->chip->para_ver & BTC_FEAT_PTA_ONOFF_CTRL ? "HW" :
13272 		       dm->pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
13273 		       wl->pta_req_mac,
13274 		       id_to_polut(wl->bt_polut_type[wl->pta_req_mac]));
13275 
13276 	if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT)
13277 		p += scnprintf(p, end - p,
13278 			       " %-15s : phy-0[gnt_wl:%s-%d/gnt_bt0:%s-%d/gnt_bt1:%s-%d]",
13279 			       "[gnt_status]",
13280 			       dm->gnt_set[RTW89_PHY_0].gnt_wl_sw_en ? "SW" : "HW",
13281 			       dm->gnt_set[RTW89_PHY_0].gnt_wl,
13282 			       dm->gnt_set[RTW89_PHY_0].gnt_bt0_sw_en ? "SW" : "HW",
13283 			       dm->gnt_set[RTW89_PHY_0].gnt_bt0,
13284 			       dm->gnt_set[RTW89_PHY_0].gnt_bt1_sw_en ? "SW" : "HW",
13285 			       dm->gnt_set[RTW89_PHY_0].gnt_bt1);
13286 	else
13287 		p += scnprintf(p, end - p,
13288 			       " %-15s : phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d]",
13289 			       "[gnt_status]",
13290 			       dm->gnt_set[RTW89_PHY_0].gnt_wl_sw_en ? "SW" : "HW",
13291 			       dm->gnt_set[RTW89_PHY_0].gnt_wl,
13292 			       dm->gnt_set[RTW89_PHY_0].gnt_bt0_sw_en ? "SW" : "HW",
13293 			       dm->gnt_set[RTW89_PHY_0].gnt_bt0);
13294 
13295 	if (rtwdev->dbcc_en) {
13296 		if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT)
13297 			p += scnprintf(p, end - p,
13298 				       ", phy-1[gnt_wl:%s-%d/gnt_bt0:%s-%d/gnt_bt1:%s-%d]",
13299 				       dm->gnt_set[RTW89_PHY_1].gnt_wl_sw_en ? "SW" : "HW",
13300 				       dm->gnt_set[RTW89_PHY_1].gnt_wl,
13301 				       dm->gnt_set[RTW89_PHY_1].gnt_bt0_sw_en ? "SW" : "HW",
13302 				       dm->gnt_set[RTW89_PHY_1].gnt_bt0,
13303 				       dm->gnt_set[RTW89_PHY_1].gnt_bt1_sw_en ? "SW" : "HW",
13304 				       dm->gnt_set[RTW89_PHY_1].gnt_bt1);
13305 		else
13306 			p += scnprintf(p, end - p,
13307 				       ", phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]",
13308 				       dm->gnt_set[RTW89_PHY_1].gnt_wl_sw_en ? "SW" : "HW",
13309 				       dm->gnt_set[RTW89_PHY_1].gnt_wl,
13310 				       dm->gnt_set[RTW89_PHY_1].gnt_bt0_sw_en ? "SW" : "HW",
13311 				       dm->gnt_set[RTW89_PHY_1].gnt_bt0);
13312 	}
13313 
13314 	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
13315 	if (!pcinfo->valid)
13316 		goto out;
13317 
13318 	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo.v7;
13319 
13320 	for (i = 0; i < pmreg->reg_num; i++) {
13321 		type = (u8)le16_to_cpu(rtwdev->chip->mon_reg[i].type);
13322 		offset = le32_to_cpu(rtwdev->chip->mon_reg[i].offset);
13323 		val = le32_to_cpu(pmreg->mreg_val[i]);
13324 
13325 		if (cnt % 6 == 0)
13326 			p += scnprintf(p, end - p,
13327 				       "\n %-15s : %s_0x%x=0x%x", "[reg]",
13328 				       id_to_regtype(type), offset, val);
13329 		else
13330 			p += scnprintf(p, end - p, ", %s_0x%x=0x%x",
13331 				       id_to_regtype(type), offset, val);
13332 		cnt++;
13333 	}
13334 
13335 out:
13336 	return p - buf;
13337 }
13338 
13339 static int _show_summary_v1(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13340 {
13341 	struct rtw89_btc *btc = &rtwdev->btc;
13342 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
13343 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
13344 	struct rtw89_btc_fbtc_rpt_ctrl_v1 *prptctrl = NULL;
13345 	struct rtw89_btc_cx *cx = &btc->cx;
13346 	struct rtw89_btc_dm *dm = &btc->dm;
13347 	struct rtw89_btc_wl_info *wl = &cx->wl;
13348 	struct rtw89_btc_bt_info *bt = &cx->bt0;
13349 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
13350 	char *p = buf, *end = buf + bufsz;
13351 	u8 i;
13352 
13353 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
13354 		return 0;
13355 
13356 	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
13357 
13358 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
13359 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
13360 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v1;
13361 
13362 		p += scnprintf(p, end - p,
13363 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
13364 			       "[summary]", pfwinfo->cnt_h2c,
13365 			       pfwinfo->cnt_h2c_fail, prptctrl->h2c_cnt,
13366 			       pfwinfo->cnt_c2h, prptctrl->c2h_cnt);
13367 
13368 		p += scnprintf(p, end - p,
13369 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
13370 			       pfwinfo->event[BTF_EVNT_RPT],
13371 			       prptctrl->rpt_cnt,
13372 			       prptctrl->rpt_enable, dm->error.val);
13373 
13374 		if (dm->error.map.wl_fw_hang)
13375 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
13376 		p += scnprintf(p, end - p, "\n");
13377 		p += scnprintf(p, end - p,
13378 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d",
13379 			       "[mailbox]", prptctrl->mb_send_ok_cnt,
13380 			       prptctrl->mb_send_fail_cnt,
13381 			       prptctrl->mb_recv_cnt);
13382 
13383 		p += scnprintf(p, end - p,
13384 			       "(A2DP_empty:%d, A2DP_flowstop:%d, A2DP_full:%d)\n",
13385 			       prptctrl->mb_a2dp_empty_cnt,
13386 			       prptctrl->mb_a2dp_flct_cnt,
13387 			       prptctrl->mb_a2dp_full_cnt);
13388 
13389 		p += scnprintf(p, end - p,
13390 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
13391 			       "[RFK]", wl->wcnt[BTC_WCNT_RFK_REQ],
13392 			       wl->wcnt[BTC_WCNT_RFK_GO],
13393 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
13394 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT]);
13395 
13396 		p += scnprintf(p, end - p,
13397 			       ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
13398 			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REQ],
13399 			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_GO],
13400 			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REJECT],
13401 			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT],
13402 			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_FAIL]);
13403 
13404 		if (prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT] > 0)
13405 			bt->rfk_info.map.timeout = 1;
13406 		else
13407 			bt->rfk_info.map.timeout = 0;
13408 
13409 		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
13410 	} else {
13411 		p += scnprintf(p, end - p,
13412 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
13413 			       "[summary]", pfwinfo->cnt_h2c,
13414 			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
13415 			       pfwinfo->event[BTF_EVNT_RPT],
13416 			       btc->fwinfo.rpt_en_map);
13417 		p += scnprintf(p, end - p, " (WL FW report invalid!!)\n");
13418 	}
13419 
13420 	for (i = 0; i < BTC_NCNT_NUM; i++)
13421 		cnt_sum += dm->cnt_notify[i];
13422 
13423 	p += scnprintf(p, end - p,
13424 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
13425 		       "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
13426 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
13427 
13428 	p += scnprintf(p, end - p,
13429 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
13430 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
13431 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
13432 		       cnt[BTC_NCNT_WL_STA]);
13433 
13434 	p += scnprintf(p, end - p,
13435 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
13436 		       "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
13437 		       cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
13438 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
13439 
13440 	p += scnprintf(p, end - p,
13441 		       "timer=%d, control=%d, customerize=%d\n",
13442 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
13443 		       cnt[BTC_NCNT_CUSTOMERIZE]);
13444 
13445 	return p - buf;
13446 }
13447 
13448 static int _show_summary_v4(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13449 {
13450 	struct rtw89_btc *btc = &rtwdev->btc;
13451 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
13452 	struct rtw89_btc_fbtc_rpt_ctrl_v4 *prptctrl;
13453 	struct rtw89_btc_rpt_cmn_info *pcinfo;
13454 	struct rtw89_btc_cx *cx = &btc->cx;
13455 	struct rtw89_btc_dm *dm = &btc->dm;
13456 	struct rtw89_btc_wl_info *wl = &cx->wl;
13457 	struct rtw89_btc_bt_info *bt = &cx->bt0;
13458 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
13459 	char *p = buf, *end = buf + bufsz;
13460 	u8 i;
13461 
13462 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
13463 		return 0;
13464 
13465 	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
13466 
13467 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
13468 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
13469 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v4;
13470 
13471 		p += scnprintf(p, end - p,
13472 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
13473 			       "[summary]", pfwinfo->cnt_h2c,
13474 			       pfwinfo->cnt_h2c_fail,
13475 			       le32_to_cpu(prptctrl->rpt_info.cnt_h2c),
13476 			       pfwinfo->cnt_c2h,
13477 			       le32_to_cpu(prptctrl->rpt_info.cnt_c2h));
13478 
13479 		p += scnprintf(p, end - p,
13480 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
13481 			       pfwinfo->event[BTF_EVNT_RPT],
13482 			       le32_to_cpu(prptctrl->rpt_info.cnt),
13483 			       le32_to_cpu(prptctrl->rpt_info.en),
13484 			       dm->error.val);
13485 
13486 		if (dm->error.map.wl_fw_hang)
13487 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
13488 		p += scnprintf(p, end - p, "\n");
13489 		p += scnprintf(p, end - p,
13490 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
13491 			       "[mailbox]",
13492 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
13493 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
13494 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
13495 
13496 		p += scnprintf(p, end - p,
13497 			       "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
13498 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
13499 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
13500 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
13501 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
13502 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
13503 
13504 		p += scnprintf(p, end - p,
13505 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
13506 			       "[RFK]", wl->wcnt[BTC_WCNT_RFK_REQ],
13507 			       wl->wcnt[BTC_WCNT_RFK_GO],
13508 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
13509 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT]);
13510 
13511 		p += scnprintf(p, end - p,
13512 			       ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
13513 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]),
13514 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_GO]),
13515 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REJECT]),
13516 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]),
13517 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_FAIL]));
13518 
13519 		if (le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
13520 			bt->rfk_info.map.timeout = 1;
13521 		else
13522 			bt->rfk_info.map.timeout = 0;
13523 
13524 		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
13525 	} else {
13526 		p += scnprintf(p, end - p,
13527 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
13528 			       "[summary]", pfwinfo->cnt_h2c,
13529 			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
13530 			       pfwinfo->event[BTF_EVNT_RPT],
13531 			       btc->fwinfo.rpt_en_map);
13532 		p += scnprintf(p, end - p, " (WL FW report invalid!!)\n");
13533 	}
13534 
13535 	for (i = 0; i < BTC_NCNT_NUM; i++)
13536 		cnt_sum += dm->cnt_notify[i];
13537 
13538 	p += scnprintf(p, end - p,
13539 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
13540 		       "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
13541 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
13542 
13543 	p += scnprintf(p, end - p,
13544 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
13545 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
13546 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
13547 		       cnt[BTC_NCNT_WL_STA]);
13548 
13549 	p += scnprintf(p, end - p,
13550 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
13551 		       "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
13552 		       cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
13553 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
13554 
13555 	p += scnprintf(p, end - p,
13556 		       "timer=%d, control=%d, customerize=%d\n",
13557 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
13558 		       cnt[BTC_NCNT_CUSTOMERIZE]);
13559 
13560 	return p - buf;
13561 }
13562 
13563 static int _show_summary_v5(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13564 {
13565 	struct rtw89_btc *btc = &rtwdev->btc;
13566 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
13567 	struct rtw89_btc_fbtc_rpt_ctrl_v5 *prptctrl;
13568 	struct rtw89_btc_rpt_cmn_info *pcinfo;
13569 	struct rtw89_btc_cx *cx = &btc->cx;
13570 	struct rtw89_btc_dm *dm = &btc->dm;
13571 	struct rtw89_btc_wl_info *wl = &cx->wl;
13572 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
13573 	char *p = buf, *end = buf + bufsz;
13574 	u8 i;
13575 
13576 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
13577 		return 0;
13578 
13579 	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
13580 
13581 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
13582 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
13583 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v5;
13584 
13585 		p += scnprintf(p, end - p,
13586 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d), ",
13587 			       "[summary]", pfwinfo->cnt_h2c,
13588 			       pfwinfo->cnt_h2c_fail,
13589 			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
13590 			       pfwinfo->cnt_c2h,
13591 			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
13592 			       le16_to_cpu(prptctrl->rpt_info.len_c2h));
13593 
13594 		p += scnprintf(p, end - p,
13595 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
13596 			       pfwinfo->event[BTF_EVNT_RPT],
13597 			       le16_to_cpu(prptctrl->rpt_info.cnt),
13598 			       le32_to_cpu(prptctrl->rpt_info.en));
13599 
13600 		if (dm->error.map.wl_fw_hang)
13601 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
13602 		p += scnprintf(p, end - p, "\n");
13603 		p += scnprintf(p, end - p,
13604 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
13605 			       "[mailbox]",
13606 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
13607 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
13608 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
13609 
13610 		p += scnprintf(p, end - p,
13611 			       "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
13612 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
13613 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
13614 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
13615 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
13616 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
13617 
13618 		p += scnprintf(p, end - p,
13619 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d]",
13620 			       "[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
13621 			       wl->wcnt[BTC_WCNT_RFK_GO],
13622 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
13623 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT]);
13624 
13625 		p += scnprintf(p, end - p,
13626 			       ", bt_rfk[req:%d]",
13627 			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
13628 
13629 		p += scnprintf(p, end - p,
13630 			       ", AOAC[RF_on:%d/RF_off:%d]",
13631 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
13632 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
13633 	} else {
13634 		p += scnprintf(p, end - p,
13635 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d",
13636 			       "[summary]", pfwinfo->cnt_h2c,
13637 			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h);
13638 	}
13639 
13640 	if (!pcinfo->valid || pfwinfo->len_mismch || pfwinfo->fver_mismch ||
13641 	    pfwinfo->err[BTFRE_EXCEPTION]) {
13642 		p += scnprintf(p, end - p, "\n");
13643 		p += scnprintf(p, end - p,
13644 			       " %-15s : WL FW rpt error!![rpt_ctrl_valid:%d/len:"
13645 			       "0x%x/ver:0x%x/ex:%d/lps=%d/rf_off=%d]",
13646 			       "[ERROR]", pcinfo->valid, pfwinfo->len_mismch,
13647 			       pfwinfo->fver_mismch,
13648 			       pfwinfo->err[BTFRE_EXCEPTION],
13649 			       wl->status.map.lps, wl->status.map.rf_off);
13650 	}
13651 
13652 	for (i = 0; i < BTC_NCNT_NUM; i++)
13653 		cnt_sum += dm->cnt_notify[i];
13654 
13655 	p += scnprintf(p, end - p, "\n");
13656 	p += scnprintf(p, end - p,
13657 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
13658 		       "[notify_cnt]",
13659 		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
13660 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
13661 
13662 	p += scnprintf(p, end - p,
13663 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
13664 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
13665 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
13666 		       cnt[BTC_NCNT_WL_STA]);
13667 
13668 	p += scnprintf(p, end - p,
13669 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
13670 		       "[notify_cnt]",
13671 		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
13672 		       cnt[BTC_NCNT_SWITCH_BAND],
13673 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
13674 
13675 	p += scnprintf(p, end - p,
13676 		       "timer=%d, control=%d, customerize=%d",
13677 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
13678 		       cnt[BTC_NCNT_CUSTOMERIZE]);
13679 
13680 	return p - buf;
13681 }
13682 
13683 static int _show_summary_v105(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13684 {
13685 	struct rtw89_btc *btc = &rtwdev->btc;
13686 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
13687 	struct rtw89_btc_fbtc_rpt_ctrl_v105 *prptctrl;
13688 	struct rtw89_btc_rpt_cmn_info *pcinfo;
13689 	struct rtw89_btc_cx *cx = &btc->cx;
13690 	struct rtw89_btc_dm *dm = &btc->dm;
13691 	struct rtw89_btc_wl_info *wl = &cx->wl;
13692 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
13693 	char *p = buf, *end = buf + bufsz;
13694 	u8 i;
13695 
13696 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
13697 		return 0;
13698 
13699 	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
13700 
13701 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
13702 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
13703 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v105;
13704 
13705 		p += scnprintf(p, end - p,
13706 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d), ",
13707 			       "[summary]", pfwinfo->cnt_h2c,
13708 			       pfwinfo->cnt_h2c_fail,
13709 			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
13710 			       pfwinfo->cnt_c2h,
13711 			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
13712 			       le16_to_cpu(prptctrl->rpt_info.len_c2h));
13713 
13714 		p += scnprintf(p, end - p,
13715 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
13716 			       pfwinfo->event[BTF_EVNT_RPT],
13717 			       le16_to_cpu(prptctrl->rpt_info.cnt),
13718 			       le32_to_cpu(prptctrl->rpt_info.en));
13719 
13720 		if (dm->error.map.wl_fw_hang)
13721 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
13722 		p += scnprintf(p, end - p, "\n");
13723 		p += scnprintf(p, end - p,
13724 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
13725 			       "[mailbox]",
13726 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
13727 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
13728 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
13729 
13730 		p += scnprintf(p, end - p,
13731 			       "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
13732 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
13733 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
13734 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
13735 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
13736 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
13737 
13738 		p += scnprintf(p, end - p,
13739 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d]",
13740 			       "[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
13741 			       wl->wcnt[BTC_WCNT_RFK_GO],
13742 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
13743 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT]);
13744 
13745 		p += scnprintf(p, end - p,
13746 			       ", bt_rfk[req:%d]",
13747 			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
13748 
13749 		p += scnprintf(p, end - p,
13750 			       ", AOAC[RF_on:%d/RF_off:%d]",
13751 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
13752 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
13753 	} else {
13754 		p += scnprintf(p, end - p,
13755 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d",
13756 			       "[summary]", pfwinfo->cnt_h2c,
13757 			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h);
13758 	}
13759 
13760 	if (!pcinfo->valid || pfwinfo->len_mismch || pfwinfo->fver_mismch ||
13761 	    pfwinfo->err[BTFRE_EXCEPTION]) {
13762 		p += scnprintf(p, end - p, "\n");
13763 		p += scnprintf(p, end - p,
13764 			       " %-15s : WL FW rpt error!![rpt_ctrl_valid:%d/len:"
13765 			       "0x%x/ver:0x%x/ex:%d/lps=%d/rf_off=%d]",
13766 			       "[ERROR]", pcinfo->valid, pfwinfo->len_mismch,
13767 			       pfwinfo->fver_mismch,
13768 			       pfwinfo->err[BTFRE_EXCEPTION],
13769 			       wl->status.map.lps, wl->status.map.rf_off);
13770 	}
13771 
13772 	for (i = 0; i < BTC_NCNT_NUM; i++)
13773 		cnt_sum += dm->cnt_notify[i];
13774 
13775 	p += scnprintf(p, end - p, "\n");
13776 	p += scnprintf(p, end - p,
13777 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
13778 		       "[notify_cnt]",
13779 		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
13780 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
13781 
13782 	p += scnprintf(p, end - p,
13783 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
13784 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
13785 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
13786 		       cnt[BTC_NCNT_WL_STA]);
13787 
13788 	p += scnprintf(p, end - p,
13789 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
13790 		       "[notify_cnt]",
13791 		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
13792 		       cnt[BTC_NCNT_SWITCH_BAND],
13793 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
13794 
13795 	p += scnprintf(p, end - p,
13796 		       "timer=%d, control=%d, customerize=%d",
13797 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
13798 		       cnt[BTC_NCNT_CUSTOMERIZE]);
13799 
13800 	return p - buf;
13801 }
13802 
13803 static int _show_summary_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13804 {
13805 	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
13806 	struct rtw89_btc_fbtc_rpt_ctrl_v7 *prptctrl = NULL;
13807 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
13808 	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
13809 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
13810 	struct rtw89_btc_wl_info *wl = &cx->wl;
13811 	u32 *cnt = rtwdev->btc.dm.cnt_notify;
13812 	char *p = buf, *end = buf + bufsz;
13813 	u32 cnt_sum = 0;
13814 	u8 i;
13815 
13816 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
13817 		return 0;
13818 
13819 	p += scnprintf(p, end - p, "%s",
13820 		       "\n========== [Statistics] ==========\n");
13821 
13822 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
13823 	if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
13824 	    !wl->status.map.rf_off) {
13825 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v7;
13826 
13827 		p += scnprintf(p, end - p,
13828 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d),"
13829 			       "c2h_cnt=%d(fw_send:%d, len:%d, max:%d), ",
13830 			       "[summary]", pfwinfo->cnt_h2c,
13831 			       pfwinfo->cnt_h2c_fail,
13832 			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
13833 			       pfwinfo->cnt_c2h,
13834 			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
13835 			       le16_to_cpu(prptctrl->rpt_info.len_c2h),
13836 			       rtwdev->btc.ver->info_buf);
13837 
13838 		p += scnprintf(p, end - p,
13839 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
13840 			       pfwinfo->event[BTF_EVNT_RPT],
13841 			       le16_to_cpu(prptctrl->rpt_info.cnt),
13842 			       le32_to_cpu(prptctrl->rpt_info.en));
13843 
13844 		if (dm->error.map.wl_fw_hang)
13845 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
13846 		p += scnprintf(p, end - p, "\n");
13847 
13848 		p += scnprintf(p, end - p,
13849 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
13850 			       "[mailbox]",
13851 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
13852 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
13853 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
13854 
13855 		p += scnprintf(p, end - p,
13856 			       "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)\n",
13857 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
13858 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
13859 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
13860 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
13861 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
13862 
13863 		p += scnprintf(p, end - p,
13864 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
13865 			       "[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
13866 			       wl->wcnt[BTC_WCNT_RFK_GO],
13867 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
13868 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT],
13869 			       wl->rfk_info.proc_time);
13870 
13871 		p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
13872 			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
13873 
13874 		p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]\n",
13875 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
13876 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
13877 	} else {
13878 		p += scnprintf(p, end - p,
13879 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)\n",
13880 			       "[summary]",
13881 			       pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
13882 			       pfwinfo->cnt_c2h,
13883 			       wl->status.map.lps, wl->status.map.rf_off);
13884 	}
13885 
13886 	for (i = 0; i < BTC_NCNT_NUM; i++)
13887 		cnt_sum += dm->cnt_notify[i];
13888 
13889 	p += scnprintf(p, end - p,
13890 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
13891 		       "[notify_cnt]",
13892 		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
13893 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
13894 
13895 	p += scnprintf(p, end - p,
13896 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
13897 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
13898 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
13899 		       cnt[BTC_NCNT_WL_STA]);
13900 
13901 	p += scnprintf(p, end - p,
13902 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
13903 		       "[notify_cnt]",
13904 		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
13905 		       cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
13906 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
13907 
13908 	p += scnprintf(p, end - p,
13909 		       "timer=%d, customerize=%d, hub_msg=%d, chg_fw=%d, send_cc=%d",
13910 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CUSTOMERIZE],
13911 		       rtwdev->btc.hubmsg_cnt, cnt[BTC_NCNT_RESUME_DL_FW],
13912 		       cnt[BTC_NCNT_COUNTRYCODE]);
13913 
13914 	return p - buf;
13915 }
13916 
13917 static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
13918 {
13919 	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
13920 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
13921 	struct rtw89_btc_fbtc_rpt_ctrl_v8 *prptctrl = NULL;
13922 	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
13923 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
13924 	struct rtw89_btc_wl_info *wl = &cx->wl;
13925 	u32 *cnt = rtwdev->btc.dm.cnt_notify;
13926 	char *p = buf, *end = buf + bufsz;
13927 	u32 cnt_sum = 0;
13928 	u8 i;
13929 
13930 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
13931 		return 0;
13932 
13933 	p += scnprintf(p, end - p, "%s",
13934 		       "\n========== [Statistics] ==========\n");
13935 
13936 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
13937 	if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
13938 	    !wl->status.map.rf_off) {
13939 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v8;
13940 
13941 		p += scnprintf(p, end - p,
13942 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, max:fw-%d/drv-%d), ",
13943 			       "[summary]", pfwinfo->cnt_h2c,
13944 			       pfwinfo->cnt_h2c_fail,
13945 			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
13946 			       pfwinfo->cnt_c2h,
13947 			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
13948 			       le16_to_cpu(prptctrl->rpt_info.len_c2h),
13949 			       (prptctrl->rpt_len_max_h << 8) + prptctrl->rpt_len_max_l,
13950 			       rtwdev->btc.ver->info_buf);
13951 
13952 		p += scnprintf(p, end - p,
13953 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
13954 			       pfwinfo->event[BTF_EVNT_RPT],
13955 			       le16_to_cpu(prptctrl->rpt_info.cnt),
13956 			       le32_to_cpu(prptctrl->rpt_info.en));
13957 
13958 		if (dm->error.map.wl_fw_hang)
13959 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
13960 		p += scnprintf(p, end - p, "\n");
13961 
13962 		p += scnprintf(p, end - p,
13963 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
13964 			       "[mailbox]",
13965 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
13966 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
13967 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
13968 
13969 		p += scnprintf(p, end - p,
13970 			       "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)\n",
13971 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
13972 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
13973 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
13974 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
13975 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
13976 
13977 		p += scnprintf(p, end - p,
13978 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
13979 			       "[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
13980 			       wl->wcnt[BTC_WCNT_RFK_GO],
13981 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
13982 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT],
13983 			       wl->rfk_info.proc_time);
13984 
13985 		p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
13986 			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
13987 
13988 		p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]\n",
13989 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
13990 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
13991 	} else {
13992 		p += scnprintf(p, end - p,
13993 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)\n",
13994 			       "[summary]",
13995 			       pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
13996 			       pfwinfo->cnt_c2h,
13997 			       wl->status.map.lps, wl->status.map.rf_off);
13998 	}
13999 
14000 	for (i = 0; i < BTC_NCNT_NUM; i++)
14001 		cnt_sum += dm->cnt_notify[i];
14002 
14003 	p += scnprintf(p, end - p,
14004 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
14005 		       "[notify_cnt]",
14006 		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
14007 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
14008 
14009 	p += scnprintf(p, end - p,
14010 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
14011 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
14012 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
14013 		       cnt[BTC_NCNT_WL_STA]);
14014 
14015 	p += scnprintf(p, end - p,
14016 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
14017 		       "[notify_cnt]",
14018 		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
14019 		       cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
14020 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
14021 
14022 	p += scnprintf(p, end - p,
14023 		       "timer=%d, customerize=%d, hub_msg=%d, chg_fw=%d, send_cc=%d",
14024 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CUSTOMERIZE],
14025 		       rtwdev->btc.hubmsg_cnt, cnt[BTC_NCNT_RESUME_DL_FW],
14026 		       cnt[BTC_NCNT_COUNTRYCODE]);
14027 
14028 	return p - buf;
14029 }
14030 
14031 static int _show_summary_v9(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
14032 {
14033 	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
14034 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
14035 	struct rtw89_btc_fbtc_rpt_ctrl_v9 *prptctrl = NULL;
14036 	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
14037 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
14038 	struct rtw89_btc_wl_info *wl = &cx->wl;
14039 	u32 *cnt = rtwdev->btc.dm.cnt_notify;
14040 	char *p = buf, *end = buf + bufsz;
14041 	u32 cnt_sum = 0;
14042 	u8 i;
14043 
14044 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
14045 		return 0;
14046 
14047 	p += scnprintf(p, end - p, "%s",
14048 		       "\n========== [Statistics] ==========\n");
14049 
14050 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
14051 	if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
14052 	    !wl->status.map.rf_off) {
14053 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v9;
14054 
14055 		p += scnprintf(p, end - p,
14056 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, ",
14057 			       "[summary]", pfwinfo->cnt_h2c,
14058 			       pfwinfo->cnt_h2c_fail,
14059 			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
14060 			       pfwinfo->cnt_c2h,
14061 			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
14062 			       le16_to_cpu(prptctrl->rpt_info.len_c2h));
14063 
14064 		p += scnprintf(p, end - p,
14065 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
14066 			       pfwinfo->event[BTF_EVNT_RPT],
14067 			       le16_to_cpu(prptctrl->rpt_info.cnt),
14068 			       le32_to_cpu(prptctrl->rpt_info.en));
14069 
14070 		if (dm->error.map.wl_fw_hang)
14071 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
14072 		p += scnprintf(p, end - p, "\n");
14073 
14074 		p += scnprintf(p, end - p,
14075 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
14076 			       "[mailbox]",
14077 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
14078 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
14079 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
14080 
14081 		p += scnprintf(p, end - p,
14082 			       "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)\n",
14083 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
14084 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
14085 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
14086 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
14087 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
14088 
14089 		p += scnprintf(p, end - p,
14090 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
14091 			       "[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
14092 			       wl->wcnt[BTC_WCNT_RFK_GO],
14093 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
14094 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT],
14095 			       wl->rfk_info.proc_time);
14096 
14097 		p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
14098 			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
14099 
14100 		p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]\n",
14101 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
14102 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
14103 	} else {
14104 		p += scnprintf(p, end - p,
14105 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)\n",
14106 			       "[summary]",
14107 			       pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
14108 			       pfwinfo->cnt_c2h,
14109 			       wl->status.map.lps, wl->status.map.rf_off);
14110 	}
14111 
14112 	for (i = 0; i < BTC_NCNT_NUM; i++)
14113 		cnt_sum += dm->cnt_notify[i];
14114 
14115 	p += scnprintf(p, end - p,
14116 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
14117 		       "[notify_cnt]",
14118 		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
14119 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
14120 
14121 	p += scnprintf(p, end - p,
14122 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
14123 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
14124 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
14125 		       cnt[BTC_NCNT_WL_STA]);
14126 
14127 	p += scnprintf(p, end - p,
14128 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
14129 		       "[notify_cnt]",
14130 		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
14131 		       cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
14132 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
14133 
14134 	p += scnprintf(p, end - p,
14135 		       "timer=%d, customerize=%d, hub_msg=%d, chg_fw=%d, send_cc=%d",
14136 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CUSTOMERIZE],
14137 		       rtwdev->btc.hubmsg_cnt, cnt[BTC_NCNT_RESUME_DL_FW],
14138 		       cnt[BTC_NCNT_COUNTRYCODE]);
14139 
14140 	return p - buf;
14141 }
14142 
14143 static int _show_summary_v11(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
14144 {
14145 	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
14146 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
14147 	struct rtw89_btc_fbtc_rpt_ctrl_v11 *prptctrl = NULL;
14148 	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
14149 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
14150 	struct rtw89_btc_wl_info *wl = &cx->wl;
14151 	u32 *cnt = rtwdev->btc.dm.cnt_notify;
14152 	char *p = buf, *end = buf + bufsz;
14153 	u32 cnt_sum = 0;
14154 	u8 i;
14155 
14156 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
14157 		return 0;
14158 
14159 	p += scnprintf(p, end - p, "%s",
14160 		       "\n========== [Statistics] ==========\n");
14161 
14162 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
14163 	if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
14164 	    !wl->status.map.rf_off) {
14165 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v11;
14166 
14167 		p += scnprintf(p, end - p,
14168 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, max:fw-%d/drv-%d), ",
14169 			       "[summary]", pfwinfo->cnt_h2c,
14170 			       pfwinfo->cnt_h2c_fail,
14171 			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
14172 			       pfwinfo->cnt_c2h,
14173 			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
14174 			       le16_to_cpu(prptctrl->rpt_info.len_c2h),
14175 			       (prptctrl->rpt_len_max_h << 8) + prptctrl->rpt_len_max_l,
14176 			       rtwdev->btc.ver->info_buf);
14177 
14178 		p += scnprintf(p, end - p,
14179 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
14180 			       pfwinfo->event[BTF_EVNT_RPT],
14181 			       le16_to_cpu(prptctrl->rpt_info.cnt),
14182 			       le32_to_cpu(prptctrl->rpt_info.en));
14183 
14184 		if (dm->error.map.wl_fw_hang)
14185 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
14186 		p += scnprintf(p, end - p, "\n");
14187 
14188 		p += scnprintf(p, end - p,
14189 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
14190 			       "[mailbox]",
14191 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
14192 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
14193 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
14194 
14195 		p += scnprintf(p, end - p,
14196 			       "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)\n",
14197 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
14198 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
14199 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
14200 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
14201 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
14202 
14203 		p += scnprintf(p, end - p,
14204 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
14205 			       "[RFK/LPS]", wl->wcnt[BTC_WCNT_RFK_REQ],
14206 			       wl->wcnt[BTC_WCNT_RFK_GO],
14207 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
14208 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT],
14209 			       wl->rfk_info.proc_time);
14210 
14211 		p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]\n",
14212 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
14213 			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
14214 	} else {
14215 		p += scnprintf(p, end - p,
14216 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)\n",
14217 			       "[summary]",
14218 			       pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
14219 			       pfwinfo->cnt_c2h,
14220 			       wl->status.map.lps, wl->status.map.rf_off);
14221 	}
14222 
14223 	for (i = 0; i < BTC_NCNT_NUM; i++)
14224 		cnt_sum += dm->cnt_notify[i];
14225 
14226 	p += scnprintf(p, end - p,
14227 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
14228 		       "[notify_cnt]",
14229 		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
14230 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
14231 
14232 	p += scnprintf(p, end - p,
14233 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
14234 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
14235 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
14236 		       cnt[BTC_NCNT_WL_STA]);
14237 
14238 	p += scnprintf(p, end - p,
14239 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
14240 		       "[notify_cnt]",
14241 		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
14242 		       cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
14243 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
14244 
14245 	p += scnprintf(p, end - p,
14246 		       "timer=%d, customerize=%d, hub_msg=%d, chg_fw=%d, send_cc=%d",
14247 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CUSTOMERIZE],
14248 		       rtwdev->btc.hubmsg_cnt, cnt[BTC_NCNT_RESUME_DL_FW],
14249 		       cnt[BTC_NCNT_COUNTRYCODE]);
14250 
14251 	return p - buf;
14252 }
14253 
14254 static int _show_summary_v205(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
14255 {
14256 	struct rtw89_btc *btc = &rtwdev->btc;
14257 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
14258 	struct rtw89_btc_fbtc_rpt_ctrl_v205 *prptctrl;
14259 	struct rtw89_btc_rpt_cmn_info *pcinfo;
14260 	struct rtw89_btc_cx *cx = &btc->cx;
14261 	struct rtw89_btc_dm *dm = &btc->dm;
14262 	struct rtw89_btc_wl_info *wl = &cx->wl;
14263 	struct rtw89_btc_bt_info *bt = &cx->bt0;
14264 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
14265 	char *p = buf, *end = buf + bufsz;
14266 	u8 i;
14267 
14268 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
14269 		return 0;
14270 
14271 	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
14272 
14273 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
14274 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
14275 		prptctrl = &pfwinfo->rpt_ctrl.finfo.v205;
14276 
14277 		p += scnprintf(p, end - p,
14278 			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
14279 			       "[summary]", pfwinfo->cnt_h2c,
14280 			       pfwinfo->cnt_h2c_fail,
14281 			       le32_to_cpu(prptctrl->rpt_info.cnt_h2c),
14282 			       pfwinfo->cnt_c2h,
14283 			       le32_to_cpu(prptctrl->rpt_info.cnt_c2h));
14284 
14285 		p += scnprintf(p, end - p,
14286 			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
14287 			       pfwinfo->event[BTF_EVNT_RPT],
14288 			       le32_to_cpu(prptctrl->rpt_info.cnt),
14289 			       le32_to_cpu(prptctrl->rpt_info.en),
14290 			       dm->error.val);
14291 
14292 		if (dm->error.map.wl_fw_hang)
14293 			p += scnprintf(p, end - p, " (WL FW Hang!!)");
14294 		p += scnprintf(p, end - p, "\n");
14295 		p += scnprintf(p, end - p,
14296 			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
14297 			       "[mailbox]",
14298 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
14299 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
14300 			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
14301 
14302 		p += scnprintf(p, end - p,
14303 			       "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
14304 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
14305 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
14306 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
14307 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
14308 			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
14309 
14310 		p += scnprintf(p, end - p,
14311 			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
14312 			       "[RFK]", wl->wcnt[BTC_WCNT_RFK_REQ],
14313 			       wl->wcnt[BTC_WCNT_RFK_GO],
14314 			       wl->wcnt[BTC_WCNT_RFK_REJECT],
14315 			       wl->wcnt[BTC_WCNT_RFK_TIMEOUT]);
14316 
14317 		p += scnprintf(p, end - p,
14318 			       ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
14319 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]),
14320 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_GO]),
14321 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REJECT]),
14322 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]),
14323 			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_FAIL]));
14324 
14325 		if (le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
14326 			bt->rfk_info.map.timeout = 1;
14327 		else
14328 			bt->rfk_info.map.timeout = 0;
14329 
14330 		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
14331 	} else {
14332 		p += scnprintf(p, end - p,
14333 			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
14334 			       "[summary]", pfwinfo->cnt_h2c,
14335 			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
14336 			       pfwinfo->event[BTF_EVNT_RPT],
14337 			       btc->fwinfo.rpt_en_map);
14338 		p += scnprintf(p, end - p, " (WL FW report invalid!!)\n");
14339 	}
14340 
14341 	for (i = 0; i < BTC_NCNT_NUM; i++)
14342 		cnt_sum += dm->cnt_notify[i];
14343 
14344 	p += scnprintf(p, end - p,
14345 		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
14346 		       "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
14347 		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
14348 
14349 	p += scnprintf(p, end - p,
14350 		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
14351 		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
14352 		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
14353 		       cnt[BTC_NCNT_WL_STA]);
14354 
14355 	p += scnprintf(p, end - p,
14356 		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
14357 		       "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
14358 		       cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
14359 		       cnt[BTC_NCNT_SPECIAL_PACKET]);
14360 
14361 	p += scnprintf(p, end - p,
14362 		       "timer=%d, control=%d, customerize=%d\n",
14363 		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
14364 		       cnt[BTC_NCNT_CUSTOMERIZE]);
14365 
14366 	return p - buf;
14367 }
14368 
14369 ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
14370 {
14371 	struct rtw89_btc *btc = &rtwdev->btc;
14372 	struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver;
14373 	const struct rtw89_btc_ver *ver = btc->ver;
14374 	struct rtw89_btc_dm *dm = &btc->dm;
14375 	char *p = buf, *end = buf + bufsz;
14376 
14377 	dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++;
14378 
14379 	p += scnprintf(p, end - p,
14380 		       "\n\n\n** Page:%3d/RunCNT:%3d **",
14381 		       dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO],
14382 		       dm->cnt_dm[BTC_DCNT_RUN]);
14383 	p += scnprintf(p, end - p,
14384 		       "\n========== [BTC FEATURE SUB VER] ==========");
14385 	p += scnprintf(p, end - p,
14386 		       "\n %-15s : fcxbtcrpt[%d/%d], fcxtdma[%d/%d], fcxslots[%d/%d], fcxcysta[%d/%d]",
14387 		       "[FW/DRV]", fwsubver->fcxbtcrpt, ver->fcxbtcrpt,
14388 		       fwsubver->fcxtdma, ver->fcxtdma, fwsubver->fcxslots,
14389 		       ver->fcxslots, fwsubver->fcxcysta, ver->fcxcysta);
14390 	p += scnprintf(p, end - p,
14391 		       "\n %-15s : fcxstep[%d/%d], fcxnullsta[%d/%d], fcxmreg[%d/%d], fcxgpiodbg[%d/%d]",
14392 		       "[FW/DRV]", fwsubver->fcxstep, ver->fcxstep,
14393 		       fwsubver->fcxnullsta, ver->fcxnullsta, fwsubver->fcxmreg,
14394 		       ver->fcxmreg, fwsubver->fcxgpiodbg, ver->fcxgpiodbg);
14395 	p += scnprintf(p, end - p,
14396 		       "\n %-15s : fcxbtver[%d/%d], fcxbtscan[%d/%d], fcxbtafh[%d/%d], fcxbtdevinfo[%d/%d]",
14397 		       "[FW/DRV]", fwsubver->fcxbtver, ver->fcxbtver,
14398 		       fwsubver->fcxbtscan, ver->fcxbtscan, fwsubver->fcxbtafh,
14399 		       ver->fcxbtafh, fwsubver->fcxbtdevinfo, ver->fcxbtdevinfo);
14400 	p += scnprintf(p, end - p,
14401 		       "\n %-15s : fcxosi[%d/%d], fcxmlo[%d/%d],",
14402 		       "[FW/DRV]", fwsubver->fcxosi, ver->fcxosi,
14403 		       fwsubver->fcxmlo, ver->fcxmlo);
14404 
14405 	p += _show_cx_info(rtwdev, p, end - p);
14406 	p += _show_wl_info(rtwdev, p, end - p);
14407 	p += _show_bt_info(rtwdev, p, end - p, BTC_BT_1ST);
14408 	p += _show_bt_info(rtwdev, p, end - p, BTC_BT_2ND);
14409 	p += _show_dm_info(rtwdev, p, end - p);
14410 	p += _show_fw_dm_msg(rtwdev, p, end - p);
14411 
14412 	if (ver->fcxmreg == 1)
14413 		p += _show_mreg_v1(rtwdev, p, end - p);
14414 	else if (ver->fcxmreg == 2)
14415 		p += _show_mreg_v2(rtwdev, p, end - p);
14416 	else if (ver->fcxmreg == 7)
14417 		p += _show_mreg_v7(rtwdev, p, end - p);
14418 
14419 	p += _show_gpio_dbg(rtwdev, p, end - p);
14420 
14421 	if (ver->fcxbtcrpt == 1)
14422 		p += _show_summary_v1(rtwdev, p, end - p);
14423 	else if (ver->fcxbtcrpt == 4)
14424 		p += _show_summary_v4(rtwdev, p, end - p);
14425 	else if (ver->fcxbtcrpt == 5)
14426 		p += _show_summary_v5(rtwdev, p, end - p);
14427 	else if (ver->fcxbtcrpt == 105)
14428 		p += _show_summary_v105(rtwdev, p, end - p);
14429 	else if (ver->fcxbtcrpt == 205)
14430 		p += _show_summary_v205(rtwdev, p, end - p);
14431 	else if (ver->fcxbtcrpt == 7)
14432 		p += _show_summary_v7(rtwdev, p, end - p);
14433 	else if (ver->fcxbtcrpt == 8)
14434 		p += _show_summary_v8(rtwdev, p, end - p);
14435 	else if (ver->fcxbtcrpt == 9)
14436 		p += _show_summary_v9(rtwdev, p, end - p);
14437 	else if (ver->fcxbtcrpt == 11)
14438 		p += _show_summary_v11(rtwdev, p, end - p);
14439 
14440 	p += scnprintf(p, end - p, "\n");
14441 
14442 	return p - buf;
14443 }
14444 
14445 void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev)
14446 {
14447 	const struct rtw89_chip_info *chip = rtwdev->chip;
14448 	struct rtw89_btc *btc = &rtwdev->btc;
14449 	const struct rtw89_btc_ver *btc_ver_def;
14450 	const struct rtw89_fw_suit *fw_suit;
14451 	u32 suit_ver_code;
14452 	int i;
14453 
14454 	fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_NORMAL);
14455 	suit_ver_code = RTW89_FW_SUIT_VER_CODE(fw_suit);
14456 
14457 	for (i = 0; i < ARRAY_SIZE(rtw89_btc_ver_defs); i++) {
14458 		btc_ver_def = &rtw89_btc_ver_defs[i];
14459 
14460 		if (chip->chip_id != btc_ver_def->chip_id)
14461 			continue;
14462 
14463 		if (suit_ver_code >= btc_ver_def->fw_ver_code) {
14464 			btc->ver = btc_ver_def;
14465 			goto out;
14466 		}
14467 	}
14468 
14469 	btc->ver = &rtw89_btc_ver_defs[RTW89_DEFAULT_BTC_VER_IDX];
14470 
14471 out:
14472 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] use version def[%d] = 0x%08x\n",
14473 		    (int)(btc->ver - rtw89_btc_ver_defs), btc->ver->fw_ver_code);
14474 }
14475 
14476 void rtw89_btc_ntfy_preserve_bt_time(struct rtw89_dev *rtwdev, u32 ms)
14477 {
14478 	struct rtw89_btc_bt_link_info *bt_linfo = &rtwdev->btc.cx.bt0.link_info;
14479 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
14480 
14481 	if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
14482 		return;
14483 
14484 	if (!a2dp.exist)
14485 		return;
14486 
14487 	fsleep(ms * 1000);
14488 }
14489 EXPORT_SYMBOL(rtw89_btc_ntfy_preserve_bt_time);
14490 
14491 void rtw89_btc_ntfy_conn_rfk(struct rtw89_dev *rtwdev, bool state)
14492 {
14493 	rtwdev->btc.cx.wl.rfk_info.con_rfk = state;
14494 }
14495 EXPORT_SYMBOL(rtw89_btc_ntfy_conn_rfk);
14496