linux/drivers/net/wireless/realtek/rtw88/coex.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/* Copyright(c) 2018-2019  Realtek Corporation
   3 */
   4
   5#include "main.h"
   6#include "coex.h"
   7#include "fw.h"
   8#include "ps.h"
   9#include "debug.h"
  10#include "reg.h"
  11#include "phy.h"
  12
  13static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state,
  14                                   u8 rssi, u8 rssi_thresh)
  15{
  16        struct rtw_chip_info *chip = rtwdev->chip;
  17        u8 tol = chip->rssi_tolerance;
  18        u8 next_state;
  19
  20        if (pre_state == COEX_RSSI_STATE_LOW ||
  21            pre_state == COEX_RSSI_STATE_STAY_LOW) {
  22                if (rssi >= (rssi_thresh + tol))
  23                        next_state = COEX_RSSI_STATE_HIGH;
  24                else
  25                        next_state = COEX_RSSI_STATE_STAY_LOW;
  26        } else {
  27                if (rssi < rssi_thresh)
  28                        next_state = COEX_RSSI_STATE_LOW;
  29                else
  30                        next_state = COEX_RSSI_STATE_STAY_HIGH;
  31        }
  32
  33        return next_state;
  34}
  35
  36static void rtw_coex_limited_tx(struct rtw_dev *rtwdev,
  37                                bool tx_limit_en, bool ampdu_limit_en)
  38{
  39        struct rtw_chip_info *chip = rtwdev->chip;
  40        struct rtw_coex *coex = &rtwdev->coex;
  41        struct rtw_coex_stat *coex_stat = &coex->stat;
  42        u8 num_of_active_port = 1;
  43
  44        if (!chip->scbd_support)
  45                return;
  46
  47        /* force max tx retry limit = 8 */
  48        if (coex_stat->wl_tx_limit_en == tx_limit_en &&
  49            coex_stat->wl_ampdu_limit_en == ampdu_limit_en)
  50                return;
  51
  52        if (!coex_stat->wl_tx_limit_en) {
  53                coex_stat->darfrc = rtw_read32(rtwdev, REG_DARFRC);
  54                coex_stat->darfrch = rtw_read32(rtwdev, REG_DARFRCH);
  55                coex_stat->retry_limit = rtw_read16(rtwdev, REG_RETRY_LIMIT);
  56        }
  57
  58        if (!coex_stat->wl_ampdu_limit_en)
  59                coex_stat->ampdu_max_time =
  60                                rtw_read8(rtwdev, REG_AMPDU_MAX_TIME_V1);
  61
  62        coex_stat->wl_tx_limit_en = tx_limit_en;
  63        coex_stat->wl_ampdu_limit_en = ampdu_limit_en;
  64
  65        if (tx_limit_en) {
  66                /* set BT polluted packet on for tx rate adaptive,
  67                 * not including tx retry broken by PTA
  68                 */
  69                rtw_write8_set(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);
  70
  71                /* set queue life time to avoid can't reach tx retry limit
  72                 * if tx is always broken by GNT_BT
  73                 */
  74                if (num_of_active_port <= 1)
  75                        rtw_write8_set(rtwdev, REG_LIFETIME_EN, 0xf);
  76                rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x0808);
  77
  78                /* auto rate fallback step within 8 retries */
  79                rtw_write32(rtwdev, REG_DARFRC, 0x1000000);
  80                rtw_write32(rtwdev, REG_DARFRCH, 0x4030201);
  81        } else {
  82                rtw_write8_clr(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);
  83                rtw_write8_clr(rtwdev, REG_LIFETIME_EN, 0xf);
  84
  85                rtw_write16(rtwdev, REG_RETRY_LIMIT, coex_stat->retry_limit);
  86                rtw_write32(rtwdev, REG_DARFRC, coex_stat->darfrc);
  87                rtw_write32(rtwdev, REG_DARFRCH, coex_stat->darfrch);
  88        }
  89
  90        if (ampdu_limit_en)
  91                rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, 0x20);
  92        else
  93                rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1,
  94                           coex_stat->ampdu_max_time);
  95}
  96
  97static void rtw_coex_limited_wl(struct rtw_dev *rtwdev)
  98{
  99        struct rtw_coex *coex = &rtwdev->coex;
 100        struct rtw_coex_dm *coex_dm = &coex->dm;
 101        bool tx_limit = false;
 102        bool tx_agg_ctrl = false;
 103
 104        if (!coex->under_5g && coex_dm->bt_status != COEX_BTSTATUS_NCON_IDLE) {
 105                tx_limit = true;
 106                tx_agg_ctrl = true;
 107        }
 108
 109        rtw_coex_limited_tx(rtwdev, tx_limit, tx_agg_ctrl);
 110}
 111
 112static bool rtw_coex_freerun_check(struct rtw_dev *rtwdev)
 113{
 114        struct rtw_coex *coex = &rtwdev->coex;
 115        struct rtw_coex_dm *coex_dm = &coex->dm;
 116        struct rtw_coex_stat *coex_stat = &coex->stat;
 117        struct rtw_efuse *efuse = &rtwdev->efuse;
 118        u8 bt_rssi;
 119        u8 ant_distance = 10;
 120
 121        if (coex_stat->bt_disabled)
 122                return false;
 123
 124        if (efuse->share_ant || ant_distance <= 5 || !coex_stat->wl_gl_busy)
 125                return false;
 126
 127        if (ant_distance >= 40 || coex_stat->bt_hid_pair_num >= 2)
 128                return true;
 129
 130        /* ant_distance = 5 ~ 40  */
 131        if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]) &&
 132            COEX_RSSI_HIGH(coex_dm->bt_rssi_state[0]))
 133                return true;
 134
 135        if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
 136                bt_rssi = coex_dm->bt_rssi_state[0];
 137        else
 138                bt_rssi = coex_dm->bt_rssi_state[1];
 139
 140        if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
 141            COEX_RSSI_HIGH(bt_rssi) &&
 142            coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] <= 5)
 143                return true;
 144
 145        return false;
 146}
 147
 148static void rtw_coex_wl_slot_extend(struct rtw_dev *rtwdev, bool enable)
 149{
 150        struct rtw_coex *coex = &rtwdev->coex;
 151        struct rtw_coex_stat *coex_stat = &coex->stat;
 152        u8 para[6] = {0};
 153
 154        para[0] = COEX_H2C69_WL_LEAKAP;
 155        para[1] = PARA1_H2C69_DIS_5MS;
 156
 157        if (enable)
 158                para[1] = PARA1_H2C69_EN_5MS;
 159        else
 160                coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
 161
 162        coex_stat->wl_slot_extend = enable;
 163        rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
 164}
 165
 166static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev)
 167{
 168        struct rtw_coex *coex = &rtwdev->coex;
 169        struct rtw_coex_stat *coex_stat = &coex->stat;
 170
 171        if (coex->manual_control || coex->stop_dm)
 172                return;
 173
 174
 175        if (coex_stat->tdma_timer_base == 3 && coex_stat->wl_slot_extend) {
 176                rtw_dbg(rtwdev, RTW_DBG_COEX,
 177                        "[BTCoex], set h2c 0x69 opcode 12 to turn off 5ms WL slot extend!!\n");
 178                rtw_coex_wl_slot_extend(rtwdev, false);
 179                return;
 180        }
 181
 182        if (coex_stat->wl_slot_extend && coex_stat->wl_force_lps_ctrl &&
 183            !coex_stat->wl_cck_lock_ever) {
 184                if (coex_stat->wl_fw_dbg_info[7] <= 5)
 185                        coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]++;
 186                else
 187                        coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
 188
 189                rtw_dbg(rtwdev, RTW_DBG_COEX,
 190                        "[BTCoex], 5ms WL slot extend cnt = %d!!\n",
 191                        coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]);
 192
 193                if (coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] == 7) {
 194                        rtw_dbg(rtwdev, RTW_DBG_COEX,
 195                                "[BTCoex], set h2c 0x69 opcode 12 to turn off 5ms WL slot extend!!\n");
 196                        rtw_coex_wl_slot_extend(rtwdev, false);
 197                }
 198        } else if (!coex_stat->wl_slot_extend && coex_stat->wl_cck_lock) {
 199                rtw_dbg(rtwdev, RTW_DBG_COEX,
 200                        "[BTCoex], set h2c 0x69 opcode 12 to turn on 5ms WL slot extend!!\n");
 201
 202                rtw_coex_wl_slot_extend(rtwdev, true);
 203        }
 204}
 205
 206static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev)
 207{
 208        struct rtw_coex *coex = &rtwdev->coex;
 209        struct rtw_coex_stat *coex_stat = &coex->stat;
 210        struct rtw_coex_dm *coex_dm = &coex->dm;
 211
 212        bool is_cck_lock_rate = false;
 213
 214        if (coex_stat->wl_coex_mode != COEX_WLINK_2G1PORT &&
 215            coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)
 216                return;
 217
 218        if (coex_dm->bt_status == COEX_BTSTATUS_INQ_PAGE ||
 219            coex_stat->bt_setup_link) {
 220                coex_stat->wl_cck_lock = false;
 221                coex_stat->wl_cck_lock_pre = false;
 222                return;
 223        }
 224
 225        if (coex_stat->wl_rx_rate <= COEX_CCK_2 ||
 226            coex_stat->wl_rts_rx_rate <= COEX_CCK_2)
 227                is_cck_lock_rate = true;
 228
 229        if (coex_stat->wl_connected && coex_stat->wl_gl_busy &&
 230            COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
 231            (coex_dm->bt_status == COEX_BTSTATUS_ACL_BUSY ||
 232             coex_dm->bt_status == COEX_BTSTATUS_ACL_SCO_BUSY ||
 233             coex_dm->bt_status == COEX_BTSTATUS_SCO_BUSY)) {
 234                if (is_cck_lock_rate) {
 235                        coex_stat->wl_cck_lock = true;
 236
 237                        rtw_dbg(rtwdev, RTW_DBG_COEX,
 238                                "[BTCoex], cck locking...\n");
 239
 240                } else {
 241                        coex_stat->wl_cck_lock = false;
 242
 243                        rtw_dbg(rtwdev, RTW_DBG_COEX,
 244                                "[BTCoex], cck unlock...\n");
 245                }
 246        } else {
 247                coex_stat->wl_cck_lock = false;
 248        }
 249
 250        /* CCK lock identification */
 251        if (coex_stat->wl_cck_lock && !coex_stat->wl_cck_lock_pre)
 252                ieee80211_queue_delayed_work(rtwdev->hw, &coex->wl_ccklock_work,
 253                                             3 * HZ);
 254
 255        coex_stat->wl_cck_lock_pre = coex_stat->wl_cck_lock;
 256}
 257
 258static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev)
 259{
 260        struct rtw_coex *coex = &rtwdev->coex;
 261        struct rtw_coex_stat *coex_stat = &coex->stat;
 262        struct rtw_dm_info *dm_info = &rtwdev->dm_info;
 263        u32 cnt_cck;
 264        bool wl_cck_lock = false;
 265
 266        /* wifi noisy environment identification */
 267        cnt_cck = dm_info->cck_ok_cnt + dm_info->cck_err_cnt;
 268
 269        if (!coex_stat->wl_gl_busy && !wl_cck_lock) {
 270                if (cnt_cck > 250) {
 271                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] < 5)
 272                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY2]++;
 273
 274                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5) {
 275                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0;
 276                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0;
 277                        }
 278                } else if (cnt_cck < 100) {
 279                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] < 5)
 280                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY0]++;
 281
 282                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] == 5) {
 283                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0;
 284                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0;
 285                        }
 286                } else {
 287                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] < 5)
 288                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY1]++;
 289
 290                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5) {
 291                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0;
 292                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0;
 293                        }
 294                }
 295
 296                if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5)
 297                        coex_stat->wl_noisy_level = 2;
 298                else if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5)
 299                        coex_stat->wl_noisy_level = 1;
 300                else
 301                        coex_stat->wl_noisy_level = 0;
 302
 303                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], wl_noisy_level = %d\n",
 304                        coex_stat->wl_noisy_level);
 305        }
 306}
 307
 308static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type)
 309{
 310        struct rtw_coex *coex = &rtwdev->coex;
 311        struct rtw_coex_stat *coex_stat = &coex->stat;
 312        u8 para[2] = {0};
 313        u8 times;
 314        u16 tbtt_interval = coex_stat->wl_beacon_interval;
 315
 316        if (coex_stat->tdma_timer_base == type)
 317                return;
 318
 319        coex_stat->tdma_timer_base = type;
 320
 321        para[0] = COEX_H2C69_TDMA_SLOT;
 322
 323        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], tbtt_interval = %d\n",
 324                tbtt_interval);
 325
 326        if (type == TDMA_TIMER_TYPE_4SLOT && tbtt_interval < 120) {
 327                para[1] = PARA1_H2C69_TDMA_4SLOT; /* 4-slot */
 328        } else if (tbtt_interval < 80 && tbtt_interval > 0) {
 329                times = 100 / tbtt_interval;
 330                if (100 % tbtt_interval != 0)
 331                        times++;
 332
 333                para[1] = FIELD_PREP(PARA1_H2C69_TBTT_TIMES, times);
 334        } else if (tbtt_interval >= 180) {
 335                times = tbtt_interval / 100;
 336                if (tbtt_interval % 100 <= 80)
 337                        times--;
 338
 339                para[1] = FIELD_PREP(PARA1_H2C69_TBTT_TIMES, times) |
 340                          FIELD_PREP(PARA1_H2C69_TBTT_DIV100, 1);
 341        } else {
 342                para[1] = PARA1_H2C69_TDMA_2SLOT;
 343        }
 344
 345        rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
 346
 347        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): h2c_0x69 = 0x%x\n",
 348                __func__, para[1]);
 349
 350        /* no 5ms_wl_slot_extend for 4-slot mode  */
 351        if (coex_stat->tdma_timer_base == 3)
 352                rtw_coex_wl_ccklock_action(rtwdev);
 353}
 354
 355static void rtw_coex_set_wl_pri_mask(struct rtw_dev *rtwdev, u8 bitmap,
 356                                     u8 data)
 357{
 358        u32 addr;
 359
 360        addr = REG_BT_COEX_TABLE_H + (bitmap / 8);
 361        bitmap = bitmap % 8;
 362
 363        rtw_write8_mask(rtwdev, addr, BIT(bitmap), data);
 364}
 365
 366void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set)
 367{
 368        struct rtw_chip_info *chip = rtwdev->chip;
 369        struct rtw_coex *coex = &rtwdev->coex;
 370        struct rtw_coex_stat *coex_stat = &coex->stat;
 371        u16 val = 0x2;
 372
 373        if (!chip->scbd_support)
 374                return;
 375
 376        val |= coex_stat->score_board;
 377
 378        /* for 8822b, scbd[10] is CQDDR on
 379         * for 8822c, scbd[10] is no fix 2M
 380         */
 381        if (!chip->new_scbd10_def && (bitpos & COEX_SCBD_FIX2M)) {
 382                if (set)
 383                        val &= ~COEX_SCBD_FIX2M;
 384                else
 385                        val |= COEX_SCBD_FIX2M;
 386        } else {
 387                if (set)
 388                        val |= bitpos;
 389                else
 390                        val &= ~bitpos;
 391        }
 392
 393        if (val != coex_stat->score_board) {
 394                coex_stat->score_board = val;
 395                val |= BIT_BT_INT_EN;
 396                rtw_write16(rtwdev, REG_WIFI_BT_INFO, val);
 397        }
 398}
 399EXPORT_SYMBOL(rtw_coex_write_scbd);
 400
 401static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev)
 402{
 403        struct rtw_chip_info *chip = rtwdev->chip;
 404
 405        if (!chip->scbd_support)
 406                return 0;
 407
 408        return (rtw_read16(rtwdev, REG_WIFI_BT_INFO)) & ~(BIT_BT_INT_EN);
 409}
 410
 411static void rtw_coex_check_rfk(struct rtw_dev *rtwdev)
 412{
 413        struct rtw_chip_info *chip = rtwdev->chip;
 414        struct rtw_coex *coex = &rtwdev->coex;
 415        struct rtw_coex_stat *coex_stat = &coex->stat;
 416        struct rtw_coex_rfe *coex_rfe = &coex->rfe;
 417        u8 cnt = 0;
 418        u32 wait_cnt;
 419        bool btk, wlk;
 420
 421        if (coex_rfe->wlg_at_btg && chip->scbd_support &&
 422            coex_stat->bt_iqk_state != 0xff) {
 423                rtw_dbg(rtwdev, RTW_DBG_COEX,
 424                        "[BTCoex], (Before Ant Setup) Delay by IQK\n");
 425
 426                wait_cnt = COEX_RFK_TIMEOUT / COEX_MIN_DELAY;
 427                do {
 428                        /* BT RFK */
 429                        btk = !!(rtw_coex_read_scbd(rtwdev) & COEX_SCBD_BT_RFK);
 430
 431                        /* WL RFK */
 432                        wlk = !!(rtw_read8(rtwdev, REG_ARFR4) & BIT_WL_RFK);
 433
 434                        if (!btk && !wlk)
 435                                break;
 436
 437                        rtw_dbg(rtwdev, RTW_DBG_COEX,
 438                                "[BTCoex], (Before Ant Setup) wlk = %d, btk = %d\n",
 439                                wlk, btk);
 440
 441                        mdelay(COEX_MIN_DELAY);
 442                } while (++cnt < wait_cnt);
 443
 444                if (cnt >= wait_cnt)
 445                        coex_stat->bt_iqk_state = 0xff;
 446        }
 447}
 448
 449static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev)
 450{
 451        struct rtw_coex *coex = &rtwdev->coex;
 452        struct rtw_coex_stat *coex_stat = &coex->stat;
 453
 454        if (coex_stat->bt_disabled)
 455                return;
 456
 457        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
 458
 459        rtw_fw_query_bt_info(rtwdev);
 460}
 461
 462static void rtw_coex_gnt_workaround(struct rtw_dev *rtwdev, bool force, u8 mode)
 463{
 464        rtw_coex_set_gnt_fix(rtwdev);
 465}
 466
 467static void rtw_coex_monitor_bt_ctr(struct rtw_dev *rtwdev)
 468{
 469        struct rtw_coex *coex = &rtwdev->coex;
 470        struct rtw_coex_stat *coex_stat = &coex->stat;
 471        u32 tmp;
 472
 473        tmp = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS);
 474        coex_stat->hi_pri_tx = FIELD_GET(MASKLWORD, tmp);
 475        coex_stat->hi_pri_rx = FIELD_GET(MASKHWORD, tmp);
 476
 477        tmp = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS_1);
 478        coex_stat->lo_pri_tx = FIELD_GET(MASKLWORD, tmp);
 479        coex_stat->lo_pri_rx = FIELD_GET(MASKHWORD, tmp);
 480
 481        rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL,
 482                   BIT_R_GRANTALL_WLMASK | BIT_STATIS_BT_EN);
 483
 484        rtw_dbg(rtwdev, RTW_DBG_COEX,
 485                "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n",
 486                coex_stat->hi_pri_rx, coex_stat->hi_pri_tx,
 487                coex_stat->lo_pri_rx, coex_stat->lo_pri_tx);
 488}
 489
 490static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
 491{
 492        struct rtw_chip_info *chip = rtwdev->chip;
 493        struct rtw_coex *coex = &rtwdev->coex;
 494        struct rtw_coex_stat *coex_stat = &coex->stat;
 495        struct rtw_coex_dm *coex_dm = &coex->dm;
 496        bool bt_disabled = false;
 497        u16 score_board;
 498
 499        if (chip->scbd_support) {
 500                score_board = rtw_coex_read_scbd(rtwdev);
 501                bt_disabled = !(score_board & COEX_SCBD_ONOFF);
 502        }
 503
 504        if (coex_stat->bt_disabled != bt_disabled) {
 505                rtw_dbg(rtwdev, RTW_DBG_COEX,
 506                        "[BTCoex], BT state changed (%d) -> (%d)\n",
 507                        coex_stat->bt_disabled, bt_disabled);
 508
 509                coex_stat->bt_disabled = bt_disabled;
 510                coex_stat->bt_ble_scan_type = 0;
 511                coex_dm->cur_bt_lna_lvl = 0;
 512
 513                if (!coex_stat->bt_disabled) {
 514                        coex_stat->bt_reenable = true;
 515                        ieee80211_queue_delayed_work(rtwdev->hw,
 516                                                     &coex->bt_reenable_work,
 517                                                     15 * HZ);
 518                } else {
 519                        coex_stat->bt_mailbox_reply = false;
 520                        coex_stat->bt_reenable = false;
 521                }
 522        }
 523}
 524
 525static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason)
 526{
 527        struct rtw_coex *coex = &rtwdev->coex;
 528        struct rtw_coex_stat *coex_stat = &coex->stat;
 529        struct rtw_coex_dm *coex_dm = &coex->dm;
 530        struct rtw_chip_info *chip = rtwdev->chip;
 531        struct rtw_traffic_stats *stats = &rtwdev->stats;
 532        bool is_5G = false;
 533        bool wl_busy = false;
 534        bool scan = false, link = false;
 535        int i;
 536        u8 rssi_state;
 537        u8 rssi_step;
 538        u8 rssi;
 539
 540        scan = test_bit(RTW_FLAG_SCANNING, rtwdev->flags);
 541        coex_stat->wl_connected = !!rtwdev->sta_cnt;
 542
 543        wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
 544        if (wl_busy != coex_stat->wl_gl_busy) {
 545                if (wl_busy)
 546                        coex_stat->wl_gl_busy = true;
 547                else
 548                        ieee80211_queue_delayed_work(rtwdev->hw,
 549                                                     &coex->wl_remain_work,
 550                                                     12 * HZ);
 551        }
 552
 553        if (stats->tx_throughput > stats->rx_throughput)
 554                coex_stat->wl_tput_dir = COEX_WL_TPUT_TX;
 555        else
 556                coex_stat->wl_tput_dir = COEX_WL_TPUT_RX;
 557
 558        if (scan || link || reason == COEX_RSN_2GCONSTART ||
 559            reason == COEX_RSN_2GSCANSTART || reason == COEX_RSN_2GSWITCHBAND)
 560                coex_stat->wl_linkscan_proc = true;
 561        else
 562                coex_stat->wl_linkscan_proc = false;
 563
 564        rtw_coex_wl_noisy_detect(rtwdev);
 565
 566        for (i = 0; i < 4; i++) {
 567                rssi_state = coex_dm->wl_rssi_state[i];
 568                rssi_step = chip->wl_rssi_step[i];
 569                rssi = rtwdev->dm_info.min_rssi;
 570                rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
 571                                                      rssi, rssi_step);
 572                coex_dm->wl_rssi_state[i] = rssi_state;
 573        }
 574
 575        if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 ||
 576            coex_stat->wl_hi_pri_task2 || coex_stat->wl_gl_busy)
 577                rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, true);
 578        else
 579                rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);
 580
 581        switch (reason) {
 582        case COEX_RSN_5GSCANSTART:
 583        case COEX_RSN_5GSWITCHBAND:
 584        case COEX_RSN_5GCONSTART:
 585
 586                is_5G = true;
 587                break;
 588        case COEX_RSN_2GSCANSTART:
 589        case COEX_RSN_2GSWITCHBAND:
 590        case COEX_RSN_2GCONSTART:
 591
 592                is_5G = false;
 593                break;
 594        default:
 595                if (rtwdev->hal.current_band_type == RTW_BAND_5G)
 596                        is_5G = true;
 597                else
 598                        is_5G = false;
 599                break;
 600        }
 601
 602        coex->under_5g = is_5G;
 603}
 604
 605static inline u8 *get_payload_from_coex_resp(struct sk_buff *resp)
 606{
 607        struct rtw_c2h_cmd *c2h;
 608        u32 pkt_offset;
 609
 610        pkt_offset = *((u32 *)resp->cb);
 611        c2h = (struct rtw_c2h_cmd *)(resp->data + pkt_offset);
 612
 613        return c2h->payload;
 614}
 615
 616void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb)
 617{
 618        struct rtw_coex *coex = &rtwdev->coex;
 619        u8 *payload = get_payload_from_coex_resp(skb);
 620
 621        if (payload[0] != COEX_RESP_ACK_BY_WL_FW) {
 622                dev_kfree_skb_any(skb);
 623                return;
 624        }
 625
 626        skb_queue_tail(&coex->queue, skb);
 627        wake_up(&coex->wait);
 628}
 629
 630static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,
 631                                             struct rtw_coex_info_req *req)
 632{
 633        struct rtw_coex *coex = &rtwdev->coex;
 634        struct sk_buff *skb_resp = NULL;
 635
 636        mutex_lock(&coex->mutex);
 637
 638        rtw_fw_query_bt_mp_info(rtwdev, req);
 639
 640        if (!wait_event_timeout(coex->wait, !skb_queue_empty(&coex->queue),
 641                                COEX_REQUEST_TIMEOUT)) {
 642                rtw_err(rtwdev, "coex request time out\n");
 643                goto out;
 644        }
 645
 646        skb_resp = skb_dequeue(&coex->queue);
 647        if (!skb_resp) {
 648                rtw_err(rtwdev, "failed to get coex info response\n");
 649                goto out;
 650        }
 651
 652out:
 653        mutex_unlock(&coex->mutex);
 654        return skb_resp;
 655}
 656
 657static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type)
 658{
 659        struct rtw_coex_info_req req = {0};
 660        struct sk_buff *skb;
 661        u8 *payload;
 662
 663        req.op_code = BT_MP_INFO_OP_SCAN_TYPE;
 664        skb = rtw_coex_info_request(rtwdev, &req);
 665        if (!skb)
 666                return false;
 667
 668        payload = get_payload_from_coex_resp(skb);
 669        *scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload);
 670        dev_kfree_skb_any(skb);
 671        return true;
 672}
 673
 674static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev,
 675                                             u8 lna_constrain_level)
 676{
 677        struct rtw_coex_info_req req = {0};
 678        struct sk_buff *skb;
 679
 680        req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT;
 681        req.para1 = lna_constrain_level;
 682        skb = rtw_coex_info_request(rtwdev, &req);
 683        if (!skb)
 684                return false;
 685
 686        dev_kfree_skb_any(skb);
 687        return true;
 688}
 689
 690#define case_BTSTATUS(src) \
 691        case COEX_BTSTATUS_##src: return #src
 692
 693static const char *rtw_coex_get_bt_status_string(u8 bt_status)
 694{
 695        switch (bt_status) {
 696        case_BTSTATUS(NCON_IDLE);
 697        case_BTSTATUS(CON_IDLE);
 698        case_BTSTATUS(INQ_PAGE);
 699        case_BTSTATUS(ACL_BUSY);
 700        case_BTSTATUS(SCO_BUSY);
 701        case_BTSTATUS(ACL_SCO_BUSY);
 702        default:
 703                return "Unknown";
 704        }
 705}
 706
 707static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
 708{
 709        struct rtw_coex *coex = &rtwdev->coex;
 710        struct rtw_coex_stat *coex_stat = &coex->stat;
 711        struct rtw_coex_dm *coex_dm = &coex->dm;
 712        struct rtw_chip_info *chip = rtwdev->chip;
 713        u8 i;
 714        u8 rssi_state;
 715        u8 rssi_step;
 716        u8 rssi;
 717
 718        /* update wl/bt rssi by btinfo */
 719        for (i = 0; i < COEX_RSSI_STEP; i++) {
 720                rssi_state = coex_dm->bt_rssi_state[i];
 721                rssi_step = chip->bt_rssi_step[i];
 722                rssi = coex_stat->bt_rssi;
 723                rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state, rssi,
 724                                                      rssi_step);
 725                coex_dm->bt_rssi_state[i] = rssi_state;
 726        }
 727
 728        if (coex_stat->bt_ble_scan_en &&
 729            coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE] % 3 == 0) {
 730                u8 scan_type;
 731
 732                if (rtw_coex_get_bt_scan_type(rtwdev, &scan_type)) {
 733                        coex_stat->bt_ble_scan_type = scan_type;
 734                        if ((coex_stat->bt_ble_scan_type & 0x1) == 0x1)
 735                                coex_stat->bt_init_scan = true;
 736                        else
 737                                coex_stat->bt_init_scan = false;
 738                }
 739        }
 740
 741        coex_stat->bt_profile_num = 0;
 742
 743        /* set link exist status */
 744        if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {
 745                coex_stat->bt_link_exist = false;
 746                coex_stat->bt_pan_exist = false;
 747                coex_stat->bt_a2dp_exist = false;
 748                coex_stat->bt_hid_exist = false;
 749                coex_stat->bt_hfp_exist = false;
 750        } else {
 751                /* connection exists */
 752                coex_stat->bt_link_exist = true;
 753                if (coex_stat->bt_info_lb2 & COEX_INFO_FTP) {
 754                        coex_stat->bt_pan_exist = true;
 755                        coex_stat->bt_profile_num++;
 756                } else {
 757                        coex_stat->bt_pan_exist = false;
 758                }
 759
 760                if (coex_stat->bt_info_lb2 & COEX_INFO_A2DP) {
 761                        coex_stat->bt_a2dp_exist = true;
 762                        coex_stat->bt_profile_num++;
 763                } else {
 764                        coex_stat->bt_a2dp_exist = false;
 765                }
 766
 767                if (coex_stat->bt_info_lb2 & COEX_INFO_HID) {
 768                        coex_stat->bt_hid_exist = true;
 769                        coex_stat->bt_profile_num++;
 770                } else {
 771                        coex_stat->bt_hid_exist = false;
 772                }
 773
 774                if (coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) {
 775                        coex_stat->bt_hfp_exist = true;
 776                        coex_stat->bt_profile_num++;
 777                } else {
 778                        coex_stat->bt_hfp_exist = false;
 779                }
 780        }
 781
 782        if (coex_stat->bt_info_lb2 & COEX_INFO_INQ_PAGE) {
 783                coex_dm->bt_status = COEX_BTSTATUS_INQ_PAGE;
 784        } else if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {
 785                coex_dm->bt_status = COEX_BTSTATUS_NCON_IDLE;
 786                coex_stat->bt_multi_link_remain = false;
 787        } else if (coex_stat->bt_info_lb2 == COEX_INFO_CONNECTION) {
 788                coex_dm->bt_status = COEX_BTSTATUS_CON_IDLE;
 789        } else if ((coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) ||
 790                   (coex_stat->bt_info_lb2 & COEX_INFO_SCO_BUSY)) {
 791                if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY)
 792                        coex_dm->bt_status = COEX_BTSTATUS_ACL_SCO_BUSY;
 793                else
 794                        coex_dm->bt_status = COEX_BTSTATUS_SCO_BUSY;
 795        } else if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY) {
 796                coex_dm->bt_status = COEX_BTSTATUS_ACL_BUSY;
 797        } else {
 798                coex_dm->bt_status = COEX_BTSTATUS_MAX;
 799        }
 800
 801        coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE]++;
 802
 803        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(), %s!!!\n", __func__,
 804                rtw_coex_get_bt_status_string(coex_dm->bt_status));
 805}
 806
 807static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
 808{
 809        struct rtw_chip_info *chip = rtwdev->chip;
 810        struct rtw_efuse *efuse = &rtwdev->efuse;
 811        struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm;
 812        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
 813        u8 link = 0;
 814        u8 center_chan = 0;
 815        u8 bw;
 816        int i;
 817
 818        bw = rtwdev->hal.current_band_width;
 819
 820        if (type != COEX_MEDIA_DISCONNECT)
 821                center_chan = rtwdev->hal.current_channel;
 822
 823        if (center_chan == 0 ||
 824            (efuse->share_ant && center_chan <= 14 &&
 825             coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)) {
 826                link = 0;
 827                center_chan = 0;
 828                bw = 0;
 829        } else if (center_chan <= 14) {
 830                link = 0x1;
 831
 832                if (bw == RTW_CHANNEL_WIDTH_40)
 833                        bw = chip->bt_afh_span_bw40;
 834                else
 835                        bw = chip->bt_afh_span_bw20;
 836        } else if (chip->afh_5g_num > 1) {
 837                for (i = 0; i < chip->afh_5g_num; i++) {
 838                        if (center_chan == chip->afh_5g[i].wl_5g_ch) {
 839                                link = 0x3;
 840                                center_chan = chip->afh_5g[i].bt_skip_ch;
 841                                bw = chip->afh_5g[i].bt_skip_span;
 842                                break;
 843                        }
 844                }
 845        }
 846
 847        coex_dm->wl_ch_info[0] = link;
 848        coex_dm->wl_ch_info[1] = center_chan;
 849        coex_dm->wl_ch_info[2] = bw;
 850
 851        rtw_fw_wl_ch_info(rtwdev, link, center_chan, bw);
 852        rtw_dbg(rtwdev, RTW_DBG_COEX,
 853                "[BTCoex], %s: para[0:2] = 0x%x 0x%x 0x%x\n", __func__, link,
 854                center_chan, bw);
 855}
 856
 857static void rtw_coex_set_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl)
 858{
 859        struct rtw_coex *coex = &rtwdev->coex;
 860        struct rtw_coex_dm *coex_dm = &coex->dm;
 861
 862        if (bt_pwr_dec_lvl == coex_dm->cur_bt_pwr_lvl)
 863                return;
 864
 865        coex_dm->cur_bt_pwr_lvl = bt_pwr_dec_lvl;
 866
 867        rtw_fw_force_bt_tx_power(rtwdev, bt_pwr_dec_lvl);
 868}
 869
 870static void rtw_coex_set_bt_rx_gain(struct rtw_dev *rtwdev, u8 bt_lna_lvl)
 871{
 872        struct rtw_coex *coex = &rtwdev->coex;
 873        struct rtw_coex_dm *coex_dm = &coex->dm;
 874
 875        if (bt_lna_lvl == coex_dm->cur_bt_lna_lvl)
 876                return;
 877
 878        coex_dm->cur_bt_lna_lvl = bt_lna_lvl;
 879
 880        /* notify BT rx gain table changed */
 881        if (bt_lna_lvl < 7) {
 882                rtw_coex_set_lna_constrain_level(rtwdev, bt_lna_lvl);
 883                rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, true);
 884        } else {
 885                rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, false);
 886        }
 887        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): bt_rx_LNA_level = %d\n",
 888                __func__, bt_lna_lvl);
 889}
 890
 891static void rtw_coex_set_rf_para(struct rtw_dev *rtwdev,
 892                                 struct coex_rf_para para)
 893{
 894        struct rtw_coex *coex = &rtwdev->coex;
 895        struct rtw_coex_stat *coex_stat = &coex->stat;
 896        u8 offset = 0;
 897
 898        if (coex->freerun && coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] <= 5)
 899                offset = 3;
 900
 901        rtw_coex_set_wl_tx_power(rtwdev, para.wl_pwr_dec_lvl);
 902        rtw_coex_set_bt_tx_power(rtwdev, para.bt_pwr_dec_lvl + offset);
 903        rtw_coex_set_wl_rx_gain(rtwdev, para.wl_low_gain_en);
 904        rtw_coex_set_bt_rx_gain(rtwdev, para.bt_lna_lvl);
 905}
 906
 907u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr)
 908{
 909        u32 val;
 910
 911        if (!ltecoex_read_reg(rtwdev, addr, &val)) {
 912                rtw_err(rtwdev, "failed to read indirect register\n");
 913                return 0;
 914        }
 915
 916        return val;
 917}
 918EXPORT_SYMBOL(rtw_coex_read_indirect_reg);
 919
 920void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr,
 921                                 u32 mask, u32 val)
 922{
 923        u32 shift = __ffs(mask);
 924        u32 tmp;
 925
 926        tmp = rtw_coex_read_indirect_reg(rtwdev, addr);
 927        tmp = (tmp & (~mask)) | ((val << shift) & mask);
 928
 929        if (!ltecoex_reg_write(rtwdev, addr, tmp))
 930                rtw_err(rtwdev, "failed to write indirect register\n");
 931}
 932EXPORT_SYMBOL(rtw_coex_write_indirect_reg);
 933
 934static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control)
 935{
 936        struct rtw_chip_info *chip = rtwdev->chip;
 937        const struct rtw_hw_reg *btg_reg = chip->btg_reg;
 938
 939        if (wifi_control) {
 940                rtw_write8_set(rtwdev, REG_SYS_SDIO_CTRL + 3,
 941                               BIT_LTE_MUX_CTRL_PATH >> 24);
 942                if (btg_reg)
 943                        rtw_write8_set(rtwdev, btg_reg->addr, btg_reg->mask);
 944        } else {
 945                rtw_write8_clr(rtwdev, REG_SYS_SDIO_CTRL + 3,
 946                               BIT_LTE_MUX_CTRL_PATH >> 24);
 947                if (btg_reg)
 948                        rtw_write8_clr(rtwdev, btg_reg->addr, btg_reg->mask);
 949        }
 950}
 951
 952static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state)
 953{
 954        rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0xc000, state);
 955        rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0c00, state);
 956}
 957
 958static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state)
 959{
 960        rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x3000, state);
 961        rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state);
 962}
 963
 964static void rtw_coex_mimo_ps(struct rtw_dev *rtwdev, bool force, bool state)
 965{
 966        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
 967
 968        if (!force && state == coex_stat->wl_mimo_ps)
 969                return;
 970
 971        coex_stat->wl_mimo_ps = state;
 972
 973        rtw_set_txrx_1ss(rtwdev, state);
 974
 975        rtw_coex_update_wl_ch_info(rtwdev, (u8)coex_stat->wl_connected);
 976
 977        rtw_dbg(rtwdev, RTW_DBG_COEX,
 978                "[BTCoex], %s(): state = %d\n", __func__, state);
 979}
 980
 981static void rtw_btc_wltoggle_table_a(struct rtw_dev *rtwdev, bool force,
 982                                     u8 table_case)
 983{
 984        struct rtw_chip_info *chip = rtwdev->chip;
 985        struct rtw_efuse *efuse = &rtwdev->efuse;
 986        u8 h2c_para[6] = {0};
 987        u32 table_wl = 0x5a5a5a5a;
 988
 989        h2c_para[0] = COEX_H2C69_TOGGLE_TABLE_A;
 990        /* no definition */
 991        h2c_para[1] = 0x1;
 992
 993        if (efuse->share_ant) {
 994                if (table_case < chip->table_sant_num)
 995                        table_wl = chip->table_sant[table_case].wl;
 996        } else {
 997                if (table_case < chip->table_nsant_num)
 998                        table_wl = chip->table_nsant[table_case].wl;
 999        }
1000
1001        /* tell WL FW WL slot toggle table-A*/
1002        h2c_para[2] = (u8)u32_get_bits(table_wl, GENMASK(7, 0));
1003        h2c_para[3] = (u8)u32_get_bits(table_wl, GENMASK(15, 8));
1004        h2c_para[4] = (u8)u32_get_bits(table_wl, GENMASK(23, 16));
1005        h2c_para[5] = (u8)u32_get_bits(table_wl, GENMASK(31, 24));
1006
1007        rtw_fw_bt_wifi_control(rtwdev, h2c_para[0], &h2c_para[1]);
1008
1009        rtw_dbg(rtwdev, RTW_DBG_COEX,
1010                "[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n",
1011                __func__, h2c_para[0], h2c_para[1], h2c_para[2],
1012                h2c_para[3], h2c_para[4], h2c_para[5]);
1013}
1014
1015#define COEX_WL_SLOT_TOGLLE 0x5a5a5aaa
1016static void rtw_btc_wltoggle_table_b(struct rtw_dev *rtwdev, bool force,
1017                                     u8 interval, u32 table)
1018{
1019        struct rtw_coex *coex = &rtwdev->coex;
1020        struct rtw_coex_stat *coex_stat = &coex->stat;
1021        u8 cur_h2c_para[6] = {0};
1022        u8 i;
1023
1024        cur_h2c_para[0] = COEX_H2C69_TOGGLE_TABLE_B;
1025        cur_h2c_para[1] = interval;
1026        cur_h2c_para[2] = (u8)u32_get_bits(table, GENMASK(7, 0));
1027        cur_h2c_para[3] = (u8)u32_get_bits(table, GENMASK(15, 8));
1028        cur_h2c_para[4] = (u8)u32_get_bits(table, GENMASK(23, 16));
1029        cur_h2c_para[5] = (u8)u32_get_bits(table, GENMASK(31, 24));
1030
1031        coex_stat->wl_toggle_interval = interval;
1032
1033        for (i = 0; i <= 5; i++)
1034                coex_stat->wl_toggle_para[i] = cur_h2c_para[i];
1035
1036        rtw_fw_bt_wifi_control(rtwdev, cur_h2c_para[0], &cur_h2c_para[1]);
1037
1038        rtw_dbg(rtwdev, RTW_DBG_COEX,
1039                "[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n",
1040                __func__, cur_h2c_para[0], cur_h2c_para[1], cur_h2c_para[2],
1041                cur_h2c_para[3], cur_h2c_para[4], cur_h2c_para[5]);
1042}
1043
1044static void rtw_coex_set_table(struct rtw_dev *rtwdev, bool force, u32 table0,
1045                               u32 table1)
1046{
1047#define DEF_BRK_TABLE_VAL 0xf0ffffff
1048        struct rtw_coex *coex = &rtwdev->coex;
1049        struct rtw_coex_dm *coex_dm = &coex->dm;
1050
1051        /* If last tdma is wl slot toggle, force write table*/
1052        if (!force && coex_dm->reason != COEX_RSN_LPS) {
1053                if (table0 == rtw_read32(rtwdev, REG_BT_COEX_TABLE0) &&
1054                    table1 == rtw_read32(rtwdev, REG_BT_COEX_TABLE1))
1055                        return;
1056        }
1057        rtw_write32(rtwdev, REG_BT_COEX_TABLE0, table0);
1058        rtw_write32(rtwdev, REG_BT_COEX_TABLE1, table1);
1059        rtw_write32(rtwdev, REG_BT_COEX_BRK_TABLE, DEF_BRK_TABLE_VAL);
1060
1061        rtw_dbg(rtwdev, RTW_DBG_COEX,
1062                "[BTCoex], %s(): 0x6c0 = %x, 0x6c4 = %x\n", __func__, table0,
1063                table1);
1064}
1065
1066static void rtw_coex_table(struct rtw_dev *rtwdev, bool force, u8 type)
1067{
1068        struct rtw_coex *coex = &rtwdev->coex;
1069        struct rtw_coex_dm *coex_dm = &coex->dm;
1070        struct rtw_chip_info *chip = rtwdev->chip;
1071        struct rtw_efuse *efuse = &rtwdev->efuse;
1072        struct rtw_coex_stat *coex_stat = &coex->stat;
1073
1074        coex_dm->cur_table = type;
1075
1076        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], Coex_Table - %d\n", type);
1077
1078        if (efuse->share_ant) {
1079                if (type < chip->table_sant_num)
1080                        rtw_coex_set_table(rtwdev, force,
1081                                           chip->table_sant[type].bt,
1082                                           chip->table_sant[type].wl);
1083        } else {
1084                type = type - 100;
1085                if (type < chip->table_nsant_num)
1086                        rtw_coex_set_table(rtwdev, force,
1087                                           chip->table_nsant[type].bt,
1088                                           chip->table_nsant[type].wl);
1089        }
1090        if (coex_stat->wl_slot_toggle_change)
1091                rtw_btc_wltoggle_table_a(rtwdev, true, type);
1092}
1093
1094static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable)
1095{
1096        struct rtw_coex *coex = &rtwdev->coex;
1097
1098        if (coex->manual_control || coex->stop_dm)
1099                return;
1100
1101        rtw_fw_bt_ignore_wlan_action(rtwdev, enable);
1102}
1103
1104static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type,
1105                                      u8 lps_val, u8 rpwm_val)
1106{
1107        struct rtw_coex *coex = &rtwdev->coex;
1108        struct rtw_coex_stat *coex_stat = &coex->stat;
1109        u8 lps_mode = 0x0;
1110
1111        lps_mode = rtwdev->lps_conf.mode;
1112
1113        switch (ps_type) {
1114        case COEX_PS_WIFI_NATIVE:
1115                /* recover to original 32k low power setting */
1116                coex_stat->wl_force_lps_ctrl = false;
1117                rtw_dbg(rtwdev, RTW_DBG_COEX,
1118                        "[BTCoex], %s(): COEX_PS_WIFI_NATIVE\n", __func__);
1119                rtw_leave_lps(rtwdev);
1120                break;
1121        case COEX_PS_LPS_OFF:
1122                coex_stat->wl_force_lps_ctrl = true;
1123                if (lps_mode)
1124                        rtw_fw_coex_tdma_type(rtwdev, 0, 0, 0, 0, 0);
1125
1126                rtw_leave_lps(rtwdev);
1127                rtw_dbg(rtwdev, RTW_DBG_COEX,
1128                        "[BTCoex], %s(): COEX_PS_LPS_OFF\n", __func__);
1129                break;
1130        default:
1131                break;
1132        }
1133}
1134
1135static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
1136                              u8 byte3, u8 byte4, u8 byte5)
1137{
1138        struct rtw_coex *coex = &rtwdev->coex;
1139        struct rtw_coex_dm *coex_dm = &coex->dm;
1140        struct rtw_chip_info *chip = rtwdev->chip;
1141        struct rtw_coex_stat *coex_stat = &coex->stat;
1142        u8 ps_type = COEX_PS_WIFI_NATIVE;
1143        bool ap_enable = false;
1144
1145        if (ap_enable && (byte1 & BIT(4) && !(byte1 & BIT(5)))) {
1146                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): AP mode\n",
1147                        __func__);
1148
1149                byte1 &= ~BIT(4);
1150                byte1 |= BIT(5);
1151
1152                byte5 |= BIT(5);
1153                byte5 &= ~BIT(6);
1154
1155                ps_type = COEX_PS_WIFI_NATIVE;
1156                rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
1157        } else if ((byte1 & BIT(4) && !(byte1 & BIT(5))) ||
1158                   coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
1159                rtw_dbg(rtwdev, RTW_DBG_COEX,
1160                        "[BTCoex], %s(): Force LPS (byte1 = 0x%x)\n", __func__,
1161                        byte1);
1162
1163                if (chip->pstdma_type == COEX_PSTDMA_FORCE_LPSOFF)
1164                        ps_type = COEX_PS_LPS_OFF;
1165                else
1166                        ps_type = COEX_PS_LPS_ON;
1167                rtw_coex_power_save_state(rtwdev, ps_type, 0x50, 0x4);
1168        } else {
1169                rtw_dbg(rtwdev, RTW_DBG_COEX,
1170                        "[BTCoex], %s(): native power save (byte1 = 0x%x)\n",
1171                        __func__, byte1);
1172
1173                ps_type = COEX_PS_WIFI_NATIVE;
1174                rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
1175        }
1176
1177        coex_dm->ps_tdma_para[0] = byte1;
1178        coex_dm->ps_tdma_para[1] = byte2;
1179        coex_dm->ps_tdma_para[2] = byte3;
1180        coex_dm->ps_tdma_para[3] = byte4;
1181        coex_dm->ps_tdma_para[4] = byte5;
1182
1183        rtw_fw_coex_tdma_type(rtwdev, byte1, byte2, byte3, byte4, byte5);
1184
1185        if (byte1 & BIT(2)) {
1186                coex_stat->wl_slot_toggle = true;
1187                coex_stat->wl_slot_toggle_change = false;
1188        } else {
1189                coex_stat->wl_slot_toggle_change = coex_stat->wl_slot_toggle;
1190                coex_stat->wl_slot_toggle = false;
1191        }
1192}
1193
1194static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)
1195{
1196        struct rtw_coex *coex = &rtwdev->coex;
1197        struct rtw_coex_dm *coex_dm = &coex->dm;
1198        struct rtw_coex_stat *coex_stat = &coex->stat;
1199        struct rtw_chip_info *chip = rtwdev->chip;
1200        struct rtw_efuse *efuse = &rtwdev->efuse;
1201        u8 n, type;
1202        bool turn_on;
1203        bool wl_busy = false;
1204
1205        if (tcase & TDMA_4SLOT) /* 4-slot (50ms) mode */
1206                rtw_coex_tdma_timer_base(rtwdev, TDMA_TIMER_TYPE_4SLOT);
1207        else
1208                rtw_coex_tdma_timer_base(rtwdev, TDMA_TIMER_TYPE_2SLOT);
1209
1210        type = (u8)(tcase & 0xff);
1211
1212        turn_on = (type == 0 || type == 100) ? false : true;
1213
1214        if (!force && turn_on == coex_dm->cur_ps_tdma_on &&
1215            type == coex_dm->cur_ps_tdma) {
1216                rtw_dbg(rtwdev, RTW_DBG_COEX,
1217                        "[BTCoex], Skip TDMA because no change TDMA(%s, %d)\n",
1218                        (coex_dm->cur_ps_tdma_on ? "on" : "off"),
1219                        coex_dm->cur_ps_tdma);
1220
1221                return;
1222        }
1223        wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
1224
1225        if ((coex_stat->bt_a2dp_exist &&
1226             (coex_stat->bt_inq_remain || coex_stat->bt_multi_link)) ||
1227            !wl_busy)
1228                rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, false);
1229        else
1230                rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true);
1231
1232        /* update pre state */
1233        coex_dm->cur_ps_tdma_on = turn_on;
1234        coex_dm->cur_ps_tdma = type;
1235
1236        if (efuse->share_ant) {
1237                if (type < chip->tdma_sant_num)
1238                        rtw_coex_set_tdma(rtwdev,
1239                                          chip->tdma_sant[type].para[0],
1240                                          chip->tdma_sant[type].para[1],
1241                                          chip->tdma_sant[type].para[2],
1242                                          chip->tdma_sant[type].para[3],
1243                                          chip->tdma_sant[type].para[4]);
1244        } else {
1245                n = type - 100;
1246                if (n < chip->tdma_nsant_num)
1247                        rtw_coex_set_tdma(rtwdev,
1248                                          chip->tdma_nsant[n].para[0],
1249                                          chip->tdma_nsant[n].para[1],
1250                                          chip->tdma_nsant[n].para[2],
1251                                          chip->tdma_nsant[n].para[3],
1252                                          chip->tdma_nsant[n].para[4]);
1253        }
1254
1255
1256        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], coex tdma type(%s, %d)\n",
1257                turn_on ? "on" : "off", type);
1258}
1259
1260static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
1261{
1262        struct rtw_coex *coex = &rtwdev->coex;
1263        struct rtw_coex_stat *coex_stat = &coex->stat;
1264        struct rtw_coex_rfe *coex_rfe = &coex->rfe;
1265        struct rtw_coex_dm *coex_dm = &coex->dm;
1266        u8 ctrl_type = COEX_SWITCH_CTRL_MAX;
1267        u8 pos_type = COEX_SWITCH_TO_MAX;
1268
1269        if (!force && coex_dm->cur_ant_pos_type == phase)
1270                return;
1271
1272        coex_dm->cur_ant_pos_type = phase;
1273
1274        /* avoid switch coex_ctrl_owner during BT IQK */
1275        rtw_coex_check_rfk(rtwdev);
1276
1277        rtw_dbg(rtwdev, RTW_DBG_COEX,
1278                "[BTCoex],  coex_stat->bt_disabled = 0x%x\n",
1279                coex_stat->bt_disabled);
1280
1281        switch (phase) {
1282        case COEX_SET_ANT_POWERON:
1283                rtw_dbg(rtwdev, RTW_DBG_COEX,
1284                        "[BTCoex], %s() - PHASE_COEX_POWERON\n", __func__);
1285                /* set path control owner to BT at power-on */
1286                if (coex_stat->bt_disabled)
1287                        rtw_coex_coex_ctrl_owner(rtwdev, true);
1288                else
1289                        rtw_coex_coex_ctrl_owner(rtwdev, false);
1290
1291                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1292                pos_type = COEX_SWITCH_TO_BT;
1293                break;
1294        case COEX_SET_ANT_INIT:
1295                rtw_dbg(rtwdev, RTW_DBG_COEX,
1296                        "[BTCoex], %s() - PHASE_COEX_INIT\n", __func__);
1297                if (coex_stat->bt_disabled) {
1298                        /* set GNT_BT to SW low */
1299                        rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);
1300
1301                        /* set GNT_WL to SW high */
1302                        rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
1303                } else {
1304                        /* set GNT_BT to SW high */
1305                        rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
1306
1307                        /* set GNT_WL to SW low */
1308                        rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_LOW);
1309                }
1310
1311                /* set path control owner to wl at initial step */
1312                rtw_coex_coex_ctrl_owner(rtwdev, true);
1313
1314                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1315                pos_type = COEX_SWITCH_TO_BT;
1316                break;
1317        case COEX_SET_ANT_WONLY:
1318                rtw_dbg(rtwdev, RTW_DBG_COEX,
1319                        "[BTCoex], %s() - PHASE_WLANONLY_INIT\n", __func__);
1320                /* set GNT_BT to SW Low */
1321                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);
1322
1323                /* set GNT_WL to SW high */
1324                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
1325
1326                /* set path control owner to wl at initial step */
1327                rtw_coex_coex_ctrl_owner(rtwdev, true);
1328
1329                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1330                pos_type = COEX_SWITCH_TO_WLG;
1331                break;
1332        case COEX_SET_ANT_WOFF:
1333                rtw_dbg(rtwdev, RTW_DBG_COEX,
1334                        "[BTCoex], %s() - PHASE_WLAN_OFF\n", __func__);
1335                /* set path control owner to BT */
1336                rtw_coex_coex_ctrl_owner(rtwdev, false);
1337
1338                ctrl_type = COEX_SWITCH_CTRL_BY_BT;
1339                pos_type = COEX_SWITCH_TO_NOCARE;
1340                break;
1341        case COEX_SET_ANT_2G:
1342                rtw_dbg(rtwdev, RTW_DBG_COEX,
1343                        "[BTCoex], %s() - PHASE_2G_RUNTIME\n", __func__);
1344                /* set GNT_BT to PTA */
1345                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
1346
1347                /* set GNT_WL to PTA */
1348                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);
1349
1350                /* set path control owner to wl at runtime step */
1351                rtw_coex_coex_ctrl_owner(rtwdev, true);
1352
1353                ctrl_type = COEX_SWITCH_CTRL_BY_PTA;
1354                pos_type = COEX_SWITCH_TO_NOCARE;
1355                break;
1356        case COEX_SET_ANT_5G:
1357                rtw_dbg(rtwdev, RTW_DBG_COEX,
1358                        "[BTCoex], %s() - PHASE_5G_RUNTIME\n", __func__);
1359
1360                /* set GNT_BT to HW PTA */
1361                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
1362
1363                /* set GNT_WL to SW high */
1364                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
1365
1366                /* set path control owner to wl at runtime step */
1367                rtw_coex_coex_ctrl_owner(rtwdev, true);
1368
1369                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1370                pos_type = COEX_SWITCH_TO_WLA;
1371                break;
1372        case COEX_SET_ANT_2G_FREERUN:
1373                rtw_dbg(rtwdev, RTW_DBG_COEX,
1374                        "[BTCoex], %s() - PHASE_2G_FREERUN\n", __func__);
1375
1376                /* set GNT_BT to HW PTA */
1377                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
1378
1379                /* Set GNT_WL to SW high */
1380                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
1381
1382                /* set path control owner to wl at runtime step */
1383                rtw_coex_coex_ctrl_owner(rtwdev, true);
1384
1385                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1386                pos_type = COEX_SWITCH_TO_WLG_BT;
1387                break;
1388        case COEX_SET_ANT_2G_WLBT:
1389                rtw_dbg(rtwdev, RTW_DBG_COEX,
1390                        "[BTCoex], %s() - PHASE_2G_WLBT\n", __func__);
1391                /* set GNT_BT to HW PTA */
1392                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
1393
1394                /* Set GNT_WL to HW PTA */
1395                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);
1396
1397                /* set path control owner to wl at runtime step */
1398                rtw_coex_coex_ctrl_owner(rtwdev, true);
1399
1400                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1401                pos_type = COEX_SWITCH_TO_WLG_BT;
1402                break;
1403        default:
1404                WARN(1, "unknown phase when setting antenna path\n");
1405                return;
1406        }
1407
1408        if (ctrl_type < COEX_SWITCH_CTRL_MAX && pos_type < COEX_SWITCH_TO_MAX &&
1409            coex_rfe->ant_switch_exist)
1410                rtw_coex_set_ant_switch(rtwdev, ctrl_type, pos_type);
1411}
1412
1413#define case_ALGO(src) \
1414        case COEX_ALGO_##src: return #src
1415
1416static const char *rtw_coex_get_algo_string(u8 algo)
1417{
1418        switch (algo) {
1419        case_ALGO(NOPROFILE);
1420        case_ALGO(HFP);
1421        case_ALGO(HID);
1422        case_ALGO(A2DP);
1423        case_ALGO(PAN);
1424        case_ALGO(A2DP_HID);
1425        case_ALGO(A2DP_PAN);
1426        case_ALGO(PAN_HID);
1427        case_ALGO(A2DP_PAN_HID);
1428        default:
1429                return "Unknown";
1430        }
1431}
1432
1433#define case_BT_PROFILE(src) \
1434        case BPM_##src: return #src
1435
1436static const char *rtw_coex_get_bt_profile_string(u8 bt_profile)
1437{
1438        switch (bt_profile) {
1439        case_BT_PROFILE(NOPROFILE);
1440        case_BT_PROFILE(HFP);
1441        case_BT_PROFILE(HID);
1442        case_BT_PROFILE(A2DP);
1443        case_BT_PROFILE(PAN);
1444        case_BT_PROFILE(HID_HFP);
1445        case_BT_PROFILE(A2DP_HFP);
1446        case_BT_PROFILE(A2DP_HID);
1447        case_BT_PROFILE(A2DP_HID_HFP);
1448        case_BT_PROFILE(PAN_HFP);
1449        case_BT_PROFILE(PAN_HID);
1450        case_BT_PROFILE(PAN_HID_HFP);
1451        case_BT_PROFILE(PAN_A2DP);
1452        case_BT_PROFILE(PAN_A2DP_HFP);
1453        case_BT_PROFILE(PAN_A2DP_HID);
1454        case_BT_PROFILE(PAN_A2DP_HID_HFP);
1455        default:
1456                return "Unknown";
1457        }
1458}
1459
1460static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev)
1461{
1462        struct rtw_coex *coex = &rtwdev->coex;
1463        struct rtw_coex_stat *coex_stat = &coex->stat;
1464        u8 algorithm = COEX_ALGO_NOPROFILE;
1465        u8 profile_map = 0;
1466
1467        if (coex_stat->bt_hfp_exist)
1468                profile_map |= BPM_HFP;
1469        if (coex_stat->bt_hid_exist)
1470                profile_map |= BPM_HID;
1471        if (coex_stat->bt_a2dp_exist)
1472                profile_map |= BPM_A2DP;
1473        if (coex_stat->bt_pan_exist)
1474                profile_map |= BPM_PAN;
1475
1476        switch (profile_map) {
1477        case BPM_HFP:
1478                algorithm = COEX_ALGO_HFP;
1479                break;
1480        case           BPM_HID:
1481        case BPM_HFP + BPM_HID:
1482                algorithm = COEX_ALGO_HID;
1483                break;
1484        case BPM_HFP           + BPM_A2DP:
1485        case           BPM_HID + BPM_A2DP:
1486        case BPM_HFP + BPM_HID + BPM_A2DP:
1487                algorithm = COEX_ALGO_A2DP_HID;
1488                break;
1489        case BPM_HFP                      + BPM_PAN:
1490        case           BPM_HID            + BPM_PAN:
1491        case BPM_HFP + BPM_HID            + BPM_PAN:
1492                algorithm = COEX_ALGO_PAN_HID;
1493                break;
1494        case BPM_HFP           + BPM_A2DP + BPM_PAN:
1495        case           BPM_HID + BPM_A2DP + BPM_PAN:
1496        case BPM_HFP + BPM_HID + BPM_A2DP + BPM_PAN:
1497                algorithm = COEX_ALGO_A2DP_PAN_HID;
1498                break;
1499        case                                BPM_PAN:
1500                algorithm = COEX_ALGO_PAN;
1501                break;
1502        case                     BPM_A2DP + BPM_PAN:
1503                algorithm = COEX_ALGO_A2DP_PAN;
1504                break;
1505        case                     BPM_A2DP:
1506                if (coex_stat->bt_multi_link) {
1507                        if (coex_stat->bt_hid_pair_num > 0)
1508                                algorithm = COEX_ALGO_A2DP_HID;
1509                        else
1510                                algorithm = COEX_ALGO_A2DP_PAN;
1511                } else {
1512                        algorithm = COEX_ALGO_A2DP;
1513                }
1514                break;
1515        default:
1516                algorithm = COEX_ALGO_NOPROFILE;
1517                break;
1518        }
1519
1520        rtw_dbg(rtwdev, RTW_DBG_COEX,
1521                "[BTCoex], BT Profile = %s => Algorithm = %s\n",
1522                rtw_coex_get_bt_profile_string(profile_map),
1523                rtw_coex_get_algo_string(algorithm));
1524        return algorithm;
1525}
1526
1527static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev)
1528{
1529        struct rtw_efuse *efuse = &rtwdev->efuse;
1530        struct rtw_chip_info *chip = rtwdev->chip;
1531        u8 table_case, tdma_case;
1532
1533        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1534        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1535
1536        if (efuse->share_ant) {
1537                /* Shared-Ant */
1538                table_case = 2;
1539                tdma_case = 0;
1540        } else {
1541                /* Non-Shared-Ant */
1542                table_case = 100;
1543                tdma_case = 100;
1544        }
1545
1546        rtw_coex_table(rtwdev, false, table_case);
1547        rtw_coex_tdma(rtwdev, false, tdma_case);
1548}
1549
1550static void rtw_coex_action_freerun(struct rtw_dev *rtwdev)
1551{
1552        struct rtw_coex *coex = &rtwdev->coex;
1553        struct rtw_coex_stat *coex_stat = &coex->stat;
1554        struct rtw_coex_dm *coex_dm = &coex->dm;
1555        struct rtw_efuse *efuse = &rtwdev->efuse;
1556        struct rtw_chip_info *chip = rtwdev->chip;
1557        u8 level = 0;
1558        bool bt_afh_loss = true;
1559
1560        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1561
1562        if (efuse->share_ant)
1563                return;
1564
1565        coex->freerun = true;
1566
1567        if (bt_afh_loss)
1568                rtw_coex_update_wl_ch_info(rtwdev, COEX_MEDIA_CONNECT);
1569
1570        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);
1571
1572        rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
1573
1574        if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[0]))
1575                level = 2;
1576        else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
1577                level = 3;
1578        else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[2]))
1579                level = 4;
1580        else
1581                level = 5;
1582
1583        if (level > chip->wl_rf_para_num - 1)
1584                level = chip->wl_rf_para_num - 1;
1585
1586        if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
1587                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[level]);
1588        else
1589                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[level]);
1590
1591        rtw_coex_table(rtwdev, false, 100);
1592        rtw_coex_tdma(rtwdev, false, 100);
1593}
1594
1595static void rtw_coex_action_rf4ce(struct rtw_dev *rtwdev)
1596{
1597        struct rtw_efuse *efuse = &rtwdev->efuse;
1598        struct rtw_chip_info *chip = rtwdev->chip;
1599        u8 table_case, tdma_case;
1600
1601        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1602
1603        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1604        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1605
1606        if (efuse->share_ant) {
1607                /* Shared-Ant */
1608                table_case = 9;
1609                tdma_case = 16;
1610        } else {
1611                /* Non-Shared-Ant */
1612                table_case = 100;
1613                tdma_case = 100;
1614        }
1615
1616        rtw_coex_table(rtwdev, false, table_case);
1617        rtw_coex_tdma(rtwdev, false, tdma_case);
1618}
1619
1620static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev)
1621{
1622        struct rtw_efuse *efuse = &rtwdev->efuse;
1623        struct rtw_chip_info *chip = rtwdev->chip;
1624        u8 table_case, tdma_case;
1625
1626        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1627
1628        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1629        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1630
1631        if (efuse->share_ant) {
1632                /* Shared-Ant */
1633                table_case = 2;
1634                tdma_case = 0;
1635        } else {
1636                /* Non-Shared-Ant */
1637                table_case = 100;
1638                tdma_case = 100;
1639        }
1640
1641        rtw_coex_table(rtwdev, false, table_case);
1642        rtw_coex_tdma(rtwdev, false, tdma_case);
1643}
1644
1645static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)
1646{
1647        struct rtw_coex *coex = &rtwdev->coex;
1648        struct rtw_coex_stat *coex_stat = &coex->stat;
1649        struct rtw_efuse *efuse = &rtwdev->efuse;
1650        struct rtw_chip_info *chip = rtwdev->chip;
1651        u8 table_case, tdma_case;
1652        u32 slot_type = 0;
1653
1654        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1655
1656        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1657        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1658
1659        if (efuse->share_ant) { /* Shared-Ant */
1660                if (coex_stat->wl_gl_busy) {
1661                        table_case = 26;
1662                        if (coex_stat->bt_hid_exist &&
1663                            coex_stat->bt_profile_num == 1) {
1664                                slot_type = TDMA_4SLOT;
1665                                tdma_case = 20;
1666                        } else {
1667                                tdma_case = 20;
1668                        }
1669                } else {
1670                        table_case = 1;
1671                        tdma_case = 0;
1672                }
1673        } else { /* Non-Shared-Ant */
1674                if (coex_stat->wl_gl_busy)
1675                        table_case = 115;
1676                else
1677                        table_case = 100;
1678                tdma_case = 100;
1679        }
1680
1681        rtw_coex_table(rtwdev, false, table_case);
1682        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
1683}
1684
1685static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
1686{
1687        struct rtw_coex *coex = &rtwdev->coex;
1688        struct rtw_coex_stat *coex_stat = &coex->stat;
1689        struct rtw_coex_dm *coex_dm = &coex->dm;
1690        struct rtw_efuse *efuse = &rtwdev->efuse;
1691        struct rtw_chip_info *chip = rtwdev->chip;
1692        struct rtw_coex_rfe *coex_rfe = &coex->rfe;
1693        u8 table_case = 0xff, tdma_case = 0xff;
1694
1695        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1696        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1697
1698        if (coex_rfe->ant_switch_with_bt &&
1699            coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
1700                if (efuse->share_ant &&
1701                    COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
1702                    coex_stat->wl_gl_busy) {
1703                        table_case = 0;
1704                        tdma_case = 0;
1705                } else if (!efuse->share_ant) {
1706                        table_case = 100;
1707                        tdma_case = 100;
1708                }
1709        }
1710
1711        if (table_case != 0xff && tdma_case != 0xff) {
1712                rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);
1713                goto exit;
1714        }
1715
1716        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1717
1718        if (efuse->share_ant) {
1719                /* Shared-Ant */
1720                if (!coex_stat->wl_gl_busy) {
1721                        table_case = 10;
1722                        tdma_case = 3;
1723                } else if (coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
1724                        table_case = 11;
1725
1726                        if (coex_stat->lo_pri_rx + coex_stat->lo_pri_tx > 250)
1727                                tdma_case = 17;
1728                        else
1729                                tdma_case = 7;
1730                } else {
1731                        table_case = 12;
1732                        tdma_case = 7;
1733                }
1734        } else {
1735                /* Non-Shared-Ant */
1736                if (!coex_stat->wl_gl_busy) {
1737                        table_case = 112;
1738                        tdma_case = 104;
1739                } else if ((coex_stat->bt_ble_scan_type & 0x2) &&
1740                           coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
1741                        table_case = 114;
1742                        tdma_case = 103;
1743                } else {
1744                        table_case = 112;
1745                        tdma_case = 103;
1746                }
1747        }
1748
1749exit:
1750        rtw_coex_table(rtwdev, false, table_case);
1751        rtw_coex_tdma(rtwdev, false, tdma_case);
1752}
1753
1754static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
1755{
1756        struct rtw_coex *coex = &rtwdev->coex;
1757        struct rtw_coex_stat *coex_stat = &coex->stat;
1758        struct rtw_efuse *efuse = &rtwdev->efuse;
1759        struct rtw_chip_info *chip = rtwdev->chip;
1760        bool wl_hi_pri = false;
1761        u8 table_case, tdma_case;
1762        u32 slot_type = 0;
1763
1764        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1765        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1766        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1767
1768        if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 ||
1769            coex_stat->wl_hi_pri_task2)
1770                wl_hi_pri = true;
1771
1772        if (efuse->share_ant) {
1773                /* Shared-Ant */
1774                if (wl_hi_pri) {
1775                        rtw_dbg(rtwdev, RTW_DBG_COEX,
1776                                "[BTCoex], bt inq/page +  wifi hi-pri task\n");
1777                        table_case = 15;
1778
1779                        if (coex_stat->bt_profile_num > 0)
1780                                tdma_case = 10;
1781                        else if (coex_stat->wl_hi_pri_task1)
1782                                tdma_case = 6;
1783                        else if (!coex_stat->bt_page)
1784                                tdma_case = 8;
1785                        else
1786                                tdma_case = 9;
1787                } else if (coex_stat->wl_gl_busy) {
1788                        rtw_dbg(rtwdev, RTW_DBG_COEX,
1789                                "[BTCoex], bt inq/page + wifi busy\n");
1790                        if (coex_stat->bt_profile_num == 0) {
1791                                table_case = 12;
1792                                tdma_case = 18;
1793                        } else if (coex_stat->bt_profile_num == 1 &&
1794                                   !coex_stat->bt_a2dp_exist) {
1795                                slot_type = TDMA_4SLOT;
1796                                table_case = 12;
1797                                tdma_case = 20;
1798                        } else {
1799                                slot_type = TDMA_4SLOT;
1800                                table_case = 12;
1801                                tdma_case = 26;
1802                        }
1803                } else if (coex_stat->wl_connected) {
1804                        rtw_dbg(rtwdev, RTW_DBG_COEX,
1805                                "[BTCoex], bt inq/page + wifi connected\n");
1806                        table_case = 9;
1807                        tdma_case = 27;
1808                } else {
1809                        rtw_dbg(rtwdev, RTW_DBG_COEX,
1810                                "[BTCoex], bt inq/page + wifi not-connected\n");
1811                        table_case = 1;
1812                        tdma_case = 0;
1813                }
1814        } else {
1815                /* Non_Shared-Ant */
1816                if (wl_hi_pri) {
1817                        rtw_dbg(rtwdev, RTW_DBG_COEX,
1818                                "[BTCoex], bt inq/page +  wifi hi-pri task\n");
1819                        table_case = 114;
1820
1821                        if (coex_stat->bt_profile_num > 0)
1822                                tdma_case = 110;
1823                        else if (coex_stat->wl_hi_pri_task1)
1824                                tdma_case = 106;
1825                        else if (!coex_stat->bt_page)
1826                                tdma_case = 108;
1827                        else
1828                                tdma_case = 109;
1829                }  else if (coex_stat->wl_gl_busy) {
1830                        rtw_dbg(rtwdev, RTW_DBG_COEX,
1831                                "[BTCoex], bt inq/page + wifi busy\n");
1832                        table_case = 114;
1833                        tdma_case = 121;
1834                } else if (coex_stat->wl_connected) {
1835                        rtw_dbg(rtwdev, RTW_DBG_COEX,
1836                                "[BTCoex], bt inq/page +  wifi connected\n");
1837                        table_case = 101;
1838                        tdma_case = 100;
1839                } else {
1840                        rtw_dbg(rtwdev, RTW_DBG_COEX,
1841                                "[BTCoex], bt inq/page +  wifi not-connected\n");
1842                        table_case = 101;
1843                        tdma_case = 100;
1844                }
1845        }
1846
1847        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], wifi hi(%d), bt page(%d)\n",
1848                wl_hi_pri, coex_stat->bt_page);
1849
1850        rtw_coex_table(rtwdev, false, table_case);
1851        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
1852}
1853
1854static void rtw_coex_action_bt_game_hid(struct rtw_dev *rtwdev)
1855{
1856        struct rtw_coex *coex = &rtwdev->coex;
1857        struct rtw_coex_stat *coex_stat = &coex->stat;
1858        struct rtw_efuse *efuse = &rtwdev->efuse;
1859        struct rtw_coex_dm *coex_dm = &coex->dm;
1860        struct rtw_chip_info *chip = rtwdev->chip;
1861        u8 table_case, tdma_case;
1862
1863        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1864        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1865
1866        if (efuse->share_ant) {
1867                coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
1868                if (coex_stat->bt_whck_test)
1869                        table_case = 2;
1870                else if (coex_stat->wl_linkscan_proc || coex_stat->bt_hid_exist)
1871                        table_case = 33;
1872                else if (coex_stat->bt_setup_link || coex_stat->bt_inq_page)
1873                        table_case = 0;
1874                else if (coex_stat->bt_a2dp_exist)
1875                        table_case = 34;
1876                else
1877                        table_case = 33;
1878
1879                tdma_case = 0;
1880        } else {
1881                if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
1882                        tdma_case = 112;
1883                else
1884                        tdma_case = 113;
1885
1886                table_case = 121;
1887        }
1888
1889        if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
1890                if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
1891                        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[6]);
1892                else
1893                        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[5]);
1894        } else {
1895                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1896        }
1897
1898        rtw_coex_table(rtwdev, false, table_case);
1899        rtw_coex_tdma(rtwdev, false, tdma_case);
1900}
1901
1902static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
1903{
1904        struct rtw_coex *coex = &rtwdev->coex;
1905        struct rtw_coex_stat *coex_stat = &coex->stat;
1906        struct rtw_efuse *efuse = &rtwdev->efuse;
1907        struct rtw_chip_info *chip = rtwdev->chip;
1908        u8 table_case, tdma_case;
1909
1910        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1911        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1912        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1913
1914        if (efuse->share_ant) {
1915                /* Shared-Ant */
1916                table_case = 10;
1917                tdma_case = 5;
1918        } else {
1919                /* Non-Shared-Ant */
1920                if (coex_stat->bt_multi_link) {
1921                        table_case = 112;
1922                        tdma_case = 117;
1923                } else {
1924                        table_case = 105;
1925                        tdma_case = 100;
1926                }
1927        }
1928
1929        rtw_coex_table(rtwdev, false, table_case);
1930        rtw_coex_tdma(rtwdev, false, tdma_case);
1931}
1932
1933static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)
1934{
1935        struct rtw_coex *coex = &rtwdev->coex;
1936        struct rtw_coex_stat *coex_stat = &coex->stat;
1937        struct rtw_efuse *efuse = &rtwdev->efuse;
1938        struct rtw_chip_info *chip = rtwdev->chip;
1939        u8 table_case, tdma_case;
1940        u32 slot_type = 0;
1941        bool bt_multi_link_remain = false, is_toggle_table = false;
1942
1943        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
1944        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1945        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1946
1947        if (efuse->share_ant) {
1948                /* Shared-Ant */
1949                if (coex_stat->bt_ble_exist) {
1950                        /* RCU */
1951                        if (coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] > 5) {
1952                                table_case = 26;
1953                                tdma_case = 2;
1954                        } else {
1955                                table_case = 27;
1956                                tdma_case = 9;
1957                        }
1958                } else {
1959                        /* Legacy HID  */
1960                        if (coex_stat->bt_profile_num == 1 &&
1961                            (coex_stat->bt_multi_link ||
1962                            (coex_stat->lo_pri_rx +
1963                             coex_stat->lo_pri_tx > 360) ||
1964                             coex_stat->bt_slave ||
1965                             bt_multi_link_remain)) {
1966                                slot_type = TDMA_4SLOT;
1967                                table_case = 12;
1968                                tdma_case = 20;
1969                        } else if (coex_stat->bt_a2dp_active) {
1970                                table_case = 9;
1971                                tdma_case = 18;
1972                        } else if (coex_stat->bt_418_hid_exist &&
1973                                   coex_stat->wl_gl_busy) {
1974                                is_toggle_table = true;
1975                                slot_type = TDMA_4SLOT;
1976                                table_case = 9;
1977                                tdma_case = 24;
1978                        } else if (coex_stat->bt_ble_hid_exist &&
1979                                   coex_stat->wl_gl_busy) {
1980                                table_case = 32;
1981                                tdma_case = 9;
1982                        } else {
1983                                table_case = 9;
1984                                tdma_case = 9;
1985                        }
1986                }
1987        } else {
1988                /* Non-Shared-Ant */
1989                if (coex_stat->bt_ble_exist) {
1990                        /* BLE */
1991                        if (coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] > 5) {
1992                                table_case = 121;
1993                                tdma_case = 102;
1994                        } else {
1995                                table_case = 122;
1996                                tdma_case = 109;
1997                        }
1998                } else if (coex_stat->bt_a2dp_active) {
1999                        table_case = 113;
2000                        tdma_case = 118;
2001                } else {
2002                        table_case = 113;
2003                        tdma_case = 104;
2004                }
2005        }
2006
2007        rtw_coex_table(rtwdev, false, table_case);
2008        if (is_toggle_table) {
2009                rtw_btc_wltoggle_table_a(rtwdev, true, table_case);
2010                rtw_btc_wltoggle_table_b(rtwdev, false, 1, COEX_WL_SLOT_TOGLLE);
2011        }
2012
2013        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
2014}
2015
2016static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)
2017{
2018        struct rtw_coex *coex = &rtwdev->coex;
2019        struct rtw_coex_stat *coex_stat = &coex->stat;
2020        struct rtw_coex_dm *coex_dm = &coex->dm;
2021        struct rtw_efuse *efuse = &rtwdev->efuse;
2022        struct rtw_chip_info *chip = rtwdev->chip;
2023        u8 table_case, tdma_case;
2024        u32 slot_type = 0;
2025
2026        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2027
2028        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2029        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2030
2031        slot_type = TDMA_4SLOT;
2032
2033        if (efuse->share_ant) {
2034                /* Shared-Ant */
2035                if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)
2036                        table_case = 12;
2037                else
2038                        table_case = 9;
2039
2040                if (coex_stat->wl_connecting || !coex_stat->wl_gl_busy)
2041                        tdma_case = 14;
2042                else
2043                        tdma_case = 13;
2044        } else {
2045                /* Non-Shared-Ant */
2046                table_case = 112;
2047
2048                if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
2049                        tdma_case = 112;
2050                else
2051                        tdma_case = 113;
2052        }
2053
2054        rtw_coex_table(rtwdev, false, table_case);
2055        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
2056}
2057
2058static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev)
2059{
2060        struct rtw_coex *coex = &rtwdev->coex;
2061        struct rtw_coex_stat *coex_stat = &coex->stat;
2062        struct rtw_efuse *efuse = &rtwdev->efuse;
2063        struct rtw_chip_info *chip = rtwdev->chip;
2064        u8 table_case, tdma_case;
2065        bool ap_enable = false;
2066
2067        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2068
2069        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2070        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2071
2072        if (efuse->share_ant) { /* Shared-Ant */
2073                if (ap_enable) {
2074                        table_case = 2;
2075                        tdma_case = 0;
2076                } else if (coex_stat->wl_gl_busy) {
2077                        table_case = 28;
2078                        tdma_case = 20;
2079                } else {
2080                        table_case = 28;
2081                        tdma_case = 26;
2082                }
2083        } else { /* Non-Shared-Ant */
2084                if (ap_enable) {
2085                        table_case = 100;
2086                        tdma_case = 100;
2087                } else {
2088                        table_case = 119;
2089                        tdma_case = 120;
2090                }
2091        }
2092
2093        rtw_coex_table(rtwdev, false, table_case);
2094        rtw_coex_tdma(rtwdev, false, tdma_case);
2095}
2096
2097static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)
2098{
2099        struct rtw_coex *coex = &rtwdev->coex;
2100        struct rtw_coex_stat *coex_stat = &coex->stat;
2101        struct rtw_efuse *efuse = &rtwdev->efuse;
2102        struct rtw_chip_info *chip = rtwdev->chip;
2103        u8 table_case, tdma_case;
2104
2105        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2106        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2107        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2108
2109        if (efuse->share_ant) {
2110                /* Shared-Ant */
2111                if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)
2112                        table_case = 14;
2113                else
2114                        table_case = 10;
2115
2116                if (coex_stat->wl_gl_busy)
2117                        tdma_case = 17;
2118                else
2119                        tdma_case = 20;
2120        } else {
2121                /* Non-Shared-Ant */
2122                table_case = 112;
2123
2124                if (coex_stat->wl_gl_busy)
2125                        tdma_case = 117;
2126                else
2127                        tdma_case = 119;
2128        }
2129
2130        rtw_coex_table(rtwdev, false, table_case);
2131        rtw_coex_tdma(rtwdev, false, tdma_case);
2132}
2133
2134static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev)
2135{
2136        struct rtw_coex *coex = &rtwdev->coex;
2137        struct rtw_coex_stat *coex_stat = &coex->stat;
2138        struct rtw_coex_dm *coex_dm = &coex->dm;
2139        struct rtw_efuse *efuse = &rtwdev->efuse;
2140        struct rtw_chip_info *chip = rtwdev->chip;
2141        u8 table_case, tdma_case, interval = 0;
2142        u32 slot_type = 0;
2143        bool is_toggle_table = false;
2144
2145        slot_type = TDMA_4SLOT;
2146
2147        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2148        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2149        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2150
2151        if (efuse->share_ant) {
2152                /* Shared-Ant */
2153                if (coex_stat->bt_ble_exist) {
2154                        table_case = 26; /* for RCU */
2155                } else if (coex_stat->bt_418_hid_exist) {
2156                        table_case = 9;
2157                        interval = 1;
2158                } else {
2159                        table_case = 9;
2160                }
2161
2162                if (coex_stat->wl_connecting || !coex_stat->wl_gl_busy) {
2163                        tdma_case = 14;
2164                } else if (coex_stat->bt_418_hid_exist) {
2165                        is_toggle_table = true;
2166                        tdma_case = 23;
2167                } else {
2168                        tdma_case = 13;
2169                }
2170        } else {
2171                /* Non-Shared-Ant */
2172                if (coex_stat->bt_ble_exist)
2173                        table_case = 121;
2174                else
2175                        table_case = 113;
2176
2177                if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
2178                        tdma_case = 112;
2179                else
2180                        tdma_case = 113;
2181        }
2182
2183        rtw_coex_table(rtwdev, false, table_case);
2184        if (is_toggle_table) {
2185                rtw_btc_wltoggle_table_a(rtwdev, true, table_case);
2186                rtw_btc_wltoggle_table_b(rtwdev, false, interval, COEX_WL_SLOT_TOGLLE);
2187        }
2188        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
2189}
2190
2191static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev)
2192{
2193        struct rtw_coex *coex = &rtwdev->coex;
2194        struct rtw_coex_stat *coex_stat = &coex->stat;
2195        struct rtw_efuse *efuse = &rtwdev->efuse;
2196        struct rtw_chip_info *chip = rtwdev->chip;
2197        u8 table_case, tdma_case;
2198        bool wl_cpt_test = false, bt_cpt_test = false;
2199
2200        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2201
2202        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2203        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2204        if (efuse->share_ant) {
2205                /* Shared-Ant */
2206                if (wl_cpt_test) {
2207                        if (coex_stat->wl_gl_busy) {
2208                                table_case = 20;
2209                                tdma_case = 17;
2210                        } else {
2211                                table_case = 10;
2212                                tdma_case = 15;
2213                        }
2214                } else if (bt_cpt_test) {
2215                        table_case = 26;
2216                        tdma_case = 26;
2217                } else {
2218                        if (coex_stat->wl_gl_busy &&
2219                            coex_stat->wl_noisy_level == 0)
2220                                table_case = 14;
2221                        else
2222                                table_case = 10;
2223
2224                        if (coex_stat->wl_gl_busy)
2225                                tdma_case = 15;
2226                        else
2227                                tdma_case = 20;
2228                }
2229        } else {
2230                /* Non-Shared-Ant */
2231                table_case = 112;
2232
2233                if (coex_stat->wl_gl_busy)
2234                        tdma_case = 115;
2235                else
2236                        tdma_case = 120;
2237        }
2238
2239        if (wl_cpt_test)
2240                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[1]);
2241        else
2242                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2243
2244        rtw_coex_table(rtwdev, false, table_case);
2245        rtw_coex_tdma(rtwdev, false, tdma_case);
2246}
2247
2248static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev)
2249{
2250        struct rtw_coex *coex = &rtwdev->coex;
2251        struct rtw_coex_stat *coex_stat = &coex->stat;
2252        struct rtw_efuse *efuse = &rtwdev->efuse;
2253        struct rtw_chip_info *chip = rtwdev->chip;
2254        u8 table_case, tdma_case;
2255
2256        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2257
2258        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2259        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2260
2261        if (efuse->share_ant) {
2262                /* Shared-Ant */
2263                table_case = 9;
2264
2265                if (coex_stat->wl_gl_busy)
2266                        tdma_case = 18;
2267                else
2268                        tdma_case = 19;
2269        } else {
2270                /* Non-Shared-Ant */
2271                table_case = 113;
2272
2273                if (coex_stat->wl_gl_busy)
2274                        tdma_case = 117;
2275                else
2276                        tdma_case = 119;
2277        }
2278
2279        rtw_coex_table(rtwdev, false, table_case);
2280        rtw_coex_tdma(rtwdev, false, tdma_case);
2281}
2282
2283static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)
2284{
2285        struct rtw_coex *coex = &rtwdev->coex;
2286        struct rtw_coex_stat *coex_stat = &coex->stat;
2287        struct rtw_efuse *efuse = &rtwdev->efuse;
2288        struct rtw_chip_info *chip = rtwdev->chip;
2289        u8 table_case, tdma_case;
2290
2291        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2292        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2293        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2294
2295        if (efuse->share_ant) {
2296                /* Shared-Ant */
2297                table_case = 10;
2298
2299                if (coex_stat->wl_gl_busy)
2300                        tdma_case = 15;
2301                else
2302                        tdma_case = 20;
2303        } else {
2304                /* Non-Shared-Ant */
2305                table_case = 113;
2306
2307                if (coex_stat->wl_gl_busy)
2308                        tdma_case = 115;
2309                else
2310                        tdma_case = 120;
2311        }
2312
2313        rtw_coex_table(rtwdev, false, table_case);
2314        rtw_coex_tdma(rtwdev, false, tdma_case);
2315}
2316
2317static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
2318{
2319        struct rtw_coex *coex = &rtwdev->coex;
2320        struct rtw_efuse *efuse = &rtwdev->efuse;
2321        struct rtw_chip_info *chip = rtwdev->chip;
2322        struct rtw_coex_stat *coex_stat = &coex->stat;
2323        u8 table_case, tdma_case;
2324
2325        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2326
2327        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2328        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2329
2330        rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
2331
2332        if (coex_stat->bt_game_hid_exist && coex_stat->wl_linkscan_proc)
2333                coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
2334
2335        if (efuse->share_ant) {
2336                /* Shared-Ant */
2337                table_case = 0;
2338                tdma_case = 0;
2339        } else {
2340                /* Non-Shared-Ant */
2341                table_case = 100;
2342                tdma_case = 100;
2343        }
2344
2345        rtw_coex_table(rtwdev, false, table_case);
2346        rtw_coex_tdma(rtwdev, false, tdma_case);
2347}
2348
2349static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev)
2350{
2351        struct rtw_efuse *efuse = &rtwdev->efuse;
2352        struct rtw_chip_info *chip = rtwdev->chip;
2353        u8 table_case, tdma_case;
2354
2355        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2356        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2357        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2358
2359        if (efuse->share_ant) {
2360                /* Shared-Ant */
2361                table_case = 2;
2362                tdma_case = 0;
2363        } else {
2364                /* Non-Shared-Ant */
2365                table_case = 100;
2366                tdma_case = 100;
2367        }
2368
2369        rtw_coex_table(rtwdev, false, table_case);
2370        rtw_coex_tdma(rtwdev, false, tdma_case);
2371}
2372
2373static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
2374{
2375        struct rtw_coex *coex = &rtwdev->coex;
2376        struct rtw_efuse *efuse = &rtwdev->efuse;
2377        struct rtw_chip_info *chip = rtwdev->chip;
2378        struct rtw_coex_stat *coex_stat = &coex->stat;
2379        u8 table_case, tdma_case;
2380
2381        if (coex->under_5g)
2382                return;
2383
2384        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2385
2386        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2387
2388        if (efuse->share_ant) {
2389                /* Shared-Ant */
2390                table_case = 28;
2391                tdma_case = 0;
2392        } else {
2393                /* Non-Shared-Ant */
2394                table_case = 100;
2395                tdma_case = 100;
2396        }
2397
2398        if (coex_stat->bt_game_hid_exist) {
2399                coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
2400                if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
2401                        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[6]);
2402                else
2403                        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[5]);
2404        } else {
2405                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2406        }
2407
2408        rtw_coex_table(rtwdev, false, table_case);
2409        rtw_coex_tdma(rtwdev, false, tdma_case);
2410}
2411
2412static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
2413{
2414        struct rtw_coex *coex = &rtwdev->coex;
2415        struct rtw_coex_stat *coex_stat = &coex->stat;
2416        struct rtw_efuse *efuse = &rtwdev->efuse;
2417        struct rtw_chip_info *chip = rtwdev->chip;
2418        u8 table_case, tdma_case;
2419        u32 slot_type = 0;
2420
2421        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2422        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2423        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2424
2425        if (efuse->share_ant) { /* Shared-Ant */
2426                if (coex_stat->bt_a2dp_exist) {
2427                        slot_type = TDMA_4SLOT;
2428                        tdma_case = 11;
2429                        if (coex_stat->wl_gl_busy)
2430                                table_case = 26;
2431                        else
2432                                table_case = 9;
2433                } else {
2434                        table_case = 9;
2435                        tdma_case = 7;
2436                }
2437        } else { /* Non-Shared-Ant */
2438                if (coex_stat->bt_a2dp_exist) {
2439                        slot_type = TDMA_4SLOT;
2440                        table_case = 112;
2441                        tdma_case = 111;
2442                } else {
2443                        table_case = 112;
2444                        tdma_case = 107;
2445                }
2446        }
2447
2448        rtw_coex_table(rtwdev, false, table_case);
2449        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
2450}
2451
2452static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev)
2453{
2454        struct rtw_efuse *efuse = &rtwdev->efuse;
2455        struct rtw_chip_info *chip = rtwdev->chip;
2456        u8 table_case, tdma_case;
2457
2458        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2459        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
2460        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
2461
2462        if (efuse->share_ant) {
2463                /* Shared-Ant */
2464                table_case = 1;
2465                tdma_case = 0;
2466        } else {
2467                /* Non-Shared-Ant */
2468                table_case = 100;
2469                tdma_case = 100;
2470        }
2471
2472        rtw_coex_table(rtwdev, false, table_case);
2473        rtw_coex_tdma(rtwdev, false, tdma_case);
2474}
2475
2476static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)
2477{
2478        struct rtw_coex *coex = &rtwdev->coex;
2479        struct rtw_coex_stat *coex_stat = &coex->stat;
2480        u8 algorithm;
2481
2482        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2483
2484        algorithm = rtw_coex_algorithm(rtwdev);
2485
2486        switch (algorithm) {
2487        case COEX_ALGO_HFP:
2488                rtw_coex_action_bt_hfp(rtwdev);
2489                break;
2490        case COEX_ALGO_HID:
2491                if (rtw_coex_freerun_check(rtwdev))
2492                        rtw_coex_action_freerun(rtwdev);
2493                else
2494                        rtw_coex_action_bt_hid(rtwdev);
2495                break;
2496        case COEX_ALGO_A2DP:
2497                if (rtw_coex_freerun_check(rtwdev))
2498                        rtw_coex_action_freerun(rtwdev);
2499                else if (coex_stat->bt_a2dp_sink)
2500                        rtw_coex_action_bt_a2dpsink(rtwdev);
2501                else
2502                        rtw_coex_action_bt_a2dp(rtwdev);
2503                break;
2504        case COEX_ALGO_PAN:
2505                rtw_coex_action_bt_pan(rtwdev);
2506                break;
2507        case COEX_ALGO_A2DP_HID:
2508                if (rtw_coex_freerun_check(rtwdev))
2509                        rtw_coex_action_freerun(rtwdev);
2510                else
2511                        rtw_coex_action_bt_a2dp_hid(rtwdev);
2512                break;
2513        case COEX_ALGO_A2DP_PAN:
2514                rtw_coex_action_bt_a2dp_pan(rtwdev);
2515                break;
2516        case COEX_ALGO_PAN_HID:
2517                rtw_coex_action_bt_pan_hid(rtwdev);
2518                break;
2519        case COEX_ALGO_A2DP_PAN_HID:
2520                rtw_coex_action_bt_a2dp_pan_hid(rtwdev);
2521                break;
2522        default:
2523        case COEX_ALGO_NOPROFILE:
2524                rtw_coex_action_bt_idle(rtwdev);
2525                break;
2526        }
2527}
2528
2529static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
2530{
2531        struct rtw_coex *coex = &rtwdev->coex;
2532        struct rtw_chip_info *chip = rtwdev->chip;
2533        struct rtw_coex_dm *coex_dm = &coex->dm;
2534        struct rtw_coex_stat *coex_stat = &coex->stat;
2535        bool rf4ce_en = false;
2536
2537        lockdep_assert_held(&rtwdev->mutex);
2538
2539        if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags))
2540                return;
2541
2542        coex_dm->reason = reason;
2543
2544        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): reason = %d\n", __func__,
2545                reason);
2546
2547        /* update wifi_link_info_ext variable */
2548        rtw_coex_update_wl_link_info(rtwdev, reason);
2549
2550        rtw_coex_monitor_bt_enable(rtwdev);
2551
2552        if (coex->manual_control) {
2553                rtw_dbg(rtwdev, RTW_DBG_COEX,
2554                        "[BTCoex], return for Manual CTRL!!\n");
2555                return;
2556        }
2557
2558        if (coex->stop_dm) {
2559                rtw_dbg(rtwdev, RTW_DBG_COEX,
2560                        "[BTCoex], return for Stop Coex DM!!\n");
2561                return;
2562        }
2563
2564        if (coex_stat->wl_under_ips) {
2565                rtw_dbg(rtwdev, RTW_DBG_COEX,
2566                        "[BTCoex], return for wifi is under IPS!!\n");
2567                return;
2568        }
2569
2570        if (coex->freeze && coex_dm->reason == COEX_RSN_BTINFO &&
2571            !coex_stat->bt_setup_link) {
2572                rtw_dbg(rtwdev, RTW_DBG_COEX,
2573                        "[BTCoex], return for coex_freeze!!\n");
2574                return;
2575        }
2576
2577        coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++;
2578        coex->freerun = false;
2579
2580        /* Pure-5G Coex Process */
2581        if (coex->under_5g) {
2582                coex_stat->wl_coex_mode = COEX_WLINK_5G;
2583                rtw_coex_action_wl_under5g(rtwdev);
2584                goto exit;
2585        }
2586
2587        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], WiFi is single-port 2G!!\n");
2588        coex_stat->wl_coex_mode = COEX_WLINK_2G1PORT;
2589
2590        if (coex_stat->bt_disabled) {
2591                if (coex_stat->wl_connected && rf4ce_en)
2592                        rtw_coex_action_rf4ce(rtwdev);
2593                else if (!coex_stat->wl_connected)
2594                        rtw_coex_action_wl_not_connected(rtwdev);
2595                else
2596                        rtw_coex_action_wl_only(rtwdev);
2597                goto exit;
2598        }
2599
2600        if (coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) {
2601                rtw_coex_action_wl_native_lps(rtwdev);
2602                goto exit;
2603        }
2604
2605        if (coex_stat->bt_game_hid_exist && coex_stat->wl_connected) {
2606                rtw_coex_action_bt_game_hid(rtwdev);
2607                goto exit;
2608        }
2609
2610        if (coex_stat->bt_whck_test) {
2611                rtw_coex_action_bt_whql_test(rtwdev);
2612                goto exit;
2613        }
2614
2615        if (coex_stat->bt_setup_link) {
2616                rtw_coex_action_bt_relink(rtwdev);
2617                goto exit;
2618        }
2619
2620        if (coex_stat->bt_inq_page) {
2621                rtw_coex_action_bt_inquiry(rtwdev);
2622                goto exit;
2623        }
2624
2625        if ((coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE ||
2626             coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE) &&
2627             coex_stat->wl_connected) {
2628                rtw_coex_action_bt_idle(rtwdev);
2629                goto exit;
2630        }
2631
2632        if (coex_stat->wl_linkscan_proc && !coex->freerun) {
2633                rtw_coex_action_wl_linkscan(rtwdev);
2634                goto exit;
2635        }
2636
2637        if (coex_stat->wl_connected) {
2638                rtw_coex_action_wl_connected(rtwdev);
2639                goto exit;
2640        } else {
2641                rtw_coex_action_wl_not_connected(rtwdev);
2642                goto exit;
2643        }
2644
2645exit:
2646
2647        if (chip->wl_mimo_ps_support) {
2648                if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
2649                        if (coex_dm->reason == COEX_RSN_2GMEDIA)
2650                                rtw_coex_mimo_ps(rtwdev, true, true);
2651                        else
2652                                rtw_coex_mimo_ps(rtwdev, false, true);
2653                } else {
2654                        rtw_coex_mimo_ps(rtwdev, false, false);
2655                }
2656        }
2657
2658        rtw_coex_gnt_workaround(rtwdev, false, coex_stat->wl_coex_mode);
2659        rtw_coex_limited_wl(rtwdev);
2660}
2661
2662static void rtw_coex_init_coex_var(struct rtw_dev *rtwdev)
2663{
2664        struct rtw_coex *coex = &rtwdev->coex;
2665        struct rtw_coex_stat *coex_stat = &coex->stat;
2666        struct rtw_coex_dm *coex_dm = &coex->dm;
2667        u8 i;
2668
2669        memset(coex_dm, 0, sizeof(*coex_dm));
2670        memset(coex_stat, 0, sizeof(*coex_stat));
2671
2672        for (i = 0; i < COEX_CNT_WL_MAX; i++)
2673                coex_stat->cnt_wl[i] = 0;
2674
2675        for (i = 0; i < COEX_CNT_BT_MAX; i++)
2676                coex_stat->cnt_bt[i] = 0;
2677
2678        for (i = 0; i < ARRAY_SIZE(coex_dm->bt_rssi_state); i++)
2679                coex_dm->bt_rssi_state[i] = COEX_RSSI_STATE_LOW;
2680
2681        for (i = 0; i < ARRAY_SIZE(coex_dm->wl_rssi_state); i++)
2682                coex_dm->wl_rssi_state[i] = COEX_RSSI_STATE_LOW;
2683
2684        coex_stat->wl_coex_mode = COEX_WLINK_MAX;
2685        coex_stat->wl_rx_rate = DESC_RATE5_5M;
2686        coex_stat->wl_rts_rx_rate = DESC_RATE5_5M;
2687}
2688
2689static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
2690{
2691        struct rtw_coex *coex = &rtwdev->coex;
2692        struct rtw_coex_stat *coex_stat = &coex->stat;
2693
2694        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2695
2696        rtw_coex_init_coex_var(rtwdev);
2697
2698        coex_stat->kt_ver = u8_get_bits(rtw_read8(rtwdev, 0xf1), GENMASK(7, 4));
2699
2700        rtw_coex_monitor_bt_enable(rtwdev);
2701        rtw_coex_wl_slot_extend(rtwdev, coex_stat->wl_slot_extend);
2702
2703        rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
2704
2705        rtw_coex_set_rfe_type(rtwdev);
2706        rtw_coex_set_init(rtwdev);
2707
2708        /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */
2709        rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_RSP, 1);
2710
2711        /* set Tx beacon = Hi-Pri */
2712        rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACON, 1);
2713
2714        /* set Tx beacon queue = Hi-Pri */
2715        rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACONQ, 1);
2716
2717        /* antenna config */
2718        if (coex->wl_rf_off) {
2719                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);
2720                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);
2721                coex->stop_dm = true;
2722
2723                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): RF Off\n",
2724                        __func__);
2725        } else if (wifi_only) {
2726                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WONLY);
2727                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF,
2728                                    true);
2729                coex->stop_dm = true;
2730        } else {
2731                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_INIT);
2732                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF,
2733                                    true);
2734                coex->stop_dm = false;
2735                coex->freeze = true;
2736        }
2737
2738        /* PTA parameter */
2739        rtw_coex_table(rtwdev, true, 1);
2740        rtw_coex_tdma(rtwdev, true, 0);
2741        rtw_coex_query_bt_info(rtwdev);
2742}
2743
2744void rtw_coex_power_on_setting(struct rtw_dev *rtwdev)
2745{
2746        struct rtw_coex *coex = &rtwdev->coex;
2747        u8 table_case = 1;
2748
2749        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
2750
2751        coex->stop_dm = true;
2752        coex->wl_rf_off = false;
2753
2754        /* enable BB, we can write 0x948 */
2755        rtw_write8_set(rtwdev, REG_SYS_FUNC_EN,
2756                       BIT_FEN_BB_GLB_RST | BIT_FEN_BB_RSTB);
2757
2758        rtw_coex_monitor_bt_enable(rtwdev);
2759        rtw_coex_set_rfe_type(rtwdev);
2760
2761        /* set antenna path to BT */
2762        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_POWERON);
2763
2764        rtw_coex_table(rtwdev, true, table_case);
2765        /* red x issue */
2766        rtw_write8(rtwdev, 0xff1a, 0x0);
2767        rtw_coex_set_gnt_debug(rtwdev);
2768}
2769
2770void rtw_coex_power_off_setting(struct rtw_dev *rtwdev)
2771{
2772        rtw_write16(rtwdev, REG_WIFI_BT_INFO, BIT_BT_INT_EN);
2773}
2774
2775void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
2776{
2777        __rtw_coex_init_hw_config(rtwdev, wifi_only);
2778}
2779
2780void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type)
2781{
2782        struct rtw_coex *coex = &rtwdev->coex;
2783        struct rtw_coex_stat *coex_stat = &coex->stat;
2784
2785        if (coex->manual_control || coex->stop_dm)
2786                return;
2787
2788        if (type == COEX_IPS_ENTER) {
2789                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], IPS ENTER notify\n");
2790
2791                coex_stat->wl_under_ips = true;
2792
2793                /* for lps off */
2794                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);
2795
2796                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);
2797                rtw_coex_action_coex_all_off(rtwdev);
2798        } else if (type == COEX_IPS_LEAVE) {
2799                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], IPS LEAVE notify\n");
2800
2801                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
2802                /* run init hw config (exclude wifi only) */
2803                __rtw_coex_init_hw_config(rtwdev, false);
2804
2805                coex_stat->wl_under_ips = false;
2806        }
2807}
2808
2809void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type)
2810{
2811        struct rtw_coex *coex = &rtwdev->coex;
2812        struct rtw_coex_stat *coex_stat = &coex->stat;
2813
2814        if (coex->manual_control || coex->stop_dm)
2815                return;
2816
2817        if (type == COEX_LPS_ENABLE) {
2818                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], LPS ENABLE notify\n");
2819
2820                coex_stat->wl_under_lps = true;
2821
2822                if (coex_stat->wl_force_lps_ctrl) {
2823                        /* for ps-tdma */
2824                        rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
2825                } else {
2826                        /* for native ps */
2827                        rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false);
2828                        rtw_coex_write_scbd(rtwdev, COEX_SCBD_WLBUSY, false);
2829
2830                        rtw_coex_run_coex(rtwdev, COEX_RSN_LPS);
2831                }
2832        } else if (type == COEX_LPS_DISABLE) {
2833                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], LPS DISABLE notify\n");
2834
2835                coex_stat->wl_under_lps = false;
2836
2837                /* for lps off */
2838                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
2839
2840                if (!coex_stat->wl_force_lps_ctrl)
2841                        rtw_coex_query_bt_info(rtwdev);
2842
2843                rtw_coex_run_coex(rtwdev, COEX_RSN_LPS);
2844        }
2845}
2846
2847void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type)
2848{
2849        struct rtw_coex *coex = &rtwdev->coex;
2850        struct rtw_coex_stat *coex_stat = &coex->stat;
2851
2852        if (coex->manual_control || coex->stop_dm)
2853                return;
2854
2855        coex->freeze = false;
2856        rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
2857
2858        if (type == COEX_SCAN_START_5G) {
2859                rtw_dbg(rtwdev, RTW_DBG_COEX,
2860                        "[BTCoex], SCAN START notify (5G)\n");
2861
2862                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2863                rtw_coex_run_coex(rtwdev, COEX_RSN_5GSCANSTART);
2864        } else if ((type == COEX_SCAN_START_2G) || (type == COEX_SCAN_START)) {
2865                rtw_dbg(rtwdev, RTW_DBG_COEX,
2866                        "[BTCoex], SCAN START notify (2G)\n");
2867
2868                coex_stat->wl_hi_pri_task2 = true;
2869
2870                /* Force antenna setup for no scan result issue */
2871                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
2872                rtw_coex_run_coex(rtwdev, COEX_RSN_2GSCANSTART);
2873        } else {
2874                coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] = 30; /* To do */
2875
2876                rtw_dbg(rtwdev, RTW_DBG_COEX,
2877                        "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n",
2878                        coex_stat->cnt_wl[COEX_CNT_WL_SCANAP]);
2879
2880                coex_stat->wl_hi_pri_task2 = false;
2881                rtw_coex_run_coex(rtwdev, COEX_RSN_SCANFINISH);
2882        }
2883}
2884
2885void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type)
2886{
2887        struct rtw_coex *coex = &rtwdev->coex;
2888
2889        if (coex->manual_control || coex->stop_dm)
2890                return;
2891
2892        if (type == COEX_SWITCH_TO_5G) {
2893                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): TO_5G\n",
2894                        __func__);
2895        } else if (type == COEX_SWITCH_TO_24G_NOFORSCAN) {
2896                rtw_dbg(rtwdev, RTW_DBG_COEX,
2897                        "[BTCoex], %s(): TO_24G_NOFORSCAN\n", __func__);
2898        } else {
2899                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): TO_2G\n",
2900                        __func__);
2901        }
2902
2903        if (type == COEX_SWITCH_TO_5G)
2904                rtw_coex_run_coex(rtwdev, COEX_RSN_5GSWITCHBAND);
2905        else if (type == COEX_SWITCH_TO_24G_NOFORSCAN)
2906                rtw_coex_run_coex(rtwdev, COEX_RSN_2GSWITCHBAND);
2907        else
2908                rtw_coex_scan_notify(rtwdev, COEX_SCAN_START_2G);
2909}
2910
2911void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type)
2912{
2913        struct rtw_coex *coex = &rtwdev->coex;
2914        struct rtw_coex_stat *coex_stat = &coex->stat;
2915
2916        if (coex->manual_control || coex->stop_dm)
2917                return;
2918
2919        rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
2920
2921        if (type == COEX_ASSOCIATE_5G_START) {
2922                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G start\n",
2923                        __func__);
2924
2925                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2926                rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONSTART);
2927        } else if (type == COEX_ASSOCIATE_5G_FINISH) {
2928                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G finish\n",
2929                        __func__);
2930
2931                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2932                rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONFINISH);
2933        } else if (type == COEX_ASSOCIATE_START) {
2934                coex_stat->wl_hi_pri_task1 = true;
2935                coex_stat->wl_connecting = true;
2936                coex_stat->cnt_wl[COEX_CNT_WL_CONNPKT] = 2;
2937                coex_stat->wl_connecting = true;
2938                ieee80211_queue_delayed_work(rtwdev->hw,
2939                                             &coex->wl_connecting_work, 2 * HZ);
2940
2941                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G start\n",
2942                        __func__);
2943                /* Force antenna setup for no scan result issue */
2944                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
2945
2946                rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONSTART);
2947
2948                /* To keep TDMA case during connect process,
2949                 * to avoid changed by Btinfo and runcoexmechanism
2950                 */
2951                coex->freeze = true;
2952                ieee80211_queue_delayed_work(rtwdev->hw, &coex->defreeze_work,
2953                                             5 * HZ);
2954        } else {
2955                coex_stat->wl_hi_pri_task1 = false;
2956                coex->freeze = false;
2957                coex_stat->wl_connecting = false;
2958
2959                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G finish\n",
2960                        __func__);
2961                rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONFINISH);
2962        }
2963}
2964
2965void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type)
2966{
2967        struct rtw_coex *coex = &rtwdev->coex;
2968        struct rtw_coex_stat *coex_stat = &coex->stat;
2969
2970        if (coex->manual_control || coex->stop_dm)
2971                return;
2972
2973        if (type == COEX_MEDIA_CONNECT_5G) {
2974                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G\n", __func__);
2975
2976                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
2977
2978                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2979                rtw_coex_run_coex(rtwdev, COEX_RSN_5GMEDIA);
2980        } else if (type == COEX_MEDIA_CONNECT) {
2981                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G\n", __func__);
2982
2983                coex_stat->wl_connecting = false;
2984
2985                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
2986
2987                /* Force antenna setup for no scan result issue */
2988                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
2989
2990                /* Set CCK Rx high Pri */
2991                rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 1);
2992                rtw_coex_run_coex(rtwdev, COEX_RSN_2GMEDIA);
2993        } else {
2994                rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): disconnect!!\n",
2995                        __func__);
2996                rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 0);
2997                rtw_coex_run_coex(rtwdev, COEX_RSN_MEDIADISCON);
2998        }
2999
3000        rtw_coex_update_wl_ch_info(rtwdev, type);
3001}
3002
3003void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
3004{
3005        struct rtw_coex *coex = &rtwdev->coex;
3006        struct rtw_coex_stat *coex_stat = &coex->stat;
3007        struct rtw_chip_info *chip = rtwdev->chip;
3008        struct rtw_coex_dm *coex_dm = &coex->dm;
3009        u32 bt_relink_time;
3010        u8 i, rsp_source = 0, type;
3011        bool inq_page = false;
3012
3013        rsp_source = buf[0] & 0xf;
3014        if (rsp_source >= COEX_BTINFO_SRC_MAX)
3015                return;
3016        coex_stat->cnt_bt_info_c2h[rsp_source]++;
3017
3018        if (rsp_source == COEX_BTINFO_SRC_BT_IQK) {
3019                coex_stat->bt_iqk_state = buf[1];
3020                if (coex_stat->bt_iqk_state == 0)
3021                        coex_stat->cnt_bt[COEX_CNT_BT_IQK]++;
3022                else if (coex_stat->bt_iqk_state == 2)
3023                        coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]++;
3024
3025                rtw_dbg(rtwdev, RTW_DBG_COEX,
3026                        "[BTCoex], BT IQK by bt_info, data0 = 0x%02x\n",
3027                        buf[1]);
3028
3029                return;
3030        }
3031
3032        if (rsp_source == COEX_BTINFO_SRC_BT_SCBD) {
3033                rtw_dbg(rtwdev, RTW_DBG_COEX,
3034                        "[BTCoex], BT Scoreboard change notify by WL FW c2h, 0xaa = 0x%02x, 0xab = 0x%02x\n",
3035                        buf[1], buf[2]);
3036
3037                rtw_coex_monitor_bt_enable(rtwdev);
3038                if (coex_stat->bt_disabled != coex_stat->bt_disabled_pre) {
3039                        coex_stat->bt_disabled_pre = coex_stat->bt_disabled;
3040                        rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
3041                }
3042                return;
3043        }
3044
3045        if (rsp_source == COEX_BTINFO_SRC_H2C60) {
3046                rtw_dbg(rtwdev, RTW_DBG_COEX,
3047                        "[BTCoex], H2C 0x60 content replied by WL FW: H2C_0x60 = [%02x %02x %02x %02x %02x]\n",
3048                        buf[1], buf[2], buf[3], buf[4], buf[5]);
3049
3050                for (i = 1; i <= COEX_WL_TDMA_PARA_LENGTH; i++)
3051                        coex_dm->fw_tdma_para[i - 1] = buf[i];
3052                return;
3053        }
3054
3055        if (rsp_source == COEX_BTINFO_SRC_WL_FW) {
3056                rtw_dbg(rtwdev, RTW_DBG_COEX,
3057                        "[BTCoex], bt_info reply by WL FW\n");
3058
3059                rtw_coex_update_bt_link_info(rtwdev);
3060                return;
3061        }
3062
3063        if (rsp_source == COEX_BTINFO_SRC_BT_RSP ||
3064            rsp_source == COEX_BTINFO_SRC_BT_ACT) {
3065                if (coex_stat->bt_disabled) {
3066                        coex_stat->bt_disabled = false;
3067                        coex_stat->bt_reenable = true;
3068                        ieee80211_queue_delayed_work(rtwdev->hw,
3069                                                     &coex->bt_reenable_work,
3070                                                     15 * HZ);
3071                        rtw_dbg(rtwdev, RTW_DBG_COEX,
3072                                "[BTCoex], BT enable detected by bt_info\n");
3073                }
3074        }
3075
3076        if (length != COEX_BTINFO_LENGTH) {
3077                rtw_dbg(rtwdev, RTW_DBG_COEX,
3078                        "[BTCoex], Bt_info length = %d invalid!!\n", length);
3079
3080                return;
3081        }
3082
3083        rtw_dbg(rtwdev, RTW_DBG_COEX,
3084                "[BTCoex], Bt_info[%d], len=%d, data=[%02x %02x %02x %02x %02x %02x]\n",
3085                buf[0], length, buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
3086
3087        for (i = 0; i < COEX_BTINFO_LENGTH; i++)
3088                coex_stat->bt_info_c2h[rsp_source][i] = buf[i];
3089
3090        /* get the same info from bt, skip it */
3091        if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 &&
3092            coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 &&
3093            coex_stat->bt_info_c2h[rsp_source][3] == coex_stat->bt_info_hb0 &&
3094            coex_stat->bt_info_c2h[rsp_source][4] == coex_stat->bt_info_hb1 &&
3095            coex_stat->bt_info_c2h[rsp_source][5] == coex_stat->bt_info_hb2 &&
3096            coex_stat->bt_info_c2h[rsp_source][6] == coex_stat->bt_info_hb3) {
3097                rtw_dbg(rtwdev, RTW_DBG_COEX,
3098                        "[BTCoex], Return because Btinfo duplicate!!\n");
3099                return;
3100        }
3101
3102        coex_stat->bt_info_lb2 = coex_stat->bt_info_c2h[rsp_source][1];
3103        coex_stat->bt_info_lb3 = coex_stat->bt_info_c2h[rsp_source][2];
3104        coex_stat->bt_info_hb0 = coex_stat->bt_info_c2h[rsp_source][3];
3105        coex_stat->bt_info_hb1 = coex_stat->bt_info_c2h[rsp_source][4];
3106        coex_stat->bt_info_hb2 = coex_stat->bt_info_c2h[rsp_source][5];
3107        coex_stat->bt_info_hb3 = coex_stat->bt_info_c2h[rsp_source][6];
3108
3109        /* 0xff means BT is under WHCK test */
3110        coex_stat->bt_whck_test = (coex_stat->bt_info_lb2 == 0xff);
3111
3112        inq_page = ((coex_stat->bt_info_lb2 & BIT(2)) == BIT(2));
3113
3114        if (inq_page != coex_stat->bt_inq_page) {
3115                cancel_delayed_work_sync(&coex->bt_remain_work);
3116                coex_stat->bt_inq_page = inq_page;
3117
3118                if (inq_page)
3119                        coex_stat->bt_inq_remain = true;
3120                else
3121                        ieee80211_queue_delayed_work(rtwdev->hw,
3122                                                     &coex->bt_remain_work,
3123                                                     4 * HZ);
3124        }
3125        coex_stat->bt_acl_busy = ((coex_stat->bt_info_lb2 & BIT(3)) == BIT(3));
3126        if (chip->ble_hid_profile_support) {
3127                if (coex_stat->bt_info_lb2 & BIT(5)) {
3128                        if (coex_stat->bt_info_hb1 & BIT(0)) {
3129                                /*BLE HID*/
3130                                coex_stat->bt_ble_hid_exist = true;
3131                        } else {
3132                                coex_stat->bt_ble_hid_exist = false;
3133                        }
3134                        coex_stat->bt_ble_exist = false;
3135                } else if (coex_stat->bt_info_hb1 & BIT(0)) {
3136                        /*RCU*/
3137                        coex_stat->bt_ble_hid_exist = false;
3138                        coex_stat->bt_ble_exist = true;
3139                } else {
3140                        coex_stat->bt_ble_hid_exist = false;
3141                        coex_stat->bt_ble_exist = false;
3142                }
3143        } else {
3144                if (coex_stat->bt_info_hb1 & BIT(0)) {
3145                        if (coex_stat->bt_hid_slot == 1 &&
3146                            coex_stat->hi_pri_rx + 100 < coex_stat->hi_pri_tx &&
3147                            coex_stat->hi_pri_rx < 100) {
3148                                coex_stat->bt_ble_hid_exist = true;
3149                                coex_stat->bt_ble_exist = false;
3150                        } else {
3151                                coex_stat->bt_ble_hid_exist = false;
3152                                coex_stat->bt_ble_exist = true;
3153                        }
3154                } else {
3155                        coex_stat->bt_ble_hid_exist = false;
3156                        coex_stat->bt_ble_exist = false;
3157                }
3158        }
3159
3160        coex_stat->cnt_bt[COEX_CNT_BT_RETRY] = coex_stat->bt_info_lb3 & 0xf;
3161        if (coex_stat->cnt_bt[COEX_CNT_BT_RETRY] >= 1)
3162                coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]++;
3163
3164        coex_stat->bt_fix_2M = ((coex_stat->bt_info_lb3 & BIT(4)) == BIT(4));
3165        coex_stat->bt_inq = ((coex_stat->bt_info_lb3 & BIT(5)) == BIT(5));
3166        if (coex_stat->bt_inq)
3167                coex_stat->cnt_bt[COEX_CNT_BT_INQ]++;
3168
3169        coex_stat->bt_page = ((coex_stat->bt_info_lb3 & BIT(7)) == BIT(7));
3170        if (coex_stat->bt_page)
3171                coex_stat->cnt_bt[COEX_CNT_BT_PAGE]++;
3172
3173        /* unit: % (value-100 to translate to unit: dBm in coex info) */
3174        if (chip->bt_rssi_type == COEX_BTRSSI_RATIO) {
3175                coex_stat->bt_rssi = coex_stat->bt_info_hb0 * 2 + 10;
3176        } else {
3177                if (coex_stat->bt_info_hb0 <= 127)
3178                        coex_stat->bt_rssi = 100;
3179                else if (256 - coex_stat->bt_info_hb0 <= 100)
3180                        coex_stat->bt_rssi = 100 - (256 - coex_stat->bt_info_hb0);
3181                else
3182                        coex_stat->bt_rssi = 0;
3183        }
3184
3185        if (coex_stat->bt_info_hb1 & BIT(1))
3186                coex_stat->cnt_bt[COEX_CNT_BT_REINIT]++;
3187
3188        if (coex_stat->bt_info_hb1 & BIT(2)) {
3189                coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK]++;
3190                coex_stat->bt_setup_link = true;
3191                if (coex_stat->bt_reenable)
3192                        bt_relink_time = 6 * HZ;
3193                else
3194                        bt_relink_time = 1 * HZ;
3195
3196                ieee80211_queue_delayed_work(rtwdev->hw,
3197                                             &coex->bt_relink_work,
3198                                             bt_relink_time);
3199
3200                rtw_dbg(rtwdev, RTW_DBG_COEX,
3201                        "[BTCoex], Re-Link start in BT info!!\n");
3202        }
3203
3204        if (coex_stat->bt_info_hb1 & BIT(3))
3205                coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT]++;
3206
3207        coex_stat->bt_ble_voice = ((coex_stat->bt_info_hb1 & BIT(4)) == BIT(4));
3208        coex_stat->bt_ble_scan_en = ((coex_stat->bt_info_hb1 & BIT(5)) == BIT(5));
3209        if (coex_stat->bt_info_hb1 & BIT(6))
3210                coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH]++;
3211
3212        coex_stat->bt_multi_link = ((coex_stat->bt_info_hb1 & BIT(7)) == BIT(7));
3213        /* for multi_link = 0 but bt pkt remain exist */
3214        /* Use PS-TDMA to protect WL RX */
3215        if (!coex_stat->bt_multi_link && coex_stat->bt_multi_link_pre) {
3216                coex_stat->bt_multi_link_remain = true;
3217                ieee80211_queue_delayed_work(rtwdev->hw,
3218                                             &coex->bt_multi_link_remain_work,
3219                                             3 * HZ);
3220        }
3221        coex_stat->bt_multi_link_pre = coex_stat->bt_multi_link;
3222
3223        /* resend wifi info to bt, it is reset and lost the info */
3224        if (coex_stat->bt_info_hb1 & BIT(1)) {
3225                rtw_dbg(rtwdev, RTW_DBG_COEX,
3226                        "[BTCoex], BT Re-init, send wifi BW & Chnl to BT!!\n");
3227
3228                if (coex_stat->wl_connected)
3229                        type = COEX_MEDIA_CONNECT;
3230                else
3231                        type = COEX_MEDIA_DISCONNECT;
3232                rtw_coex_update_wl_ch_info(rtwdev, type);
3233        }
3234
3235        /* if ignore_wlan_act && not set_up_link */
3236        if ((coex_stat->bt_info_hb1 & BIT(3)) &&
3237            (!(coex_stat->bt_info_hb1 & BIT(2)))) {
3238                rtw_dbg(rtwdev, RTW_DBG_COEX,
3239                        "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n");
3240                rtw_coex_ignore_wlan_act(rtwdev, false);
3241        }
3242
3243        coex_stat->bt_opp_exist = ((coex_stat->bt_info_hb2 & BIT(0)) == BIT(0));
3244        if (coex_stat->bt_info_hb2 & BIT(1))
3245                coex_stat->cnt_bt[COEX_CNT_BT_AFHUPDATE]++;
3246
3247        coex_stat->bt_a2dp_active = (coex_stat->bt_info_hb2 & BIT(2)) == BIT(2);
3248        coex_stat->bt_slave = ((coex_stat->bt_info_hb2 & BIT(3)) == BIT(3));
3249        coex_stat->bt_hid_slot = (coex_stat->bt_info_hb2 & 0x30) >> 4;
3250        coex_stat->bt_hid_pair_num = (coex_stat->bt_info_hb2 & 0xc0) >> 6;
3251        if (coex_stat->bt_hid_pair_num > 0 && coex_stat->bt_hid_slot >= 2)
3252                coex_stat->bt_418_hid_exist = true;
3253        else if (coex_stat->bt_hid_pair_num == 0 || coex_stat->bt_hid_slot == 1)
3254                coex_stat->bt_418_hid_exist = false;
3255
3256        if ((coex_stat->bt_info_lb2 & 0x49) == 0x49)
3257                coex_stat->bt_a2dp_bitpool = (coex_stat->bt_info_hb3 & 0x7f);
3258        else
3259                coex_stat->bt_a2dp_bitpool = 0;
3260
3261        coex_stat->bt_a2dp_sink = ((coex_stat->bt_info_hb3 & BIT(7)) == BIT(7));
3262
3263        rtw_coex_update_bt_link_info(rtwdev);
3264        rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
3265}
3266
3267#define COEX_BT_HIDINFO_MTK     0x46
3268static const u8 coex_bt_hidinfo_ps[] = {0x57, 0x69, 0x72};
3269static const u8 coex_bt_hidinfo_xb[] = {0x58, 0x62, 0x6f};
3270
3271void rtw_coex_bt_hid_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
3272{
3273        struct rtw_coex *coex = &rtwdev->coex;
3274        struct rtw_chip_info *chip = rtwdev->chip;
3275        struct rtw_coex_stat *coex_stat = &coex->stat;
3276        struct rtw_coex_hid *hidinfo;
3277        struct rtw_coex_hid_info_a *hida;
3278        struct rtw_coex_hid_handle_list *hl, *bhl;
3279        u8 sub_id = buf[2], gamehid_cnt = 0, handle, i;
3280        bool cur_game_hid_exist, complete;
3281
3282        if (!chip->wl_mimo_ps_support &&
3283            (sub_id == COEX_BT_HIDINFO_LIST || sub_id == COEX_BT_HIDINFO_A))
3284                return;
3285
3286        rtw_dbg(rtwdev, RTW_DBG_COEX,
3287                "[BTCoex], HID info notify, sub_id = 0x%x\n", sub_id);
3288
3289        switch (sub_id) {
3290        case COEX_BT_HIDINFO_LIST:
3291                hl = &coex_stat->hid_handle_list;
3292                bhl = (struct rtw_coex_hid_handle_list *)buf;
3293                if (!memcmp(hl, bhl, sizeof(*hl)))
3294                        return;
3295                coex_stat->hid_handle_list = *bhl;
3296                memset(&coex_stat->hid_info, 0, sizeof(coex_stat->hid_info));
3297                for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
3298                        hidinfo = &coex_stat->hid_info[i];
3299                        if (hl->handle[i] != COEX_BT_HIDINFO_NOTCON &&
3300                            hl->handle[i] != 0)
3301                                hidinfo->hid_handle = hl->handle[i];
3302                }
3303                break;
3304        case COEX_BT_HIDINFO_A:
3305                hida = (struct rtw_coex_hid_info_a *)buf;
3306                handle = hida->handle;
3307                for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
3308                        hidinfo = &coex_stat->hid_info[i];
3309                        if (hidinfo->hid_handle == handle) {
3310                                hidinfo->hid_vendor = hida->vendor;
3311                                memcpy(hidinfo->hid_name, hida->name,
3312                                       sizeof(hidinfo->hid_name));
3313                                hidinfo->hid_info_completed = true;
3314                                break;
3315                        }
3316                }
3317                break;
3318        }
3319        for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
3320                hidinfo = &coex_stat->hid_info[i];
3321                complete = hidinfo->hid_info_completed;
3322                handle = hidinfo->hid_handle;
3323                if (!complete || handle == COEX_BT_HIDINFO_NOTCON ||
3324                    handle == 0 || handle >= COEX_BT_BLE_HANDLE_THRS) {
3325                        hidinfo->is_game_hid = false;
3326                        continue;
3327                }
3328
3329                if (hidinfo->hid_vendor == COEX_BT_HIDINFO_MTK) {
3330                        if ((memcmp(hidinfo->hid_name,
3331                                    coex_bt_hidinfo_ps,
3332                                    COEX_BT_HIDINFO_NAME)) == 0)
3333                                hidinfo->is_game_hid = true;
3334                        else if ((memcmp(hidinfo->hid_name,
3335                                         coex_bt_hidinfo_xb,
3336                                         COEX_BT_HIDINFO_NAME)) == 0)
3337                                hidinfo->is_game_hid = true;
3338                        else
3339                                hidinfo->is_game_hid = false;
3340                } else {
3341                        hidinfo->is_game_hid = false;
3342                }
3343                if (hidinfo->is_game_hid)
3344                        gamehid_cnt++;
3345        }
3346
3347        if (gamehid_cnt > 0)
3348                cur_game_hid_exist = true;
3349        else
3350                cur_game_hid_exist = false;
3351
3352        if (cur_game_hid_exist != coex_stat->bt_game_hid_exist) {
3353                coex_stat->bt_game_hid_exist = cur_game_hid_exist;
3354                rtw_dbg(rtwdev, RTW_DBG_COEX,
3355                        "[BTCoex], HID info changed!bt_game_hid_exist = %d!\n",
3356                        coex_stat->bt_game_hid_exist);
3357                rtw_coex_run_coex(rtwdev, COEX_RSN_BTSTATUS);
3358        }
3359}
3360
3361void rtw_coex_query_bt_hid_list(struct rtw_dev *rtwdev)
3362{
3363        struct rtw_coex *coex = &rtwdev->coex;
3364        struct rtw_chip_info *chip = rtwdev->chip;
3365        struct rtw_coex_stat *coex_stat = &coex->stat;
3366        struct rtw_coex_hid *hidinfo;
3367        u8 i, handle;
3368        bool complete;
3369
3370        if (!chip->wl_mimo_ps_support || coex_stat->wl_under_ips ||
3371            (coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl))
3372                return;
3373
3374        if (!coex_stat->bt_hid_exist &&
3375            !((coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION) &&
3376              (coex_stat->hi_pri_tx + coex_stat->hi_pri_rx >
3377               COEX_BT_GAMEHID_CNT)))
3378                return;
3379
3380        rtw_fw_coex_query_hid_info(rtwdev, COEX_BT_HIDINFO_LIST, 0);
3381
3382        for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
3383                hidinfo = &coex_stat->hid_info[i];
3384                complete = hidinfo->hid_info_completed;
3385                handle = hidinfo->hid_handle;
3386                if (handle == 0 || handle == COEX_BT_HIDINFO_NOTCON ||
3387                    handle >= COEX_BT_BLE_HANDLE_THRS || complete)
3388                        continue;
3389
3390                rtw_fw_coex_query_hid_info(rtwdev,
3391                                           COEX_BT_HIDINFO_A,
3392                                           handle);
3393        }
3394}
3395
3396void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
3397{
3398        struct rtw_coex *coex = &rtwdev->coex;
3399        struct rtw_coex_stat *coex_stat = &coex->stat;
3400        u8 val;
3401        int i;
3402
3403        rtw_dbg(rtwdev, RTW_DBG_COEX,
3404                "[BTCoex], WiFi Fw Dbg info = %8ph (len = %d)\n",
3405                buf, length);
3406        if (WARN(length < 8, "invalid wl info c2h length\n"))
3407                return;
3408
3409        if (buf[0] != 0x08)
3410                return;
3411
3412        for (i = 1; i < 8; i++) {
3413                val = coex_stat->wl_fw_dbg_info_pre[i];
3414                if (buf[i] >= val)
3415                        coex_stat->wl_fw_dbg_info[i] = buf[i] - val;
3416                else
3417                        coex_stat->wl_fw_dbg_info[i] = 255 - val + buf[i];
3418
3419                coex_stat->wl_fw_dbg_info_pre[i] = buf[i];
3420        }
3421
3422        coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]++;
3423        rtw_coex_wl_ccklock_action(rtwdev);
3424        rtw_coex_wl_ccklock_detect(rtwdev);
3425}
3426
3427void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type)
3428{
3429        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
3430}
3431
3432void rtw_coex_wl_status_check(struct rtw_dev *rtwdev)
3433{
3434        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3435
3436        if ((coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) ||
3437            coex_stat->wl_under_ips)
3438                return;
3439
3440        rtw_coex_monitor_bt_ctr(rtwdev);
3441}
3442
3443void rtw_coex_bt_relink_work(struct work_struct *work)
3444{
3445        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
3446                                              coex.bt_relink_work.work);
3447        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3448
3449        mutex_lock(&rtwdev->mutex);
3450        coex_stat->bt_setup_link = false;
3451        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
3452        mutex_unlock(&rtwdev->mutex);
3453}
3454
3455void rtw_coex_bt_reenable_work(struct work_struct *work)
3456{
3457        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
3458                                              coex.bt_reenable_work.work);
3459        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3460
3461        mutex_lock(&rtwdev->mutex);
3462        coex_stat->bt_reenable = false;
3463        mutex_unlock(&rtwdev->mutex);
3464}
3465
3466void rtw_coex_defreeze_work(struct work_struct *work)
3467{
3468        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
3469                                              coex.defreeze_work.work);
3470        struct rtw_coex *coex = &rtwdev->coex;
3471        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3472
3473        mutex_lock(&rtwdev->mutex);
3474        coex->freeze = false;
3475        coex_stat->wl_hi_pri_task1 = false;
3476        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
3477        mutex_unlock(&rtwdev->mutex);
3478}
3479
3480void rtw_coex_wl_remain_work(struct work_struct *work)
3481{
3482        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
3483                                              coex.wl_remain_work.work);
3484        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3485
3486        mutex_lock(&rtwdev->mutex);
3487        coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
3488        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
3489        mutex_unlock(&rtwdev->mutex);
3490}
3491
3492void rtw_coex_bt_remain_work(struct work_struct *work)
3493{
3494        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
3495                                              coex.bt_remain_work.work);
3496        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3497
3498        mutex_lock(&rtwdev->mutex);
3499        coex_stat->bt_inq_remain = coex_stat->bt_inq_page;
3500        rtw_coex_run_coex(rtwdev, COEX_RSN_BTSTATUS);
3501        mutex_unlock(&rtwdev->mutex);
3502}
3503
3504void rtw_coex_wl_connecting_work(struct work_struct *work)
3505{
3506        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
3507                                              coex.wl_connecting_work.work);
3508        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3509
3510        mutex_lock(&rtwdev->mutex);
3511        coex_stat->wl_connecting = false;
3512        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], WL connecting stop!!\n");
3513        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
3514        mutex_unlock(&rtwdev->mutex);
3515}
3516
3517void rtw_coex_bt_multi_link_remain_work(struct work_struct *work)
3518{
3519        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
3520                coex.bt_multi_link_remain_work.work);
3521        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3522
3523        mutex_lock(&rtwdev->mutex);
3524        coex_stat->bt_multi_link_remain = false;
3525        mutex_unlock(&rtwdev->mutex);
3526}
3527
3528void rtw_coex_wl_ccklock_work(struct work_struct *work)
3529{
3530        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
3531                                              coex.wl_ccklock_work.work);
3532        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
3533
3534        mutex_lock(&rtwdev->mutex);
3535        coex_stat->wl_cck_lock = false;
3536        mutex_unlock(&rtwdev->mutex);
3537}
3538
3539#ifdef CONFIG_RTW88_DEBUGFS
3540#define INFO_SIZE       80
3541
3542#define case_BTINFO(src) \
3543        case COEX_BTINFO_SRC_##src: return #src
3544
3545static const char *rtw_coex_get_bt_info_src_string(u8 bt_info_src)
3546{
3547        switch (bt_info_src) {
3548        case_BTINFO(WL_FW);
3549        case_BTINFO(BT_RSP);
3550        case_BTINFO(BT_ACT);
3551        default:
3552                return "Unknown";
3553        }
3554}
3555
3556#define case_RSN(src) \
3557        case COEX_RSN_##src: return #src
3558
3559static const char *rtw_coex_get_reason_string(u8 reason)
3560{
3561        switch (reason) {
3562        case_RSN(2GSCANSTART);
3563        case_RSN(5GSCANSTART);
3564        case_RSN(SCANFINISH);
3565        case_RSN(2GSWITCHBAND);
3566        case_RSN(5GSWITCHBAND);
3567        case_RSN(2GCONSTART);
3568        case_RSN(5GCONSTART);
3569        case_RSN(2GCONFINISH);
3570        case_RSN(5GCONFINISH);
3571        case_RSN(2GMEDIA);
3572        case_RSN(5GMEDIA);
3573        case_RSN(MEDIADISCON);
3574        case_RSN(BTINFO);
3575        case_RSN(LPS);
3576        case_RSN(WLSTATUS);
3577        default:
3578                return "Unknown";
3579        }
3580}
3581
3582static u8 rtw_coex_get_table_index(struct rtw_dev *rtwdev, u32 wl_reg_6c0,
3583                                   u32 wl_reg_6c4)
3584{
3585        struct rtw_chip_info *chip = rtwdev->chip;
3586        struct rtw_efuse *efuse = &rtwdev->efuse;
3587        u8 ans = 0xFF;
3588        u8 n, i;
3589        u32 load_bt_val;
3590        u32 load_wl_val;
3591        bool share_ant = efuse->share_ant;
3592
3593        if (share_ant)
3594                n = chip->table_sant_num;
3595        else
3596                n = chip->table_nsant_num;
3597
3598        for (i = 0; i < n; i++) {
3599                if (share_ant) {
3600                        load_bt_val = chip->table_sant[i].bt;
3601                        load_wl_val = chip->table_sant[i].wl;
3602                } else {
3603                        load_bt_val = chip->table_nsant[i].bt;
3604                        load_wl_val = chip->table_nsant[i].wl;
3605                }
3606
3607                if (wl_reg_6c0 == load_bt_val &&
3608                    wl_reg_6c4 == load_wl_val) {
3609                        ans = i;
3610                        if (!share_ant)
3611                                ans += 100;
3612                        break;
3613                }
3614        }
3615
3616        return ans;
3617}
3618
3619static u8 rtw_coex_get_tdma_index(struct rtw_dev *rtwdev, u8 *tdma_para)
3620{
3621        struct rtw_efuse *efuse = &rtwdev->efuse;
3622        struct rtw_chip_info *chip = rtwdev->chip;
3623        u8 ans = 0xFF;
3624        u8 n, i, j;
3625        u8 load_cur_tab_val;
3626        bool valid = false;
3627        bool share_ant = efuse->share_ant;
3628
3629        if (share_ant)
3630                n = chip->tdma_sant_num;
3631        else
3632                n = chip->tdma_nsant_num;
3633
3634        for (i = 0; i < n; i++) {
3635                valid = false;
3636                for (j = 0; j < 5; j++) {
3637                        if (share_ant)
3638                                load_cur_tab_val = chip->tdma_sant[i].para[j];
3639                        else
3640                                load_cur_tab_val = chip->tdma_nsant[i].para[j];
3641
3642                        if (*(tdma_para + j) != load_cur_tab_val)
3643                                break;
3644
3645                        if (j == 4)
3646                                valid = true;
3647                }
3648                if (valid) {
3649                        ans = i;
3650                        break;
3651                }
3652        }
3653
3654        return ans;
3655}
3656
3657static int rtw_coex_addr_info(struct rtw_dev *rtwdev,
3658                              const struct rtw_reg_domain *reg,
3659                              char addr_info[], int n)
3660{
3661        const char *rf_prefix = "";
3662        const char *sep = n == 0 ? "" : "/ ";
3663        int ffs, fls;
3664        int max_fls;
3665
3666        if (INFO_SIZE - n <= 0)
3667                return 0;
3668
3669        switch (reg->domain) {
3670        case RTW_REG_DOMAIN_MAC32:
3671                max_fls = 31;
3672                break;
3673        case RTW_REG_DOMAIN_MAC16:
3674                max_fls = 15;
3675                break;
3676        case RTW_REG_DOMAIN_MAC8:
3677                max_fls = 7;
3678                break;
3679        case RTW_REG_DOMAIN_RF_A:
3680        case RTW_REG_DOMAIN_RF_B:
3681                rf_prefix = "RF_";
3682                max_fls = 19;
3683                break;
3684        default:
3685                return 0;
3686        }
3687
3688        ffs = __ffs(reg->mask);
3689        fls = __fls(reg->mask);
3690
3691        if (ffs == 0 && fls == max_fls)
3692                return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x",
3693                                 sep, rf_prefix, reg->addr);
3694        else if (ffs == fls)
3695                return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x[%d]",
3696                                 sep, rf_prefix, reg->addr, ffs);
3697        else
3698                return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x[%d:%d]",
3699                                 sep, rf_prefix, reg->addr, fls, ffs);
3700}
3701
3702static int rtw_coex_val_info(struct rtw_dev *rtwdev,
3703                             const struct rtw_reg_domain *reg,
3704                             char val_info[], int n)
3705{
3706        const char *sep = n == 0 ? "" : "/ ";
3707        u8 rf_path;
3708
3709        if (INFO_SIZE - n <= 0)
3710                return 0;
3711
3712        switch (reg->domain) {
3713        case RTW_REG_DOMAIN_MAC32:
3714                return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,
3715                                 rtw_read32_mask(rtwdev, reg->addr, reg->mask));
3716        case RTW_REG_DOMAIN_MAC16:
3717                return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,
3718                                 rtw_read16_mask(rtwdev, reg->addr, reg->mask));
3719        case RTW_REG_DOMAIN_MAC8:
3720                return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,
3721                                 rtw_read8_mask(rtwdev, reg->addr, reg->mask));
3722        case RTW_REG_DOMAIN_RF_A:
3723                rf_path = RF_PATH_A;
3724                break;
3725        case RTW_REG_DOMAIN_RF_B:
3726                rf_path = RF_PATH_B;
3727                break;
3728        default:
3729                return 0;
3730        }
3731
3732        /* only RF go through here */
3733        return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,
3734                         rtw_read_rf(rtwdev, rf_path, reg->addr, reg->mask));
3735}
3736
3737static void rtw_coex_set_coexinfo_hw(struct rtw_dev *rtwdev, struct seq_file *m)
3738{
3739        struct rtw_chip_info *chip = rtwdev->chip;
3740        const struct rtw_reg_domain *reg;
3741        char addr_info[INFO_SIZE];
3742        int n_addr = 0;
3743        char val_info[INFO_SIZE];
3744        int n_val = 0;
3745        int i;
3746
3747        for (i = 0; i < chip->coex_info_hw_regs_num; i++) {
3748                reg = &chip->coex_info_hw_regs[i];
3749
3750                n_addr += rtw_coex_addr_info(rtwdev, reg, addr_info, n_addr);
3751                n_val += rtw_coex_val_info(rtwdev, reg, val_info, n_val);
3752
3753                if (reg->domain == RTW_REG_DOMAIN_NL) {
3754                        seq_printf(m, "%-40s = %s\n", addr_info, val_info);
3755                        n_addr = 0;
3756                        n_val = 0;
3757                }
3758        }
3759
3760        if (n_addr != 0 && n_val != 0)
3761                seq_printf(m, "%-40s = %s\n", addr_info, val_info);
3762}
3763
3764static bool rtw_coex_get_bt_reg(struct rtw_dev *rtwdev,
3765                                u8 type, u16 addr, u16 *val)
3766{
3767        struct rtw_coex_info_req req = {0};
3768        struct sk_buff *skb;
3769        __le16 le_addr;
3770        u8 *payload;
3771
3772        le_addr = cpu_to_le16(addr);
3773        req.op_code = BT_MP_INFO_OP_READ_REG;
3774        req.para1 = type;
3775        req.para2 = le16_get_bits(le_addr, GENMASK(7, 0));
3776        req.para3 = le16_get_bits(le_addr, GENMASK(15, 8));
3777        skb = rtw_coex_info_request(rtwdev, &req);
3778        if (!skb) {
3779                *val = 0xeaea;
3780                return false;
3781        }
3782
3783        payload = get_payload_from_coex_resp(skb);
3784        *val = GET_COEX_RESP_BT_REG_VAL(payload);
3785        dev_kfree_skb_any(skb);
3786
3787        return true;
3788}
3789
3790static bool rtw_coex_get_bt_patch_version(struct rtw_dev *rtwdev,
3791                                          u32 *patch_version)
3792{
3793        struct rtw_coex_info_req req = {0};
3794        struct sk_buff *skb;
3795        u8 *payload;
3796
3797        req.op_code = BT_MP_INFO_OP_PATCH_VER;
3798        skb = rtw_coex_info_request(rtwdev, &req);
3799        if (!skb)
3800                return false;
3801
3802        payload = get_payload_from_coex_resp(skb);
3803        *patch_version = GET_COEX_RESP_BT_PATCH_VER(payload);
3804        dev_kfree_skb_any(skb);
3805
3806        return true;
3807}
3808
3809static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev,
3810                                              u32 *supported_version)
3811{
3812        struct rtw_coex_info_req req = {0};
3813        struct sk_buff *skb;
3814        u8 *payload;
3815
3816        req.op_code = BT_MP_INFO_OP_SUPP_VER;
3817        skb = rtw_coex_info_request(rtwdev, &req);
3818        if (!skb)
3819                return false;
3820
3821        payload = get_payload_from_coex_resp(skb);
3822        *supported_version = GET_COEX_RESP_BT_SUPP_VER(payload);
3823        dev_kfree_skb_any(skb);
3824
3825        return true;
3826}
3827
3828static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev,
3829                                              u32 *supported_feature)
3830{
3831        struct rtw_coex_info_req req = {0};
3832        struct sk_buff *skb;
3833        u8 *payload;
3834
3835        req.op_code = BT_MP_INFO_OP_SUPP_FEAT;
3836        skb = rtw_coex_info_request(rtwdev, &req);
3837        if (!skb)
3838                return false;
3839
3840        payload = get_payload_from_coex_resp(skb);
3841        *supported_feature = GET_COEX_RESP_BT_SUPP_FEAT(payload);
3842        dev_kfree_skb_any(skb);
3843
3844        return true;
3845}
3846
3847struct rtw_coex_sta_stat_iter_data {
3848        struct rtw_vif *rtwvif;
3849        struct seq_file *file;
3850};
3851
3852static void rtw_coex_sta_stat_iter(void *data, struct ieee80211_sta *sta)
3853{
3854        struct rtw_coex_sta_stat_iter_data *sta_iter_data = data;
3855        struct rtw_vif *rtwvif = sta_iter_data->rtwvif;
3856        struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
3857        struct seq_file *m = sta_iter_data->file;
3858        struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
3859        u8 rssi;
3860
3861        if (si->vif != vif)
3862                return;
3863
3864        rssi = ewma_rssi_read(&si->avg_rssi);
3865        seq_printf(m, "\tPeer %3d\n", si->mac_id);
3866        seq_printf(m, "\t\t%-24s = %d\n", "RSSI", rssi);
3867        seq_printf(m, "\t\t%-24s = %d\n", "BW mode", si->bw_mode);
3868}
3869
3870struct rtw_coex_vif_stat_iter_data {
3871        struct rtw_dev *rtwdev;
3872        struct seq_file *file;
3873};
3874
3875static void rtw_coex_vif_stat_iter(void *data, u8 *mac,
3876                                   struct ieee80211_vif *vif)
3877{
3878        struct rtw_coex_vif_stat_iter_data *vif_iter_data = data;
3879        struct rtw_coex_sta_stat_iter_data sta_iter_data;
3880        struct rtw_dev *rtwdev = vif_iter_data->rtwdev;
3881        struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
3882        struct seq_file *m = vif_iter_data->file;
3883        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
3884
3885        seq_printf(m, "Iface on Port (%d)\n", rtwvif->port);
3886        seq_printf(m, "\t%-32s = %d\n",
3887                   "Beacon interval", bss_conf->beacon_int);
3888        seq_printf(m, "\t%-32s = %d\n",
3889                   "Network Type", rtwvif->net_type);
3890
3891        sta_iter_data.rtwvif = rtwvif;
3892        sta_iter_data.file = m;
3893        rtw_iterate_stas_atomic(rtwdev, rtw_coex_sta_stat_iter,
3894                                &sta_iter_data);
3895}
3896
3897#define case_WLINK(src) \
3898        case COEX_WLINK_##src: return #src
3899
3900static const char *rtw_coex_get_wl_coex_mode(u8 coex_wl_link_mode)
3901{
3902        switch (coex_wl_link_mode) {
3903        case_WLINK(2G1PORT);
3904        case_WLINK(5G);
3905        case_WLINK(2GFREE);
3906        default:
3907                return "Unknown";
3908        }
3909}
3910
3911void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
3912{
3913        struct rtw_chip_info *chip = rtwdev->chip;
3914        struct rtw_dm_info *dm_info = &rtwdev->dm_info;
3915        struct rtw_coex *coex = &rtwdev->coex;
3916        struct rtw_coex_stat *coex_stat = &coex->stat;
3917        struct rtw_coex_dm *coex_dm = &coex->dm;
3918        struct rtw_hal *hal = &rtwdev->hal;
3919        struct rtw_efuse *efuse = &rtwdev->efuse;
3920        struct rtw_fw_state *fw = &rtwdev->fw;
3921        struct rtw_coex_vif_stat_iter_data vif_iter_data;
3922        u8 reason = coex_dm->reason;
3923        u8 sys_lte;
3924        u16 score_board_WB, score_board_BW;
3925        u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc;
3926        u32 lte_coex, bt_coex;
3927        int i;
3928
3929        score_board_BW = rtw_coex_read_scbd(rtwdev);
3930        score_board_WB = coex_stat->score_board;
3931        wl_reg_6c0 = rtw_read32(rtwdev, REG_BT_COEX_TABLE0);
3932        wl_reg_6c4 = rtw_read32(rtwdev, REG_BT_COEX_TABLE1);
3933        wl_reg_6c8 = rtw_read32(rtwdev, REG_BT_COEX_BRK_TABLE);
3934        wl_reg_6cc = rtw_read32(rtwdev, REG_BT_COEX_TABLE_H);
3935        wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL);
3936
3937        sys_lte = rtw_read8(rtwdev, 0x73);
3938        lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38);
3939        bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54);
3940
3941        if (!coex_stat->bt_disabled && !coex_stat->bt_mailbox_reply) {
3942                rtw_coex_get_bt_supported_version(rtwdev,
3943                                &coex_stat->bt_supported_version);
3944                rtw_coex_get_bt_patch_version(rtwdev, &coex_stat->patch_ver);
3945                rtw_coex_get_bt_supported_feature(rtwdev,
3946                                &coex_stat->bt_supported_feature);
3947                rtw_coex_get_bt_reg(rtwdev, 3, 0xae, &coex_stat->bt_reg_vendor_ae);
3948                rtw_coex_get_bt_reg(rtwdev, 3, 0xac, &coex_stat->bt_reg_vendor_ac);
3949
3950                if (coex_stat->patch_ver != 0)
3951                        coex_stat->bt_mailbox_reply = true;
3952        }
3953
3954        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
3955        seq_printf(m, "**********************************************\n");
3956        seq_printf(m, "\t\tBT Coexist info %x\n", chip->id);
3957        seq_printf(m, "**********************************************\n");
3958
3959        if (coex->manual_control) {
3960                seq_puts(m, "============[Under Manual Control]============\n");
3961                seq_puts(m, "==========================================\n");
3962
3963        } else if (coex->stop_dm) {
3964                seq_puts(m, "============[Coex is STOPPED]============\n");
3965                seq_puts(m, "==========================================\n");
3966
3967        } else if (coex->freeze) {
3968                seq_puts(m, "============[coex_freeze]============\n");
3969                seq_puts(m, "==========================================\n");
3970        }
3971
3972        seq_printf(m, "%-40s = %s/ %d\n",
3973                   "Mech/ RFE",
3974                   efuse->share_ant ? "Shared" : "Non-Shared",
3975                   efuse->rfe_option);
3976        seq_printf(m, "%-40s = %08x/ 0x%02x/ 0x%08x %s\n",
3977                   "Coex Ver/ BT Dez/ BT Rpt",
3978                   chip->coex_para_ver, chip->bt_desired_ver,
3979                   coex_stat->bt_supported_version,
3980                   coex_stat->bt_disabled ? "(BT disabled)" :
3981                   coex_stat->bt_supported_version >= chip->bt_desired_ver ?
3982                   "(Match)" : "(Mismatch)");
3983        seq_printf(m, "%-40s = %s/ %u/ %d\n",
3984                   "Role/ RoleSwCnt/ IgnWL/ Feature",
3985                   coex_stat->bt_slave ? "Slave" : "Master",
3986                   coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH],
3987                   coex_dm->ignore_wl_act);
3988        seq_printf(m, "%-40s = %u.%u/ 0x%x/ 0x%x/ %c\n",
3989                   "WL FW/ BT FW/ BT FW Desired/ KT",
3990                   fw->version, fw->sub_version,
3991                   coex_stat->patch_ver,
3992                   chip->wl_fw_desired_ver, coex_stat->kt_ver + 65);
3993        seq_printf(m, "%-40s = %u/ %u/ %u/ ch-(%u)\n",
3994                   "AFH Map",
3995                   coex_dm->wl_ch_info[0], coex_dm->wl_ch_info[1],
3996                   coex_dm->wl_ch_info[2], hal->current_channel);
3997
3998        rtw_debugfs_get_simple_phy_info(m);
3999        seq_printf(m, "**********************************************\n");
4000        seq_printf(m, "\t\tBT Status\n");
4001        seq_printf(m, "**********************************************\n");
4002        seq_printf(m, "%-40s = %s/ %ddBm/ %u/ %u\n",
4003                   "BT status/ rssi/ retry/ pop",
4004                   coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE ? "non-conn" :
4005                   coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE ? "conn-idle" : "busy",
4006                   coex_stat->bt_rssi - 100,
4007                   coex_stat->cnt_bt[COEX_CNT_BT_RETRY],
4008                   coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]);
4009        seq_printf(m, "%-40s = %s%s%s%s%s (multi-link %d)\n",
4010                   "Profiles",
4011                   coex_stat->bt_a2dp_exist ? (coex_stat->bt_a2dp_sink ?
4012                                               "A2DP sink," : "A2DP,") : "",
4013                   coex_stat->bt_hfp_exist ? "HFP," : "",
4014                   coex_stat->bt_hid_exist ?
4015                   (coex_stat->bt_ble_exist ? "HID(RCU)," :
4016                    coex_stat->bt_hid_slot >= 2 ? "HID(4/18)" :
4017                    coex_stat->bt_ble_hid_exist ? "HID(BLE)" :
4018                    "HID(2/18),") : "",
4019                   coex_stat->bt_pan_exist ? coex_stat->bt_opp_exist ?
4020                   "OPP," : "PAN," : "",
4021                   coex_stat->bt_ble_voice ? "Voice," : "",
4022                   coex_stat->bt_multi_link);
4023        seq_printf(m, "%-40s = %u/ %u/ %u/ 0x%08x\n",
4024                   "Reinit/ Relink/ IgnWl/ Feature",
4025                   coex_stat->cnt_bt[COEX_CNT_BT_REINIT],
4026                   coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK],
4027                   coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT],
4028                   coex_stat->bt_supported_feature);
4029        seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",
4030                   "Page/ Inq/ iqk/ iqk fail",
4031                   coex_stat->cnt_bt[COEX_CNT_BT_PAGE],
4032                   coex_stat->cnt_bt[COEX_CNT_BT_INQ],
4033                   coex_stat->cnt_bt[COEX_CNT_BT_IQK],
4034                   coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]);
4035        seq_printf(m, "%-40s = 0x%04x/ 0x%04x/ 0x%04x/ 0x%04x\n",
4036                   "0xae/ 0xac/ score board (W->B)/ (B->W)",
4037                   coex_stat->bt_reg_vendor_ae,
4038                   coex_stat->bt_reg_vendor_ac,
4039                   score_board_WB, score_board_BW);
4040        seq_printf(m, "%-40s = %u/%u, %u/%u\n",
4041                   "Hi-Pri TX/RX, Lo-Pri TX/RX",
4042                   coex_stat->hi_pri_tx, coex_stat->hi_pri_rx,
4043                   coex_stat->lo_pri_tx, coex_stat->lo_pri_rx);
4044        for (i = 0; i < COEX_BTINFO_SRC_BT_IQK; i++)
4045                seq_printf(m, "%-40s = %7ph\n",
4046                           rtw_coex_get_bt_info_src_string(i),
4047                           coex_stat->bt_info_c2h[i]);
4048
4049        seq_printf(m, "**********************************************\n");
4050        seq_printf(m, "\t\tWiFi Status\n");
4051        seq_printf(m, "**********************************************\n");
4052        seq_printf(m, "%-40s = %d\n",
4053                   "Scanning", test_bit(RTW_FLAG_SCANNING, rtwdev->flags));
4054        seq_printf(m, "%-40s = %u/ TX %d Mbps/ RX %d Mbps\n",
4055                   "G_busy/ TX/ RX",
4056                   coex_stat->wl_gl_busy,
4057                   rtwdev->stats.tx_throughput, rtwdev->stats.rx_throughput);
4058        seq_printf(m, "%-40s = %u/ %u/ %u\n",
4059                   "IPS/ Low Power/ PS mode",
4060                   test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags),
4061                   test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags),
4062                   rtwdev->lps_conf.mode);
4063
4064        vif_iter_data.rtwdev = rtwdev;
4065        vif_iter_data.file = m;
4066        rtw_iterate_vifs_atomic(rtwdev, rtw_coex_vif_stat_iter, &vif_iter_data);
4067
4068        if (coex->manual_control) {
4069                seq_printf(m, "**********************************************\n");
4070                seq_printf(m, "\t\tMechanism (Under Manual)\n");
4071                seq_printf(m, "**********************************************\n");
4072                seq_printf(m, "%-40s = %5ph (%d)\n",
4073                           "TDMA Now",
4074                           coex_dm->fw_tdma_para,
4075                           rtw_coex_get_tdma_index(rtwdev,
4076                                                   &coex_dm->fw_tdma_para[0]));
4077        } else {
4078                seq_printf(m, "**********************************************\n");
4079                seq_printf(m, "\t\tMechanism\n");
4080                seq_printf(m, "**********************************************\n");
4081                seq_printf(m, "%-40s = %5ph (case-%d)\n",
4082                           "TDMA",
4083                           coex_dm->ps_tdma_para, coex_dm->cur_ps_tdma);
4084        }
4085        seq_printf(m, "%-40s = %s/ %s/ %d\n",
4086                   "Coex Mode/Free Run/Timer base",
4087                   rtw_coex_get_wl_coex_mode(coex_stat->wl_coex_mode),
4088                   coex->freerun ? "Yes" : "No",
4089                   coex_stat->tdma_timer_base);
4090        seq_printf(m, "%-40s = %d(%d)/ 0x%08x/ 0x%08x/ 0x%08x\n",
4091                   "Table/ 0x6c0/ 0x6c4/ 0x6c8",
4092                   coex_dm->cur_table,
4093                   rtw_coex_get_table_index(rtwdev, wl_reg_6c0, wl_reg_6c4),
4094                   wl_reg_6c0, wl_reg_6c4, wl_reg_6c8);
4095        seq_printf(m, "%-40s = 0x%08x/ 0x%08x/ %d/ reason (%s)\n",
4096                   "0x778/ 0x6cc/ Run Count/ Reason",
4097                   wl_reg_778, wl_reg_6cc,
4098                   coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN],
4099                   rtw_coex_get_reason_string(reason));
4100        seq_printf(m, "%-40s = %3ph\n",
4101                   "AFH Map to BT",
4102                   coex_dm->wl_ch_info);
4103        seq_printf(m, "%-40s = %s/ %d\n",
4104                   "AntDiv/ BtCtrlLPS/ g_busy",
4105                   coex_stat->wl_force_lps_ctrl ? "On" : "Off",
4106                   coex_stat->wl_gl_busy);
4107        seq_printf(m, "%-40s = %u/ %u/ %u/ %u/ %u\n",
4108                   "Null All/ Retry/ Ack/ BT Empty/ BT Late",
4109                   coex_stat->wl_fw_dbg_info[1], coex_stat->wl_fw_dbg_info[2],
4110                   coex_stat->wl_fw_dbg_info[3], coex_stat->wl_fw_dbg_info[4],
4111                   coex_stat->wl_fw_dbg_info[5]);
4112        seq_printf(m, "%-40s = %u/ %u/ %s/ %u\n",
4113                   "Cnt TDMA Toggle/ Lk 5ms/ Lk 5ms on/ FW",
4114                   coex_stat->wl_fw_dbg_info[6],
4115                   coex_stat->wl_fw_dbg_info[7],
4116                   coex_stat->wl_slot_extend ? "Yes" : "No",
4117                   coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]);
4118        seq_printf(m, "%-40s = %d/ %d/ %s/ %d\n",
4119                   "WL_TxPw/ BT_TxPw/ WL_Rx/ BT_LNA_Lvl",
4120                   coex_dm->cur_wl_pwr_lvl,
4121                   coex_dm->cur_bt_pwr_lvl,
4122                   coex_dm->cur_wl_rx_low_gain_en ? "On" : "Off",
4123                   coex_dm->cur_bt_lna_lvl);
4124
4125        seq_printf(m, "**********************************************\n");
4126        seq_printf(m, "\t\tHW setting\n");
4127        seq_printf(m, "**********************************************\n");
4128        seq_printf(m, "%-40s = %s/ %s\n",
4129                   "LTE Coex/ Path Owner",
4130                   lte_coex & BIT(7) ? "ON" : "OFF",
4131                   sys_lte & BIT(2) ? "WL" : "BT");
4132        seq_printf(m, "%-40s = RF:%s_BB:%s/ RF:%s_BB:%s/ %s\n",
4133                   "GNT_WL_CTRL/ GNT_BT_CTRL/ Dbg",
4134                   lte_coex & BIT(12) ? "SW" : "HW",
4135                   lte_coex & BIT(8) ? "SW" : "HW",
4136                   lte_coex & BIT(14) ? "SW" : "HW",
4137                   lte_coex & BIT(10) ? "SW" : "HW",
4138                   sys_lte & BIT(3) ? "On" : "Off");
4139        seq_printf(m, "%-40s = %lu/ %lu\n",
4140                   "GNT_WL/ GNT_BT",
4141                   (bt_coex & BIT(2)) >> 2, (bt_coex & BIT(3)) >> 3);
4142        seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",
4143                   "CRC OK CCK/ OFDM/ HT/ VHT",
4144                   dm_info->cck_ok_cnt, dm_info->ofdm_ok_cnt,
4145                   dm_info->ht_ok_cnt, dm_info->vht_ok_cnt);
4146        seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",
4147                   "CRC ERR CCK/ OFDM/ HT/ VHT",
4148                   dm_info->cck_err_cnt, dm_info->ofdm_err_cnt,
4149                   dm_info->ht_err_cnt, dm_info->vht_err_cnt);
4150        seq_printf(m, "%-40s = %s/ %s/ %s/ %u\n",
4151                   "HiPr/ Locking/ Locked/ Noisy",
4152                   coex_stat->wl_hi_pri_task1 ? "Y" : "N",
4153                   coex_stat->wl_cck_lock ? "Y" : "N",
4154                   coex_stat->wl_cck_lock_ever ? "Y" : "N",
4155                   coex_stat->wl_noisy_level);
4156
4157        rtw_coex_set_coexinfo_hw(rtwdev, m);
4158        seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n",
4159                   "EVM A/ EVM B/ SNR A/ SNR B",
4160                   -dm_info->rx_evm_dbm[RF_PATH_A],
4161                   -dm_info->rx_evm_dbm[RF_PATH_B],
4162                   -dm_info->rx_snr[RF_PATH_A],
4163                   -dm_info->rx_snr[RF_PATH_B]);
4164        seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n",
4165                   "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA",
4166                   dm_info->cck_cca_cnt, dm_info->cck_fa_cnt,
4167                   dm_info->ofdm_cca_cnt, dm_info->ofdm_fa_cnt);
4168        seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n", "CRC OK CCK/11g/11n/11ac",
4169                   dm_info->cck_ok_cnt, dm_info->ofdm_ok_cnt,
4170                   dm_info->ht_ok_cnt, dm_info->vht_ok_cnt);
4171        seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n", "CRC Err CCK/11g/11n/11ac",
4172                   dm_info->cck_err_cnt, dm_info->ofdm_err_cnt,
4173                   dm_info->ht_err_cnt, dm_info->vht_err_cnt);
4174
4175}
4176#endif /* CONFIG_RTW88_DEBUGFS */
4177