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