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

source code of linux/drivers/net/wireless/realtek/rtw89/coex.c