cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

coex.c (164411B)


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