Linux Audio

Check our new training course

Linux BSP development engineering services

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