Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /* Copyright(c) 2019-2020  Realtek Corporation
0003  */
0004 
0005 #include "coex.h"
0006 #include "debug.h"
0007 #include "fw.h"
0008 #include "mac.h"
0009 #include "ps.h"
0010 #include "reg.h"
0011 
0012 #define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/
0013 
0014 enum btc_fbtc_tdma_template {
0015     CXTD_OFF = 0x0,
0016     CXTD_OFF_B2,
0017     CXTD_OFF_EXT,
0018     CXTD_FIX,
0019     CXTD_PFIX,
0020     CXTD_AUTO,
0021     CXTD_PAUTO,
0022     CXTD_AUTO2,
0023     CXTD_PAUTO2,
0024     CXTD_MAX,
0025 };
0026 
0027 enum btc_fbtc_tdma_type {
0028     CXTDMA_OFF = 0x0,
0029     CXTDMA_FIX = 0x1,
0030     CXTDMA_AUTO = 0x2,
0031     CXTDMA_AUTO2 = 0x3,
0032     CXTDMA_MAX
0033 };
0034 
0035 enum btc_fbtc_tdma_rx_flow_ctrl {
0036     CXFLC_OFF = 0x0,
0037     CXFLC_NULLP = 0x1,
0038     CXFLC_QOSNULL = 0x2,
0039     CXFLC_CTS = 0x3,
0040     CXFLC_MAX
0041 };
0042 
0043 enum btc_fbtc_tdma_wlan_tx_pause {
0044     CXTPS_OFF = 0x0,  /* no wl tx pause*/
0045     CXTPS_ON = 0x1,
0046     CXTPS_MAX
0047 };
0048 
0049 enum btc_mlme_state {
0050     MLME_NO_LINK,
0051     MLME_LINKING,
0052     MLME_LINKED,
0053 };
0054 
0055 #define FCXONESLOT_VER 1
0056 struct btc_fbtc_1slot {
0057     u8 fver;
0058     u8 sid; /* slot id */
0059     struct rtw89_btc_fbtc_slot slot;
0060 } __packed;
0061 
0062 static const struct rtw89_btc_fbtc_tdma t_def[] = {
0063     [CXTD_OFF]  = { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
0064     [CXTD_OFF_B2]   = { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 1, 0, 0},
0065     [CXTD_OFF_EXT]  = { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 3, 0, 0},
0066     [CXTD_FIX]  = { CXTDMA_FIX,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
0067     [CXTD_PFIX] = { CXTDMA_FIX,  CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
0068     [CXTD_AUTO] = { CXTDMA_AUTO,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
0069     [CXTD_PAUTO]    = { CXTDMA_AUTO, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
0070     [CXTD_AUTO2]    = {CXTDMA_AUTO2,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
0071     [CXTD_PAUTO2]   = {CXTDMA_AUTO2, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0}
0072 };
0073 
0074 #define __DEF_FBTC_SLOT(__dur, __cxtbl, __cxtype) \
0075     { .dur = cpu_to_le16(__dur), .cxtbl = cpu_to_le32(__cxtbl), \
0076       .cxtype = cpu_to_le16(__cxtype),}
0077 
0078 static const struct rtw89_btc_fbtc_slot s_def[] = {
0079     [CXST_OFF]  = __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX),
0080     [CXST_B2W]  = __DEF_FBTC_SLOT(5,   0x5a5a5a5a, SLOT_ISO),
0081     [CXST_W1]   = __DEF_FBTC_SLOT(70,  0x5a5a5a5a, SLOT_ISO),
0082     [CXST_W2]   = __DEF_FBTC_SLOT(70,  0x5a5a5aaa, SLOT_ISO),
0083     [CXST_W2B]  = __DEF_FBTC_SLOT(15,  0x5a5a5a5a, SLOT_ISO),
0084     [CXST_B1]   = __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX),
0085     [CXST_B2]   = __DEF_FBTC_SLOT(7,   0x6a5a5a5a, SLOT_MIX),
0086     [CXST_B3]   = __DEF_FBTC_SLOT(5,   0x55555555, SLOT_MIX),
0087     [CXST_B4]   = __DEF_FBTC_SLOT(50,  0x55555555, SLOT_MIX),
0088     [CXST_LK]   = __DEF_FBTC_SLOT(20,  0x5a5a5a5a, SLOT_ISO),
0089     [CXST_BLK]  = __DEF_FBTC_SLOT(250, 0x55555555, SLOT_MIX),
0090     [CXST_E2G]  = __DEF_FBTC_SLOT(20,  0x6a5a5a5a, SLOT_MIX),
0091     [CXST_E5G]  = __DEF_FBTC_SLOT(20,  0xffffffff, SLOT_MIX),
0092     [CXST_EBT]  = __DEF_FBTC_SLOT(20,  0x55555555, SLOT_MIX),
0093     [CXST_ENULL]    = __DEF_FBTC_SLOT(7,   0xaaaaaaaa, SLOT_ISO),
0094     [CXST_WLK]  = __DEF_FBTC_SLOT(250, 0x6a5a6a5a, SLOT_MIX),
0095     [CXST_W1FDD]    = __DEF_FBTC_SLOT(35,  0xfafafafa, SLOT_ISO),
0096     [CXST_B1FDD]    = __DEF_FBTC_SLOT(100, 0xffffffff, SLOT_MIX),
0097 };
0098 
0099 static const u32 cxtbl[] = {
0100     0xffffffff, /* 0 */
0101     0xaaaaaaaa, /* 1 */
0102     0x55555555, /* 2 */
0103     0x66555555, /* 3 */
0104     0x66556655, /* 4 */
0105     0x5a5a5a5a, /* 5 */
0106     0x5a5a5aaa, /* 6 */
0107     0xaa5a5a5a, /* 7 */
0108     0x6a5a5a5a, /* 8 */
0109     0x6a5a5aaa, /* 9 */
0110     0x6a5a6a5a, /* 10 */
0111     0x6a5a6aaa, /* 11 */
0112     0x6afa5afa, /* 12 */
0113     0xaaaa5aaa, /* 13 */
0114     0xaaffffaa, /* 14 */
0115     0xaa5555aa, /* 15 */
0116     0xfafafafa, /* 16 */
0117     0xffffddff, /* 17 */
0118     0xdaffdaff, /* 18 */
0119     0xfafadafa  /* 19 */
0120 };
0121 
0122 struct rtw89_btc_btf_tlv {
0123     u8 type;
0124     u8 len;
0125     u8 val[1];
0126 } __packed;
0127 
0128 enum btc_btf_set_report_en {
0129     RPT_EN_TDMA = BIT(0),
0130     RPT_EN_CYCLE = BIT(1),
0131     RPT_EN_MREG = BIT(2),
0132     RPT_EN_BT_VER_INFO = BIT(3),
0133     RPT_EN_BT_SCAN_INFO = BIT(4),
0134     RPT_EN_BT_AFH_MAP = BIT(5),
0135     RPT_EN_BT_DEVICE_INFO = BIT(6),
0136     RPT_EN_WL_ALL = GENMASK(2, 0),
0137     RPT_EN_BT_ALL = GENMASK(6, 3),
0138     RPT_EN_ALL = GENMASK(6, 0),
0139 };
0140 
0141 #define BTF_SET_REPORT_VER 1
0142 struct rtw89_btc_btf_set_report {
0143     u8 fver;
0144     __le32 enable;
0145     __le32 para;
0146 } __packed;
0147 
0148 #define BTF_SET_SLOT_TABLE_VER 1
0149 struct rtw89_btc_btf_set_slot_table {
0150     u8 fver;
0151     u8 tbl_num;
0152     u8 buf[];
0153 } __packed;
0154 
0155 #define BTF_SET_MON_REG_VER 1
0156 struct rtw89_btc_btf_set_mon_reg {
0157     u8 fver;
0158     u8 reg_num;
0159     u8 buf[];
0160 } __packed;
0161 
0162 enum btc_btf_set_cx_policy {
0163     CXPOLICY_TDMA = 0x0,
0164     CXPOLICY_SLOT = 0x1,
0165     CXPOLICY_TYPE = 0x2,
0166     CXPOLICY_MAX,
0167 };
0168 
0169 enum btc_b2w_scoreboard {
0170     BTC_BSCB_ACT = BIT(0),
0171     BTC_BSCB_ON = BIT(1),
0172     BTC_BSCB_WHQL = BIT(2),
0173     BTC_BSCB_BT_S1 = BIT(3),
0174     BTC_BSCB_A2DP_ACT = BIT(4),
0175     BTC_BSCB_RFK_RUN = BIT(5),
0176     BTC_BSCB_RFK_REQ = BIT(6),
0177     BTC_BSCB_LPS = BIT(7),
0178     BTC_BSCB_WLRFK = BIT(11),
0179     BTC_BSCB_BT_HILNA = BIT(13),
0180     BTC_BSCB_BT_CONNECT = BIT(16),
0181     BTC_BSCB_PATCH_CODE = BIT(30),
0182     BTC_BSCB_ALL = GENMASK(30, 0),
0183 };
0184 
0185 enum btc_phymap {
0186     BTC_PHY_0 = BIT(0),
0187     BTC_PHY_1 = BIT(1),
0188     BTC_PHY_ALL = BIT(0) | BIT(1),
0189 };
0190 
0191 enum btc_cx_state_map {
0192     BTC_WIDLE = 0,
0193     BTC_WBUSY_BNOSCAN,
0194     BTC_WBUSY_BSCAN,
0195     BTC_WSCAN_BNOSCAN,
0196     BTC_WSCAN_BSCAN,
0197     BTC_WLINKING
0198 };
0199 
0200 enum btc_ant_phase {
0201     BTC_ANT_WPOWERON = 0,
0202     BTC_ANT_WINIT,
0203     BTC_ANT_WONLY,
0204     BTC_ANT_WOFF,
0205     BTC_ANT_W2G,
0206     BTC_ANT_W5G,
0207     BTC_ANT_W25G,
0208     BTC_ANT_FREERUN,
0209     BTC_ANT_WRFK,
0210     BTC_ANT_BRFK,
0211     BTC_ANT_MAX
0212 };
0213 
0214 enum btc_plt {
0215     BTC_PLT_NONE = 0,
0216     BTC_PLT_LTE_RX = BIT(0),
0217     BTC_PLT_GNT_BT_TX = BIT(1),
0218     BTC_PLT_GNT_BT_RX = BIT(2),
0219     BTC_PLT_GNT_WL = BIT(3),
0220     BTC_PLT_BT = BIT(1) | BIT(2),
0221     BTC_PLT_ALL = 0xf
0222 };
0223 
0224 enum btc_cx_poicy_main_type {
0225     BTC_CXP_OFF = 0,
0226     BTC_CXP_OFFB,
0227     BTC_CXP_OFFE,
0228     BTC_CXP_FIX,
0229     BTC_CXP_PFIX,
0230     BTC_CXP_AUTO,
0231     BTC_CXP_PAUTO,
0232     BTC_CXP_AUTO2,
0233     BTC_CXP_PAUTO2,
0234     BTC_CXP_MANUAL,
0235     BTC_CXP_USERDEF0,
0236     BTC_CXP_MAIN_MAX
0237 };
0238 
0239 enum btc_cx_poicy_type {
0240     /* TDMA off + pri: BT > WL */
0241     BTC_CXP_OFF_BT = (BTC_CXP_OFF << 8) | 0,
0242 
0243     /* TDMA off + pri: WL > BT */
0244     BTC_CXP_OFF_WL = (BTC_CXP_OFF << 8) | 1,
0245 
0246     /* TDMA off + pri: BT = WL */
0247     BTC_CXP_OFF_EQ0 = (BTC_CXP_OFF << 8) | 2,
0248 
0249     /* TDMA off + pri: BT = WL > BT_Lo */
0250     BTC_CXP_OFF_EQ1 = (BTC_CXP_OFF << 8) | 3,
0251 
0252     /* TDMA off + pri: WL = BT, BT_Rx > WL_Lo_Tx */
0253     BTC_CXP_OFF_EQ2 = (BTC_CXP_OFF << 8) | 4,
0254 
0255     /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
0256     BTC_CXP_OFF_EQ3 = (BTC_CXP_OFF << 8) | 5,
0257 
0258     /* TDMA off + pri: BT_Hi > WL > BT_Lo */
0259     BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 6,
0260 
0261     /* TDMA off + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */
0262     BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 7,
0263 
0264     /* TDMA off+Bcn-Protect + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo*/
0265     BTC_CXP_OFFB_BWB0 = (BTC_CXP_OFFB << 8) | 0,
0266 
0267     /* TDMA off + Ext-Ctrl + pri: default */
0268     BTC_CXP_OFFE_DEF = (BTC_CXP_OFFE << 8) | 0,
0269 
0270     /* TDMA off + Ext-Ctrl + pri: E2G-slot block all BT */
0271     BTC_CXP_OFFE_DEF2 = (BTC_CXP_OFFE << 8) | 1,
0272 
0273     /* TDMA Fix slot-0: W1:B1 = 30:30 */
0274     BTC_CXP_FIX_TD3030 = (BTC_CXP_FIX << 8) | 0,
0275 
0276     /* TDMA Fix slot-1: W1:B1 = 50:50 */
0277     BTC_CXP_FIX_TD5050 = (BTC_CXP_FIX << 8) | 1,
0278 
0279     /* TDMA Fix slot-2: W1:B1 = 20:30 */
0280     BTC_CXP_FIX_TD2030 = (BTC_CXP_FIX << 8) | 2,
0281 
0282     /* TDMA Fix slot-3: W1:B1 = 40:10 */
0283     BTC_CXP_FIX_TD4010 = (BTC_CXP_FIX << 8) | 3,
0284 
0285     /* TDMA Fix slot-4: W1:B1 = 70:10 */
0286     BTC_CXP_FIX_TD7010 = (BTC_CXP_FIX << 8) | 4,
0287 
0288     /* TDMA Fix slot-5: W1:B1 = 20:60 */
0289     BTC_CXP_FIX_TD2060 = (BTC_CXP_FIX << 8) | 5,
0290 
0291     /* TDMA Fix slot-6: W1:B1 = 30:60 */
0292     BTC_CXP_FIX_TD3060 = (BTC_CXP_FIX << 8) | 6,
0293 
0294     /* TDMA Fix slot-7: W1:B1 = 20:80 */
0295     BTC_CXP_FIX_TD2080 = (BTC_CXP_FIX << 8) | 7,
0296 
0297     /* TDMA Fix slot-8: W1:B1 = user-define */
0298     BTC_CXP_FIX_TDW1B1 = (BTC_CXP_FIX << 8) | 8,
0299 
0300     /* TDMA Fix slot-9: W1:B1 = 40:20 */
0301     BTC_CXP_FIX_TD4020 = (BTC_CXP_FIX << 8) | 9,
0302 
0303     /* PS-TDMA Fix slot-0: W1:B1 = 30:30 */
0304     BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0,
0305 
0306     /* PS-TDMA Fix slot-1: W1:B1 = 50:50 */
0307     BTC_CXP_PFIX_TD5050 = (BTC_CXP_PFIX << 8) | 1,
0308 
0309     /* PS-TDMA Fix slot-2: W1:B1 = 20:30 */
0310     BTC_CXP_PFIX_TD2030 = (BTC_CXP_PFIX << 8) | 2,
0311 
0312     /* PS-TDMA Fix slot-3: W1:B1 = 20:60 */
0313     BTC_CXP_PFIX_TD2060 = (BTC_CXP_PFIX << 8) | 3,
0314 
0315     /* PS-TDMA Fix slot-4: W1:B1 = 30:70 */
0316     BTC_CXP_PFIX_TD3070 = (BTC_CXP_PFIX << 8) | 4,
0317 
0318     /* PS-TDMA Fix slot-5: W1:B1 = 20:80 */
0319     BTC_CXP_PFIX_TD2080 = (BTC_CXP_PFIX << 8) | 5,
0320 
0321     /* PS-TDMA Fix slot-6: W1:B1 = user-define */
0322     BTC_CXP_PFIX_TDW1B1 = (BTC_CXP_PFIX << 8) | 6,
0323 
0324     /* TDMA Auto slot-0: W1:B1 = 50:200 */
0325     BTC_CXP_AUTO_TD50200 = (BTC_CXP_AUTO << 8) | 0,
0326 
0327     /* TDMA Auto slot-1: W1:B1 = 60:200 */
0328     BTC_CXP_AUTO_TD60200 = (BTC_CXP_AUTO << 8) | 1,
0329 
0330     /* TDMA Auto slot-2: W1:B1 = 20:200 */
0331     BTC_CXP_AUTO_TD20200 = (BTC_CXP_AUTO << 8) | 2,
0332 
0333     /* TDMA Auto slot-3: W1:B1 = user-define */
0334     BTC_CXP_AUTO_TDW1B1 = (BTC_CXP_AUTO << 8) | 3,
0335 
0336     /* PS-TDMA Auto slot-0: W1:B1 = 50:200 */
0337     BTC_CXP_PAUTO_TD50200 = (BTC_CXP_PAUTO << 8) | 0,
0338 
0339     /* PS-TDMA Auto slot-1: W1:B1 = 60:200 */
0340     BTC_CXP_PAUTO_TD60200 = (BTC_CXP_PAUTO << 8) | 1,
0341 
0342     /* PS-TDMA Auto slot-2: W1:B1 = 20:200 */
0343     BTC_CXP_PAUTO_TD20200 = (BTC_CXP_PAUTO << 8) | 2,
0344 
0345     /* PS-TDMA Auto slot-3: W1:B1 = user-define */
0346     BTC_CXP_PAUTO_TDW1B1 = (BTC_CXP_PAUTO << 8) | 3,
0347 
0348     /* TDMA Auto slot2-0: W1:B4 = 30:50 */
0349     BTC_CXP_AUTO2_TD3050 = (BTC_CXP_AUTO2 << 8) | 0,
0350 
0351     /* TDMA Auto slot2-1: W1:B4 = 30:70 */
0352     BTC_CXP_AUTO2_TD3070 = (BTC_CXP_AUTO2 << 8) | 1,
0353 
0354     /* TDMA Auto slot2-2: W1:B4 = 50:50 */
0355     BTC_CXP_AUTO2_TD5050 = (BTC_CXP_AUTO2 << 8) | 2,
0356 
0357     /* TDMA Auto slot2-3: W1:B4 = 60:60 */
0358     BTC_CXP_AUTO2_TD6060 = (BTC_CXP_AUTO2 << 8) | 3,
0359 
0360     /* TDMA Auto slot2-4: W1:B4 = 20:80 */
0361     BTC_CXP_AUTO2_TD2080 = (BTC_CXP_AUTO2 << 8) | 4,
0362 
0363     /* TDMA Auto slot2-5: W1:B4 = user-define */
0364     BTC_CXP_AUTO2_TDW1B4 = (BTC_CXP_AUTO2 << 8) | 5,
0365 
0366     /* PS-TDMA Auto slot2-0: W1:B4 = 30:50 */
0367     BTC_CXP_PAUTO2_TD3050 = (BTC_CXP_PAUTO2 << 8) | 0,
0368 
0369     /* PS-TDMA Auto slot2-1: W1:B4 = 30:70 */
0370     BTC_CXP_PAUTO2_TD3070 = (BTC_CXP_PAUTO2 << 8) | 1,
0371 
0372     /* PS-TDMA Auto slot2-2: W1:B4 = 50:50 */
0373     BTC_CXP_PAUTO2_TD5050 = (BTC_CXP_PAUTO2 << 8) | 2,
0374 
0375     /* PS-TDMA Auto slot2-3: W1:B4 = 60:60 */
0376     BTC_CXP_PAUTO2_TD6060 = (BTC_CXP_PAUTO2 << 8) | 3,
0377 
0378     /* PS-TDMA Auto slot2-4: W1:B4 = 20:80 */
0379     BTC_CXP_PAUTO2_TD2080 = (BTC_CXP_PAUTO2 << 8) | 4,
0380 
0381     /* PS-TDMA Auto slot2-5: W1:B4 = user-define */
0382     BTC_CXP_PAUTO2_TDW1B4 = (BTC_CXP_PAUTO2 << 8) | 5,
0383 
0384     BTC_CXP_MAX = 0xffff
0385 };
0386 
0387 enum btc_wl_rfk_result {
0388     BTC_WRFK_REJECT = 0,
0389     BTC_WRFK_ALLOW = 1,
0390 };
0391 
0392 enum btc_coex_info_map_en {
0393     BTC_COEX_INFO_CX = BIT(0),
0394     BTC_COEX_INFO_WL = BIT(1),
0395     BTC_COEX_INFO_BT = BIT(2),
0396     BTC_COEX_INFO_DM = BIT(3),
0397     BTC_COEX_INFO_MREG = BIT(4),
0398     BTC_COEX_INFO_SUMMARY = BIT(5),
0399     BTC_COEX_INFO_ALL = GENMASK(7, 0),
0400 };
0401 
0402 #define BTC_CXP_MASK GENMASK(15, 8)
0403 
0404 enum btc_w2b_scoreboard {
0405     BTC_WSCB_ACTIVE = BIT(0),
0406     BTC_WSCB_ON = BIT(1),
0407     BTC_WSCB_SCAN = BIT(2),
0408     BTC_WSCB_UNDERTEST = BIT(3),
0409     BTC_WSCB_RXGAIN = BIT(4),
0410     BTC_WSCB_WLBUSY = BIT(7),
0411     BTC_WSCB_EXTFEM = BIT(8),
0412     BTC_WSCB_TDMA = BIT(9),
0413     BTC_WSCB_FIX2M = BIT(10),
0414     BTC_WSCB_WLRFK = BIT(11),
0415     BTC_WSCB_BTRFK_GNT = BIT(12), /* not used, use mailbox to inform BT */
0416     BTC_WSCB_BT_HILNA = BIT(13),
0417     BTC_WSCB_BTLOG = BIT(14),
0418     BTC_WSCB_ALL = GENMASK(23, 0),
0419 };
0420 
0421 enum btc_wl_link_mode {
0422     BTC_WLINK_NOLINK = 0x0,
0423     BTC_WLINK_2G_STA,
0424     BTC_WLINK_2G_AP,
0425     BTC_WLINK_2G_GO,
0426     BTC_WLINK_2G_GC,
0427     BTC_WLINK_2G_SCC,
0428     BTC_WLINK_2G_MCC,
0429     BTC_WLINK_25G_MCC,
0430     BTC_WLINK_25G_DBCC,
0431     BTC_WLINK_5G,
0432     BTC_WLINK_2G_NAN,
0433     BTC_WLINK_OTHER,
0434     BTC_WLINK_MAX
0435 };
0436 
0437 enum btc_bt_hid_type {
0438     BTC_HID_218 = BIT(0),
0439     BTC_HID_418 = BIT(1),
0440     BTC_HID_BLE = BIT(2),
0441     BTC_HID_RCU = BIT(3),
0442     BTC_HID_RCU_VOICE = BIT(4),
0443     BTC_HID_OTHER_LEGACY = BIT(5)
0444 };
0445 
0446 enum btc_reset_module {
0447     BTC_RESET_CX = BIT(0),
0448     BTC_RESET_DM = BIT(1),
0449     BTC_RESET_CTRL = BIT(2),
0450     BTC_RESET_CXDM = BIT(0) | BIT(1),
0451     BTC_RESET_BTINFO = BIT(3),
0452     BTC_RESET_MDINFO = BIT(4),
0453     BTC_RESET_ALL =  GENMASK(7, 0),
0454 };
0455 
0456 enum btc_gnt_state {
0457     BTC_GNT_HW  = 0,
0458     BTC_GNT_SW_LO,
0459     BTC_GNT_SW_HI,
0460     BTC_GNT_MAX
0461 };
0462 
0463 enum btc_wl_max_tx_time {
0464     BTC_MAX_TX_TIME_L1 = 500,
0465     BTC_MAX_TX_TIME_L2 = 1000,
0466     BTC_MAX_TX_TIME_L3 = 2000,
0467     BTC_MAX_TX_TIME_DEF = 5280
0468 };
0469 
0470 enum btc_wl_max_tx_retry {
0471     BTC_MAX_TX_RETRY_L1 = 7,
0472     BTC_MAX_TX_RETRY_L2 = 15,
0473     BTC_MAX_TX_RETRY_DEF = 31,
0474 };
0475 
0476 enum btc_reason_and_action {
0477     BTC_RSN_NONE,
0478     BTC_RSN_NTFY_INIT,
0479     BTC_RSN_NTFY_SWBAND,
0480     BTC_RSN_NTFY_WL_STA,
0481     BTC_RSN_NTFY_RADIO_STATE,
0482     BTC_RSN_UPDATE_BT_SCBD,
0483     BTC_RSN_NTFY_WL_RFK,
0484     BTC_RSN_UPDATE_BT_INFO,
0485     BTC_RSN_NTFY_SCAN_START,
0486     BTC_RSN_NTFY_SCAN_FINISH,
0487     BTC_RSN_NTFY_SPECIFIC_PACKET,
0488     BTC_RSN_NTFY_POWEROFF,
0489     BTC_RSN_NTFY_ROLE_INFO,
0490     BTC_RSN_CMD_SET_COEX,
0491     BTC_RSN_ACT1_WORK,
0492     BTC_RSN_BT_DEVINFO_WORK,
0493     BTC_RSN_RFK_CHK_WORK,
0494     BTC_RSN_NUM,
0495     BTC_ACT_NONE = 100,
0496     BTC_ACT_WL_ONLY,
0497     BTC_ACT_WL_5G,
0498     BTC_ACT_WL_OTHER,
0499     BTC_ACT_WL_IDLE,
0500     BTC_ACT_WL_NC,
0501     BTC_ACT_WL_RFK,
0502     BTC_ACT_WL_INIT,
0503     BTC_ACT_WL_OFF,
0504     BTC_ACT_FREERUN,
0505     BTC_ACT_BT_WHQL,
0506     BTC_ACT_BT_RFK,
0507     BTC_ACT_BT_OFF,
0508     BTC_ACT_BT_IDLE,
0509     BTC_ACT_BT_HFP,
0510     BTC_ACT_BT_HID,
0511     BTC_ACT_BT_A2DP,
0512     BTC_ACT_BT_A2DPSINK,
0513     BTC_ACT_BT_PAN,
0514     BTC_ACT_BT_A2DP_HID,
0515     BTC_ACT_BT_A2DP_PAN,
0516     BTC_ACT_BT_PAN_HID,
0517     BTC_ACT_BT_A2DP_PAN_HID,
0518     BTC_ACT_WL_25G_MCC,
0519     BTC_ACT_WL_2G_MCC,
0520     BTC_ACT_WL_2G_SCC,
0521     BTC_ACT_WL_2G_AP,
0522     BTC_ACT_WL_2G_GO,
0523     BTC_ACT_WL_2G_GC,
0524     BTC_ACT_WL_2G_NAN,
0525     BTC_ACT_LAST,
0526     BTC_ACT_NUM = BTC_ACT_LAST - BTC_ACT_NONE,
0527     BTC_ACT_EXT_BIT = BIT(14),
0528     BTC_POLICY_EXT_BIT = BIT(15),
0529 };
0530 
0531 #define BTC_FREERUN_ANTISO_MIN 30
0532 #define BTC_TDMA_BTHID_MAX 2
0533 #define BTC_BLINK_NOCONNECT 0
0534 
0535 static void _run_coex(struct rtw89_dev *rtwdev,
0536               enum btc_reason_and_action reason);
0537 static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state);
0538 static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update);
0539 
0540 static void _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
0541              void *param, u16 len)
0542 {
0543     struct rtw89_btc *btc = &rtwdev->btc;
0544     struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
0545     struct rtw89_btc_cx *cx = &btc->cx;
0546     struct rtw89_btc_wl_info *wl = &cx->wl;
0547     int ret;
0548 
0549     if (!wl->status.map.init_ok) {
0550         rtw89_debug(rtwdev, RTW89_DBG_BTC,
0551                 "[BTC], %s(): return by btc not init!!\n", __func__);
0552         pfwinfo->cnt_h2c_fail++;
0553         return;
0554     } else if ((wl->status.map.rf_off_pre == 1 && wl->status.map.rf_off == 1) ||
0555            (wl->status.map.lps_pre == 1 && wl->status.map.lps == 1)) {
0556         rtw89_debug(rtwdev, RTW89_DBG_BTC,
0557                 "[BTC], %s(): return by wl off!!\n", __func__);
0558         pfwinfo->cnt_h2c_fail++;
0559         return;
0560     }
0561 
0562     pfwinfo->cnt_h2c++;
0563 
0564     ret = rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, param, len,
0565                     false, true);
0566     if (ret != 0)
0567         pfwinfo->cnt_h2c_fail++;
0568 }
0569 
0570 static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
0571 {
0572     struct rtw89_btc *btc = &rtwdev->btc;
0573     struct rtw89_btc_cx *cx = &btc->cx;
0574     struct rtw89_btc_wl_info *wl = &btc->cx.wl;
0575     struct rtw89_btc_bt_info *bt = &btc->cx.bt;
0576     struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
0577     struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
0578     u8 i;
0579 
0580     rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
0581 
0582     if (type & BTC_RESET_CX)
0583         memset(cx, 0, sizeof(*cx));
0584     else if (type & BTC_RESET_BTINFO) /* only for BT enable */
0585         memset(bt, 0, sizeof(*bt));
0586 
0587     if (type & BTC_RESET_CTRL) {
0588         memset(&btc->ctrl, 0, sizeof(btc->ctrl));
0589         btc->ctrl.trace_step = FCXDEF_STEP;
0590     }
0591 
0592     /* Init Coex variables that are not zero */
0593     if (type & BTC_RESET_DM) {
0594         memset(&btc->dm, 0, sizeof(btc->dm));
0595         memset(bt_linfo->rssi_state, 0, sizeof(bt_linfo->rssi_state));
0596 
0597         for (i = 0; i < RTW89_PORT_NUM; i++)
0598             memset(wl_linfo[i].rssi_state, 0,
0599                    sizeof(wl_linfo[i].rssi_state));
0600 
0601         /* set the slot_now table to original */
0602         btc->dm.tdma_now = t_def[CXTD_OFF];
0603         btc->dm.tdma = t_def[CXTD_OFF];
0604         memcpy(&btc->dm.slot_now, s_def, sizeof(btc->dm.slot_now));
0605         memcpy(&btc->dm.slot, s_def, sizeof(btc->dm.slot));
0606 
0607         btc->policy_len = 0;
0608         btc->bt_req_len = 0;
0609 
0610         btc->dm.coex_info_map = BTC_COEX_INFO_ALL;
0611         btc->dm.wl_tx_limit.tx_time = BTC_MAX_TX_TIME_DEF;
0612         btc->dm.wl_tx_limit.tx_retry = BTC_MAX_TX_RETRY_DEF;
0613     }
0614 
0615     if (type & BTC_RESET_MDINFO)
0616         memset(&btc->mdinfo, 0, sizeof(btc->mdinfo));
0617 }
0618 
0619 #define BTC_FWINFO_BUF 1024
0620 
0621 #define BTC_RPT_HDR_SIZE 3
0622 #define BTC_CHK_WLSLOT_DRIFT_MAX 15
0623 #define BTC_CHK_HANG_MAX 3
0624 
0625 static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt)
0626 {
0627     struct rtw89_btc *btc = &rtwdev->btc;
0628     struct rtw89_btc_cx *cx = &btc->cx;
0629     struct rtw89_btc_dm *dm = &btc->dm;
0630     struct rtw89_btc_bt_info *bt = &cx->bt;
0631 
0632     rtw89_debug(rtwdev, RTW89_DBG_BTC,
0633             "[BTC], %s(): type:%d cnt:%d\n",
0634             __func__, type, cnt);
0635 
0636     switch (type) {
0637     case BTC_DCNT_RPT_FREEZE:
0638         if (dm->cnt_dm[BTC_DCNT_RPT] == cnt && btc->fwinfo.rpt_en_map)
0639             dm->cnt_dm[BTC_DCNT_RPT_FREEZE]++;
0640         else
0641             dm->cnt_dm[BTC_DCNT_RPT_FREEZE] = 0;
0642 
0643         if (dm->cnt_dm[BTC_DCNT_RPT_FREEZE] >= BTC_CHK_HANG_MAX)
0644             dm->error.map.wl_fw_hang = true;
0645         else
0646             dm->error.map.wl_fw_hang = false;
0647 
0648         dm->cnt_dm[BTC_DCNT_RPT] = cnt;
0649         break;
0650     case BTC_DCNT_CYCLE_FREEZE:
0651         if (dm->cnt_dm[BTC_DCNT_CYCLE] == cnt &&
0652             (dm->tdma_now.type != CXTDMA_OFF ||
0653              dm->tdma_now.ext_ctrl == CXECTL_EXT))
0654             dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE]++;
0655         else
0656             dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE] = 0;
0657 
0658         if (dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE] >= BTC_CHK_HANG_MAX)
0659             dm->error.map.cycle_hang = true;
0660         else
0661             dm->error.map.cycle_hang = false;
0662 
0663         dm->cnt_dm[BTC_DCNT_CYCLE] = cnt;
0664         break;
0665     case BTC_DCNT_W1_FREEZE:
0666         if (dm->cnt_dm[BTC_DCNT_W1] == cnt &&
0667             dm->tdma_now.type != CXTDMA_OFF)
0668             dm->cnt_dm[BTC_DCNT_W1_FREEZE]++;
0669         else
0670             dm->cnt_dm[BTC_DCNT_W1_FREEZE] = 0;
0671 
0672         if (dm->cnt_dm[BTC_DCNT_W1_FREEZE] >= BTC_CHK_HANG_MAX)
0673             dm->error.map.w1_hang = true;
0674         else
0675             dm->error.map.w1_hang = false;
0676 
0677         dm->cnt_dm[BTC_DCNT_W1] = cnt;
0678         break;
0679     case BTC_DCNT_B1_FREEZE:
0680         if (dm->cnt_dm[BTC_DCNT_B1] == cnt &&
0681             dm->tdma_now.type != CXTDMA_OFF)
0682             dm->cnt_dm[BTC_DCNT_B1_FREEZE]++;
0683         else
0684             dm->cnt_dm[BTC_DCNT_B1_FREEZE] = 0;
0685 
0686         if (dm->cnt_dm[BTC_DCNT_B1_FREEZE] >= BTC_CHK_HANG_MAX)
0687             dm->error.map.b1_hang = true;
0688         else
0689             dm->error.map.b1_hang = false;
0690 
0691         dm->cnt_dm[BTC_DCNT_B1] = cnt;
0692         break;
0693     case BTC_DCNT_TDMA_NONSYNC:
0694         if (cnt != 0) /* if tdma not sync between drv/fw  */
0695             dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC]++;
0696         else
0697             dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] = 0;
0698 
0699         if (dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] >= BTC_CHK_HANG_MAX)
0700             dm->error.map.tdma_no_sync = true;
0701         else
0702             dm->error.map.tdma_no_sync = false;
0703         break;
0704     case BTC_DCNT_SLOT_NONSYNC:
0705         if (cnt != 0) /* if slot not sync between drv/fw  */
0706             dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC]++;
0707         else
0708             dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] = 0;
0709 
0710         if (dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] >= BTC_CHK_HANG_MAX)
0711             dm->error.map.tdma_no_sync = true;
0712         else
0713             dm->error.map.tdma_no_sync = false;
0714         break;
0715     case BTC_DCNT_BTCNT_FREEZE:
0716         cnt = cx->cnt_bt[BTC_BCNT_HIPRI_RX] +
0717               cx->cnt_bt[BTC_BCNT_HIPRI_TX] +
0718               cx->cnt_bt[BTC_BCNT_LOPRI_RX] +
0719               cx->cnt_bt[BTC_BCNT_LOPRI_TX];
0720 
0721         if (cnt == 0)
0722             dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE]++;
0723         else
0724             dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] = 0;
0725 
0726         if ((dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] >= BTC_CHK_HANG_MAX &&
0727              bt->enable.now) || (!dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] &&
0728              !bt->enable.now))
0729             _update_bt_scbd(rtwdev, false);
0730         break;
0731     case BTC_DCNT_WL_SLOT_DRIFT:
0732         if (cnt >= BTC_CHK_WLSLOT_DRIFT_MAX)
0733             dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT]++;
0734         else
0735             dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] = 0;
0736 
0737         if (dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
0738             dm->error.map.wl_slot_drift = true;
0739         else
0740             dm->error.map.wl_slot_drift = false;
0741         break;
0742     }
0743 }
0744 
0745 static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
0746 {
0747     struct rtw89_btc *btc = &rtwdev->btc;
0748     struct rtw89_btc_bt_info *bt = &btc->cx.bt;
0749     struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
0750     struct rtw89_btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc;
0751     struct rtw89_btc_fbtc_btver *pver = NULL;
0752     struct rtw89_btc_fbtc_btscan *pscan = NULL;
0753     struct rtw89_btc_fbtc_btafh *pafh = NULL;
0754     struct rtw89_btc_fbtc_btdevinfo *pdev = NULL;
0755 
0756     pver = (struct rtw89_btc_fbtc_btver *)pfinfo;
0757     pscan = (struct rtw89_btc_fbtc_btscan *)pfinfo;
0758     pafh = (struct rtw89_btc_fbtc_btafh *)pfinfo;
0759     pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo;
0760 
0761     rtw89_debug(rtwdev, RTW89_DBG_BTC,
0762             "[BTC], %s(): rpt_type:%d\n",
0763             __func__, rpt_type);
0764 
0765     switch (rpt_type) {
0766     case BTC_RPT_TYPE_BT_VER:
0767         bt->ver_info.fw = le32_to_cpu(pver->fw_ver);
0768         bt->ver_info.fw_coex = le32_get_bits(pver->coex_ver, GENMASK(7, 0));
0769         bt->feature = le32_to_cpu(pver->feature);
0770         break;
0771     case BTC_RPT_TYPE_BT_SCAN:
0772         memcpy(bt->scan_info, pscan->scan, BTC_SCAN_MAX1);
0773         break;
0774     case BTC_RPT_TYPE_BT_AFH:
0775         memcpy(&bt_linfo->afh_map[0], pafh->afh_l, 4);
0776         memcpy(&bt_linfo->afh_map[4], pafh->afh_m, 4);
0777         memcpy(&bt_linfo->afh_map[8], pafh->afh_h, 2);
0778         break;
0779     case BTC_RPT_TYPE_BT_DEVICE:
0780         a2dp->device_name = le32_to_cpu(pdev->dev_name);
0781         a2dp->vendor_id = le16_to_cpu(pdev->vendor_id);
0782         a2dp->flush_time = le32_to_cpu(pdev->flush_time);
0783         break;
0784     default:
0785         break;
0786     }
0787 }
0788 
0789 struct rtw89_btc_fbtc_cysta_cpu {
0790     u8 fver;
0791     u8 rsvd;
0792     u16 cycles;
0793     u16 cycles_a2dp[CXT_FLCTRL_MAX];
0794     u16 a2dpept;
0795     u16 a2dpeptto;
0796     u16 tavg_cycle[CXT_MAX];
0797     u16 tmax_cycle[CXT_MAX];
0798     u16 tmaxdiff_cycle[CXT_MAX];
0799     u16 tavg_a2dp[CXT_FLCTRL_MAX];
0800     u16 tmax_a2dp[CXT_FLCTRL_MAX];
0801     u16 tavg_a2dpept;
0802     u16 tmax_a2dpept;
0803     u16 tavg_lk;
0804     u16 tmax_lk;
0805     u32 slot_cnt[CXST_MAX];
0806     u32 bcn_cnt[CXBCN_MAX];
0807     u32 leakrx_cnt;
0808     u32 collision_cnt;
0809     u32 skip_cnt;
0810     u32 exception;
0811     u32 except_cnt;
0812     u16 tslot_cycle[BTC_CYCLE_SLOT_MAX];
0813 };
0814 
0815 static void rtw89_btc_fbtc_cysta_to_cpu(const struct rtw89_btc_fbtc_cysta *src,
0816                     struct rtw89_btc_fbtc_cysta_cpu *dst)
0817 {
0818     static_assert(sizeof(*src) == sizeof(*dst));
0819 
0820 #define __CPY_U8(_x)    ({dst->_x = src->_x; })
0821 #define __CPY_LE16(_x)  ({dst->_x = le16_to_cpu(src->_x); })
0822 #define __CPY_LE16S(_x) ({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \
0823                    dst->_x[_i] = le16_to_cpu(src->_x[_i]); })
0824 #define __CPY_LE32(_x)  ({dst->_x = le32_to_cpu(src->_x); })
0825 #define __CPY_LE32S(_x) ({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \
0826                    dst->_x[_i] = le32_to_cpu(src->_x[_i]); })
0827 
0828     __CPY_U8(fver);
0829     __CPY_U8(rsvd);
0830     __CPY_LE16(cycles);
0831     __CPY_LE16S(cycles_a2dp);
0832     __CPY_LE16(a2dpept);
0833     __CPY_LE16(a2dpeptto);
0834     __CPY_LE16S(tavg_cycle);
0835     __CPY_LE16S(tmax_cycle);
0836     __CPY_LE16S(tmaxdiff_cycle);
0837     __CPY_LE16S(tavg_a2dp);
0838     __CPY_LE16S(tmax_a2dp);
0839     __CPY_LE16(tavg_a2dpept);
0840     __CPY_LE16(tmax_a2dpept);
0841     __CPY_LE16(tavg_lk);
0842     __CPY_LE16(tmax_lk);
0843     __CPY_LE32S(slot_cnt);
0844     __CPY_LE32S(bcn_cnt);
0845     __CPY_LE32(leakrx_cnt);
0846     __CPY_LE32(collision_cnt);
0847     __CPY_LE32(skip_cnt);
0848     __CPY_LE32(exception);
0849     __CPY_LE32(except_cnt);
0850     __CPY_LE16S(tslot_cycle);
0851 
0852 #undef __CPY_U8
0853 #undef __CPY_LE16
0854 #undef __CPY_LE16S
0855 #undef __CPY_LE32
0856 #undef __CPY_LE32S
0857 }
0858 
0859 #define BTC_LEAK_AP_TH 10
0860 #define BTC_CYSTA_CHK_PERIOD 100
0861 
0862 struct rtw89_btc_prpt {
0863     u8 type;
0864     __le16 len;
0865     u8 content[];
0866 } __packed;
0867 
0868 static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
0869                struct rtw89_btc_btf_fwinfo *pfwinfo,
0870                u8 *prptbuf, u32 index)
0871 {
0872     struct rtw89_btc *btc = &rtwdev->btc;
0873     struct rtw89_btc_dm *dm = &btc->dm;
0874     struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
0875     struct rtw89_btc_wl_info *wl = &btc->cx.wl;
0876     struct rtw89_btc_fbtc_rpt_ctrl *prpt = NULL;
0877     struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL;
0878     struct rtw89_btc_fbtc_cysta_cpu pcysta[1];
0879     struct rtw89_btc_prpt *btc_prpt = NULL;
0880     struct rtw89_btc_fbtc_slot *rtp_slot = NULL;
0881     u8 rpt_type = 0, *rpt_content = NULL, *pfinfo = NULL;
0882     u16 wl_slot_set = 0;
0883     u32 trace_step = btc->ctrl.trace_step, rpt_len = 0, diff_t;
0884     u8 i;
0885 
0886     rtw89_debug(rtwdev, RTW89_DBG_BTC,
0887             "[BTC], %s(): index:%d\n",
0888             __func__, index);
0889 
0890     if (!prptbuf) {
0891         pfwinfo->err[BTFRE_INVALID_INPUT]++;
0892         return 0;
0893     }
0894 
0895     btc_prpt = (struct rtw89_btc_prpt *)&prptbuf[index];
0896     rpt_type = btc_prpt->type;
0897     rpt_len = le16_to_cpu(btc_prpt->len);
0898     rpt_content = btc_prpt->content;
0899 
0900     rtw89_debug(rtwdev, RTW89_DBG_BTC,
0901             "[BTC], %s(): rpt_type:%d\n",
0902             __func__, rpt_type);
0903 
0904     switch (rpt_type) {
0905     case BTC_RPT_TYPE_CTRL:
0906         pcinfo = &pfwinfo->rpt_ctrl.cinfo;
0907         pfinfo = (u8 *)(&pfwinfo->rpt_ctrl.finfo);
0908         pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo);
0909         pcinfo->req_fver = BTCRPT_VER;
0910         pcinfo->rx_len = rpt_len;
0911         pcinfo->rx_cnt++;
0912         break;
0913     case BTC_RPT_TYPE_TDMA:
0914         pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
0915         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_tdma.finfo);
0916         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo);
0917         pcinfo->req_fver = FCXTDMA_VER;
0918         pcinfo->rx_len = rpt_len;
0919         pcinfo->rx_cnt++;
0920         break;
0921     case BTC_RPT_TYPE_SLOT:
0922         pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
0923         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_slots.finfo);
0924         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo);
0925         pcinfo->req_fver = FCXSLOTS_VER;
0926         pcinfo->rx_len = rpt_len;
0927         pcinfo->rx_cnt++;
0928         break;
0929     case BTC_RPT_TYPE_CYSTA:
0930         pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
0931         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_cysta.finfo);
0932         pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo;
0933         rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta);
0934         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo);
0935         pcinfo->req_fver = FCXCYSTA_VER;
0936         pcinfo->rx_len = rpt_len;
0937         pcinfo->rx_cnt++;
0938         break;
0939     case BTC_RPT_TYPE_STEP:
0940         pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
0941         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_step.finfo);
0942         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.step[0]) *
0943                   trace_step + 8;
0944         pcinfo->req_fver = FCXSTEP_VER;
0945         pcinfo->rx_len = rpt_len;
0946         pcinfo->rx_cnt++;
0947         break;
0948     case BTC_RPT_TYPE_NULLSTA:
0949         pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
0950         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_nullsta.finfo);
0951         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo);
0952         pcinfo->req_fver = FCXNULLSTA_VER;
0953         pcinfo->rx_len = rpt_len;
0954         pcinfo->rx_cnt++;
0955         break;
0956     case BTC_RPT_TYPE_MREG:
0957         pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
0958         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_mregval.finfo);
0959         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo);
0960         pcinfo->req_fver = FCXMREG_VER;
0961         pcinfo->rx_len = rpt_len;
0962         pcinfo->rx_cnt++;
0963         break;
0964     case BTC_RPT_TYPE_GPIO_DBG:
0965         pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
0966         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_gpio_dbg.finfo);
0967         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo);
0968         pcinfo->req_fver = FCXGPIODBG_VER;
0969         pcinfo->rx_len = rpt_len;
0970         pcinfo->rx_cnt++;
0971         break;
0972     case BTC_RPT_TYPE_BT_VER:
0973         pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo;
0974         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btver.finfo);
0975         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo);
0976         pcinfo->req_fver = FCX_BTVER_VER;
0977         pcinfo->rx_len = rpt_len;
0978         pcinfo->rx_cnt++;
0979         break;
0980     case BTC_RPT_TYPE_BT_SCAN:
0981         pcinfo = &pfwinfo->rpt_fbtc_btscan.cinfo;
0982         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btscan.finfo);
0983         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo);
0984         pcinfo->req_fver = FCX_BTSCAN_VER;
0985         pcinfo->rx_len = rpt_len;
0986         pcinfo->rx_cnt++;
0987         break;
0988     case BTC_RPT_TYPE_BT_AFH:
0989         pcinfo = &pfwinfo->rpt_fbtc_btafh.cinfo;
0990         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btafh.finfo);
0991         pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo);
0992         pcinfo->req_fver = FCX_BTAFH_VER;
0993         pcinfo->rx_len = rpt_len;
0994         pcinfo->rx_cnt++;
0995         break;
0996     case BTC_RPT_TYPE_BT_DEVICE:
0997         pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo;
0998         pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btdev.finfo);
0999         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 
1154 static 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 
1183 static 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 
1214 static 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 
1259 static 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 
1288 static 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 
1310 static 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 
1347 static 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 
1363 static 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 
1409 static 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 
1429 static
1430 void 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 
1451 static 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 
1486 static 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 
1503 static 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 
1535 static 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 
1551 static 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 
1573 static 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 
1597 static 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 
1652 static 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 
1678 static 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 
1765 static 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 
1845 struct 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 
1856 struct 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 
1864 struct btc_btinfo_hb0 {
1865     s8 rssi;
1866 };
1867 
1868 struct 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 
1879 struct 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 
1888 struct btc_btinfo_hb3 {
1889     u8 a2dp_bitpool: 6;
1890     u8 tx_3m: 1;
1891     u8 a2dp_sink: 1;
1892 };
1893 
1894 union 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 
1904 static 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 
2206 static 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 
2239 static 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 
2259 static 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 
2390 static 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 
2396 static 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 
2404 static 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 
2417 static 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 
2429 static 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 
2437 static 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 
2445 static 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 
2491 static 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 
2507 static 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 
2522 static 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 
2567 static 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 
2595 static 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 
2623 static 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 
2667 static 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 
2695 static 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 
2723 static 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 
2754 static 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 
2760 static 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 
2772 static 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 
2778 static 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 
2793 static 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 
2825 struct 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 
2834 static 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 
2890 static 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 
2952 static 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 */
2970 static 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 
2979 static 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 
3060 static void _action_wl_2g_sta(struct rtw89_dev *rtwdev)
3061 {
3062     _action_by_bt(rtwdev);
3063 }
3064 
3065 static 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 
3095 static 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 
3113 static 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 
3130 static 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 
3148 static 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 
3165 static 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 
3183 static 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 
3196 static 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 
3214 static 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 
3231 static 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 
3253 static 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 
3275 static
3276 void _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 
3286 static 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 
3440 void 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 
3461 void 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 
3477 void 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 
3501 static 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 
3564 static 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 
3584 static
3585 void _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 
3730 exit:
3731     rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): exit\n", __func__);
3732     _action_common(rtwdev);
3733 }
3734 
3735 void 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 
3743 void 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 
3760 static 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 
3776 void 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 
3827 void 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 
3850 void 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 
3871 void 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 
3893 void 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 
3957 void 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 
3968 void 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 
3978 void 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 
3989 void 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 
4000 static 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 
4143 enum 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 
4150 void 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 
4238 void 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 
4281 static 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 
4349 void 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 }
4383 EXPORT_SYMBOL(rtw89_btc_ntfy_wl_rfk);
4384 
4385 struct 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 
4394 static 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 
4497 void 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 
4540 void 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 
4594 static 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 
4668 static 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 
4727 static 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 
4759 enum btc_bt_a2dp_type {
4760     BTC_A2DP_LEGACY = 0,
4761     BTC_A2DP_TWS_SNIFF = 1,
4762     BTC_A2DP_TWS_RELAY = 2,
4763 };
4764 
4765 static 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 
4816 static 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 
4912 static 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 
5017 static
5018 void 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 
5042 static 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 
5056 static 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 
5113 static 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 
5155 static 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 
5213 static 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 
5246 static 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 
5372 static 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 
5410 static 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 
5479 static 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 
5494 static 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 
5613 static 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 
5717 void 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 }