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
  12static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state,
  13                                   u8 rssi, u8 rssi_thresh)
  14{
  15        struct rtw_chip_info *chip = rtwdev->chip;
  16        u8 tol = chip->rssi_tolerance;
  17        u8 next_state;
  18
  19        if (pre_state == COEX_RSSI_STATE_LOW ||
  20            pre_state == COEX_RSSI_STATE_STAY_LOW) {
  21                if (rssi >= (rssi_thresh + tol))
  22                        next_state = COEX_RSSI_STATE_HIGH;
  23                else
  24                        next_state = COEX_RSSI_STATE_STAY_LOW;
  25        } else {
  26                if (rssi < rssi_thresh)
  27                        next_state = COEX_RSSI_STATE_LOW;
  28                else
  29                        next_state = COEX_RSSI_STATE_STAY_HIGH;
  30        }
  31
  32        return next_state;
  33}
  34
  35static void rtw_coex_limited_tx(struct rtw_dev *rtwdev,
  36                                bool tx_limit_en, bool ampdu_limit_en)
  37{
  38        struct rtw_chip_info *chip = rtwdev->chip;
  39        struct rtw_coex *coex = &rtwdev->coex;
  40        struct rtw_coex_stat *coex_stat = &coex->stat;
  41        bool wifi_under_b_mode = false;
  42
  43        if (!chip->scbd_support)
  44                return;
  45
  46        /* force max tx retry limit = 8 */
  47        if (coex_stat->wl_tx_limit_en == tx_limit_en &&
  48            coex_stat->wl_ampdu_limit_en == ampdu_limit_en)
  49                return;
  50
  51        if (!coex_stat->wl_tx_limit_en) {
  52                coex_stat->darfrc = rtw_read32(rtwdev, REG_DARFRC);
  53                coex_stat->darfrch = rtw_read32(rtwdev, REG_DARFRCH);
  54                coex_stat->retry_limit = rtw_read16(rtwdev, REG_RETRY_LIMIT);
  55        }
  56
  57        if (!coex_stat->wl_ampdu_limit_en)
  58                coex_stat->ampdu_max_time =
  59                                rtw_read8(rtwdev, REG_AMPDU_MAX_TIME_V1);
  60
  61        coex_stat->wl_tx_limit_en = tx_limit_en;
  62        coex_stat->wl_ampdu_limit_en = ampdu_limit_en;
  63
  64        if (tx_limit_en) {
  65                /* set BT polluted packet on for tx rate adaptive,
  66                 * not including tx retry broken by PTA
  67                 */
  68                rtw_write8_set(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);
  69
  70                /* set queue life time to avoid can't reach tx retry limit
  71                 * if tx is always broken by GNT_BT
  72                 */
  73                rtw_write8_set(rtwdev, REG_LIFETIME_EN, 0xf);
  74                rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x0808);
  75
  76                /* auto rate fallback step within 8 retries */
  77                if (wifi_under_b_mode) {
  78                        rtw_write32(rtwdev, REG_DARFRC, 0x1000000);
  79                        rtw_write32(rtwdev, REG_DARFRCH, 0x1010101);
  80                } else {
  81                        rtw_write32(rtwdev, REG_DARFRC, 0x1000000);
  82                        rtw_write32(rtwdev, REG_DARFRCH, 0x4030201);
  83                }
  84        } else {
  85                rtw_write8_clr(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);
  86                rtw_write8_clr(rtwdev, REG_LIFETIME_EN, 0xf);
  87
  88                rtw_write16(rtwdev, REG_RETRY_LIMIT, coex_stat->retry_limit);
  89                rtw_write32(rtwdev, REG_DARFRC, coex_stat->darfrc);
  90                rtw_write32(rtwdev, REG_DARFRCH, coex_stat->darfrch);
  91        }
  92
  93        if (ampdu_limit_en)
  94                rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, 0x20);
  95        else
  96                rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1,
  97                           coex_stat->ampdu_max_time);
  98}
  99
 100static void rtw_coex_limited_wl(struct rtw_dev *rtwdev)
 101{
 102        struct rtw_coex *coex = &rtwdev->coex;
 103        struct rtw_coex_dm *coex_dm = &coex->dm;
 104        struct rtw_coex_stat *coex_stat = &coex->stat;
 105        bool tx_limit = false;
 106        bool tx_agg_ctrl = false;
 107
 108        if (coex->under_5g ||
 109            coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
 110                /* no need to limit tx */
 111        } else {
 112                tx_limit = true;
 113                if (coex_stat->bt_hid_exist || coex_stat->bt_hfp_exist ||
 114                    coex_stat->bt_hid_pair_num > 0)
 115                        tx_agg_ctrl = true;
 116        }
 117
 118        rtw_coex_limited_tx(rtwdev, tx_limit, tx_agg_ctrl);
 119}
 120
 121static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev)
 122{
 123        struct rtw_coex *coex = &rtwdev->coex;
 124        struct rtw_coex_stat *coex_stat = &coex->stat;
 125        u8 para[6] = {0};
 126
 127        if (coex->stop_dm)
 128                return;
 129
 130        para[0] = COEX_H2C69_WL_LEAKAP;
 131
 132        if (coex_stat->tdma_timer_base == 3 && coex_stat->wl_slot_extend) {
 133                para[1] = PARA1_H2C69_DIS_5MS; /* disable 5ms extend */
 134                rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
 135                coex_stat->wl_slot_extend = false;
 136                coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
 137                return;
 138        }
 139
 140        if (coex_stat->wl_slot_extend && coex_stat->wl_force_lps_ctrl &&
 141            !coex_stat->wl_cck_lock_ever) {
 142                if (coex_stat->wl_fw_dbg_info[7] <= 5)
 143                        coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]++;
 144                else
 145                        coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
 146
 147                if (coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] == 7) {
 148                        para[1] = 0x1; /* disable 5ms extend */
 149                        rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
 150                        coex_stat->wl_slot_extend = false;
 151                        coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
 152                }
 153        } else if (!coex_stat->wl_slot_extend && coex_stat->wl_cck_lock) {
 154                para[1] = 0x0; /* enable 5ms extend */
 155                rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
 156                coex_stat->wl_slot_extend = true;
 157        }
 158}
 159
 160static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev)
 161{
 162        struct rtw_coex *coex = &rtwdev->coex;
 163        struct rtw_coex_stat *coex_stat = &coex->stat;
 164
 165        /* TODO: wait for rx_rate_change_notify implement */
 166        coex_stat->wl_cck_lock = false;
 167        coex_stat->wl_cck_lock_pre = false;
 168        coex_stat->wl_cck_lock_ever = false;
 169}
 170
 171static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev)
 172{
 173        struct rtw_coex *coex = &rtwdev->coex;
 174        struct rtw_coex_stat *coex_stat = &coex->stat;
 175        struct rtw_dm_info *dm_info = &rtwdev->dm_info;
 176        u32 cnt_cck;
 177
 178        /* wifi noisy environment identification */
 179        cnt_cck = dm_info->cck_ok_cnt + dm_info->cck_err_cnt;
 180
 181        if (!coex_stat->wl_gl_busy) {
 182                if (cnt_cck > 250) {
 183                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] < 5)
 184                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY2]++;
 185
 186                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5) {
 187                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0;
 188                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0;
 189                        }
 190                } else if (cnt_cck < 100) {
 191                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] < 5)
 192                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY0]++;
 193
 194                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] == 5) {
 195                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0;
 196                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0;
 197                        }
 198                } else {
 199                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] < 5)
 200                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY1]++;
 201
 202                        if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5) {
 203                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0;
 204                                coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0;
 205                        }
 206                }
 207
 208                if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5)
 209                        coex_stat->wl_noisy_level = 2;
 210                else if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5)
 211                        coex_stat->wl_noisy_level = 1;
 212                else
 213                        coex_stat->wl_noisy_level = 0;
 214        }
 215}
 216
 217static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type)
 218{
 219        struct rtw_coex *coex = &rtwdev->coex;
 220        struct rtw_coex_stat *coex_stat = &coex->stat;
 221        u8 para[2] = {0};
 222
 223        if (coex_stat->tdma_timer_base == type)
 224                return;
 225
 226        coex_stat->tdma_timer_base = type;
 227
 228        para[0] = COEX_H2C69_TDMA_SLOT;
 229
 230        if (type == 3) /* 4-slot  */
 231                para[1] = PARA1_H2C69_TDMA_4SLOT; /* 4-slot */
 232        else /* 2-slot  */
 233                para[1] = PARA1_H2C69_TDMA_2SLOT;
 234
 235        rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
 236
 237        /* no 5ms_wl_slot_extend for 4-slot mode  */
 238        if (coex_stat->tdma_timer_base == 3)
 239                rtw_coex_wl_ccklock_action(rtwdev);
 240}
 241
 242static void rtw_coex_set_wl_pri_mask(struct rtw_dev *rtwdev, u8 bitmap,
 243                                     u8 data)
 244{
 245        u32 addr;
 246
 247        addr = REG_BT_COEX_TABLE_H + (bitmap / 8);
 248        bitmap = bitmap % 8;
 249
 250        rtw_write8_mask(rtwdev, addr, BIT(bitmap), data);
 251}
 252
 253void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set)
 254{
 255        struct rtw_chip_info *chip = rtwdev->chip;
 256        struct rtw_coex *coex = &rtwdev->coex;
 257        struct rtw_coex_stat *coex_stat = &coex->stat;
 258        u16 val = 0x2;
 259
 260        if (!chip->scbd_support)
 261                return;
 262
 263        val |= coex_stat->score_board;
 264
 265        /* for 8822b, scbd[10] is CQDDR on
 266         * for 8822c, scbd[10] is no fix 2M
 267         */
 268        if (!chip->new_scbd10_def && (bitpos & COEX_SCBD_FIX2M)) {
 269                if (set)
 270                        val &= ~COEX_SCBD_FIX2M;
 271                else
 272                        val |= COEX_SCBD_FIX2M;
 273        } else {
 274                if (set)
 275                        val |= bitpos;
 276                else
 277                        val &= ~bitpos;
 278        }
 279
 280        if (val != coex_stat->score_board) {
 281                coex_stat->score_board = val;
 282                val |= BIT_BT_INT_EN;
 283                rtw_write16(rtwdev, REG_WIFI_BT_INFO, val);
 284        }
 285}
 286EXPORT_SYMBOL(rtw_coex_write_scbd);
 287
 288static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev)
 289{
 290        struct rtw_chip_info *chip = rtwdev->chip;
 291
 292        if (!chip->scbd_support)
 293                return 0;
 294
 295        return (rtw_read16(rtwdev, REG_WIFI_BT_INFO)) & ~(BIT_BT_INT_EN);
 296}
 297
 298static void rtw_coex_check_rfk(struct rtw_dev *rtwdev)
 299{
 300        struct rtw_chip_info *chip = rtwdev->chip;
 301        struct rtw_coex *coex = &rtwdev->coex;
 302        struct rtw_coex_stat *coex_stat = &coex->stat;
 303        struct rtw_coex_rfe *coex_rfe = &coex->rfe;
 304        u8 cnt = 0;
 305        u32 wait_cnt;
 306        bool btk, wlk;
 307
 308        if (coex_rfe->wlg_at_btg && chip->scbd_support &&
 309            coex_stat->bt_iqk_state != 0xff) {
 310                wait_cnt = COEX_RFK_TIMEOUT / COEX_MIN_DELAY;
 311                do {
 312                        /* BT RFK */
 313                        btk = !!(rtw_coex_read_scbd(rtwdev) & COEX_SCBD_BT_RFK);
 314
 315                        /* WL RFK */
 316                        wlk = !!(rtw_read8(rtwdev, REG_ARFR4) & BIT_WL_RFK);
 317
 318                        if (!btk && !wlk)
 319                                break;
 320
 321                        mdelay(COEX_MIN_DELAY);
 322                } while (++cnt < wait_cnt);
 323
 324                if (cnt >= wait_cnt)
 325                        coex_stat->bt_iqk_state = 0xff;
 326        }
 327}
 328
 329static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev)
 330{
 331        struct rtw_coex *coex = &rtwdev->coex;
 332        struct rtw_coex_stat *coex_stat = &coex->stat;
 333
 334        if (coex_stat->bt_disabled)
 335                return;
 336
 337        rtw_fw_query_bt_info(rtwdev);
 338}
 339
 340static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
 341{
 342        struct rtw_chip_info *chip = rtwdev->chip;
 343        struct rtw_coex *coex = &rtwdev->coex;
 344        struct rtw_coex_stat *coex_stat = &coex->stat;
 345        struct rtw_coex_dm *coex_dm = &coex->dm;
 346        bool bt_disabled = false;
 347        u16 score_board;
 348
 349        if (chip->scbd_support) {
 350                score_board = rtw_coex_read_scbd(rtwdev);
 351                bt_disabled = !(score_board & COEX_SCBD_ONOFF);
 352        }
 353
 354        if (coex_stat->bt_disabled != bt_disabled) {
 355                rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: BT state changed (%d) -> (%d)\n",
 356                        coex_stat->bt_disabled, bt_disabled);
 357
 358                coex_stat->bt_disabled = bt_disabled;
 359                coex_stat->bt_ble_scan_type = 0;
 360                coex_dm->cur_bt_lna_lvl = 0;
 361        }
 362
 363        if (!coex_stat->bt_disabled) {
 364                coex_stat->bt_reenable = true;
 365                ieee80211_queue_delayed_work(rtwdev->hw,
 366                                             &coex->bt_reenable_work, 15 * HZ);
 367        } else {
 368                coex_stat->bt_mailbox_reply = false;
 369                coex_stat->bt_reenable = false;
 370        }
 371}
 372
 373static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason)
 374{
 375        struct rtw_coex *coex = &rtwdev->coex;
 376        struct rtw_coex_stat *coex_stat = &coex->stat;
 377        struct rtw_coex_dm *coex_dm = &coex->dm;
 378        struct rtw_chip_info *chip = rtwdev->chip;
 379        struct rtw_traffic_stats *stats = &rtwdev->stats;
 380        bool is_5G = false;
 381        bool wl_busy = false;
 382        bool scan = false, link = false;
 383        int i;
 384        u8 rssi_state;
 385        u8 rssi_step;
 386        u8 rssi;
 387
 388        scan = test_bit(RTW_FLAG_SCANNING, rtwdev->flags);
 389        coex_stat->wl_connected = !!rtwdev->sta_cnt;
 390
 391        wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
 392        if (wl_busy != coex_stat->wl_gl_busy) {
 393                if (wl_busy)
 394                        coex_stat->wl_gl_busy = true;
 395                else
 396                        ieee80211_queue_delayed_work(rtwdev->hw,
 397                                                     &coex->wl_remain_work,
 398                                                     12 * HZ);
 399        }
 400
 401        if (stats->tx_throughput > stats->rx_throughput)
 402                coex_stat->wl_tput_dir = COEX_WL_TPUT_TX;
 403        else
 404                coex_stat->wl_tput_dir = COEX_WL_TPUT_RX;
 405
 406        if (scan || link || reason == COEX_RSN_2GCONSTART ||
 407            reason == COEX_RSN_2GSCANSTART || reason == COEX_RSN_2GSWITCHBAND)
 408                coex_stat->wl_linkscan_proc = true;
 409        else
 410                coex_stat->wl_linkscan_proc = false;
 411
 412        rtw_coex_wl_noisy_detect(rtwdev);
 413
 414        for (i = 0; i < 4; i++) {
 415                rssi_state = coex_dm->wl_rssi_state[i];
 416                rssi_step = chip->wl_rssi_step[i];
 417                rssi = rtwdev->dm_info.min_rssi;
 418                rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
 419                                                      rssi, rssi_step);
 420                coex_dm->wl_rssi_state[i] = rssi_state;
 421        }
 422
 423        switch (reason) {
 424        case COEX_RSN_5GSCANSTART:
 425        case COEX_RSN_5GSWITCHBAND:
 426        case COEX_RSN_5GCONSTART:
 427
 428                is_5G = true;
 429                break;
 430        case COEX_RSN_2GSCANSTART:
 431        case COEX_RSN_2GSWITCHBAND:
 432        case COEX_RSN_2GCONSTART:
 433
 434                is_5G = false;
 435                break;
 436        default:
 437                if (rtwdev->hal.current_band_type == RTW_BAND_5G)
 438                        is_5G = true;
 439                else
 440                        is_5G = false;
 441                break;
 442        }
 443
 444        coex->under_5g = is_5G;
 445}
 446
 447static inline u8 *get_payload_from_coex_resp(struct sk_buff *resp)
 448{
 449        struct rtw_c2h_cmd *c2h;
 450        u32 pkt_offset;
 451
 452        pkt_offset = *((u32 *)resp->cb);
 453        c2h = (struct rtw_c2h_cmd *)(resp->data + pkt_offset);
 454
 455        return c2h->payload;
 456}
 457
 458void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb)
 459{
 460        struct rtw_coex *coex = &rtwdev->coex;
 461        u8 *payload = get_payload_from_coex_resp(skb);
 462
 463        if (payload[0] != COEX_RESP_ACK_BY_WL_FW)
 464                return;
 465
 466        skb_queue_tail(&coex->queue, skb);
 467        wake_up(&coex->wait);
 468}
 469
 470static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,
 471                                             struct rtw_coex_info_req *req)
 472{
 473        struct rtw_coex *coex = &rtwdev->coex;
 474        struct sk_buff *skb_resp = NULL;
 475
 476        mutex_lock(&coex->mutex);
 477
 478        rtw_fw_query_bt_mp_info(rtwdev, req);
 479
 480        if (!wait_event_timeout(coex->wait, !skb_queue_empty(&coex->queue),
 481                                COEX_REQUEST_TIMEOUT)) {
 482                rtw_err(rtwdev, "coex request time out\n");
 483                goto out;
 484        }
 485
 486        skb_resp = skb_dequeue(&coex->queue);
 487        if (!skb_resp) {
 488                rtw_err(rtwdev, "failed to get coex info response\n");
 489                goto out;
 490        }
 491
 492out:
 493        mutex_unlock(&coex->mutex);
 494        return skb_resp;
 495}
 496
 497static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type)
 498{
 499        struct rtw_coex_info_req req = {0};
 500        struct sk_buff *skb;
 501        u8 *payload;
 502        bool ret = false;
 503
 504        req.op_code = BT_MP_INFO_OP_SCAN_TYPE;
 505        skb = rtw_coex_info_request(rtwdev, &req);
 506        if (!skb)
 507                goto out;
 508
 509        payload = get_payload_from_coex_resp(skb);
 510        *scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload);
 511        dev_kfree_skb_any(skb);
 512        ret = true;
 513
 514out:
 515        return ret;
 516}
 517
 518static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev,
 519                                             u8 lna_constrain_level)
 520{
 521        struct rtw_coex_info_req req = {0};
 522        struct sk_buff *skb;
 523        bool ret = false;
 524
 525        req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT;
 526        req.para1 = lna_constrain_level;
 527        skb = rtw_coex_info_request(rtwdev, &req);
 528        if (!skb)
 529                goto out;
 530
 531        dev_kfree_skb_any(skb);
 532        ret = true;
 533
 534out:
 535        return ret;
 536}
 537
 538static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
 539{
 540        struct rtw_coex *coex = &rtwdev->coex;
 541        struct rtw_coex_stat *coex_stat = &coex->stat;
 542        struct rtw_coex_dm *coex_dm = &coex->dm;
 543        struct rtw_chip_info *chip = rtwdev->chip;
 544        u8 i;
 545        u8 rssi_state;
 546        u8 rssi_step;
 547        u8 rssi;
 548
 549        /* update wl/bt rssi by btinfo */
 550        for (i = 0; i < COEX_RSSI_STEP; i++) {
 551                rssi_state = coex_dm->bt_rssi_state[i];
 552                rssi_step = chip->bt_rssi_step[i];
 553                rssi = coex_stat->bt_rssi;
 554                rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
 555                                                      rssi, rssi_step);
 556                coex_dm->bt_rssi_state[i] = rssi_state;
 557        }
 558
 559        for (i = 0; i < COEX_RSSI_STEP; i++) {
 560                rssi_state = coex_dm->wl_rssi_state[i];
 561                rssi_step = chip->wl_rssi_step[i];
 562                rssi = rtwdev->dm_info.min_rssi;
 563                rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
 564                                                      rssi, rssi_step);
 565                coex_dm->wl_rssi_state[i] = rssi_state;
 566        }
 567
 568        if (coex_stat->bt_ble_scan_en &&
 569            coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE] % 3 == 0) {
 570                u8 scan_type;
 571
 572                if (rtw_coex_get_bt_scan_type(rtwdev, &scan_type)) {
 573                        coex_stat->bt_ble_scan_type = scan_type;
 574                        if ((coex_stat->bt_ble_scan_type & 0x1) == 0x1)
 575                                coex_stat->bt_init_scan = true;
 576                        else
 577                                coex_stat->bt_init_scan = false;
 578                }
 579        }
 580
 581        coex_stat->bt_profile_num = 0;
 582
 583        /* set link exist status */
 584        if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {
 585                coex_stat->bt_link_exist = false;
 586                coex_stat->bt_pan_exist = false;
 587                coex_stat->bt_a2dp_exist = false;
 588                coex_stat->bt_hid_exist = false;
 589                coex_stat->bt_hfp_exist = false;
 590        } else {
 591                /* connection exists */
 592                coex_stat->bt_link_exist = true;
 593                if (coex_stat->bt_info_lb2 & COEX_INFO_FTP) {
 594                        coex_stat->bt_pan_exist = true;
 595                        coex_stat->bt_profile_num++;
 596                } else {
 597                        coex_stat->bt_pan_exist = false;
 598                }
 599
 600                if (coex_stat->bt_info_lb2 & COEX_INFO_A2DP) {
 601                        coex_stat->bt_a2dp_exist = true;
 602                        coex_stat->bt_profile_num++;
 603                } else {
 604                        coex_stat->bt_a2dp_exist = false;
 605                }
 606
 607                if (coex_stat->bt_info_lb2 & COEX_INFO_HID) {
 608                        coex_stat->bt_hid_exist = true;
 609                        coex_stat->bt_profile_num++;
 610                } else {
 611                        coex_stat->bt_hid_exist = false;
 612                }
 613
 614                if (coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) {
 615                        coex_stat->bt_hfp_exist = true;
 616                        coex_stat->bt_profile_num++;
 617                } else {
 618                        coex_stat->bt_hfp_exist = false;
 619                }
 620        }
 621
 622        if (coex_stat->bt_info_lb2 & COEX_INFO_INQ_PAGE) {
 623                coex_dm->bt_status = COEX_BTSTATUS_INQ_PAGE;
 624        } else if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {
 625                coex_dm->bt_status = COEX_BTSTATUS_NCON_IDLE;
 626        } else if (coex_stat->bt_info_lb2 == COEX_INFO_CONNECTION) {
 627                coex_dm->bt_status = COEX_BTSTATUS_CON_IDLE;
 628        } else if ((coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) ||
 629                   (coex_stat->bt_info_lb2 & COEX_INFO_SCO_BUSY)) {
 630                if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY)
 631                        coex_dm->bt_status = COEX_BTSTATUS_ACL_SCO_BUSY;
 632                else
 633                        coex_dm->bt_status = COEX_BTSTATUS_SCO_BUSY;
 634        } else if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY) {
 635                coex_dm->bt_status = COEX_BTSTATUS_ACL_BUSY;
 636        } else {
 637                coex_dm->bt_status = COEX_BTSTATUS_MAX;
 638        }
 639
 640        coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE]++;
 641
 642        rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: bt status(%d)\n", coex_dm->bt_status);
 643}
 644
 645static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
 646{
 647        struct rtw_chip_info *chip = rtwdev->chip;
 648        struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm;
 649        struct rtw_efuse *efuse = &rtwdev->efuse;
 650        u8 link = 0;
 651        u8 center_chan = 0;
 652        u8 bw;
 653        int i;
 654
 655        bw = rtwdev->hal.current_band_width;
 656
 657        if (type != COEX_MEDIA_DISCONNECT)
 658                center_chan = rtwdev->hal.current_channel;
 659
 660        if (center_chan == 0 || (efuse->share_ant && center_chan <= 14)) {
 661                link = 0;
 662        } else if (center_chan <= 14) {
 663                link = 0x1;
 664
 665                if (bw == RTW_CHANNEL_WIDTH_40)
 666                        bw = chip->bt_afh_span_bw40;
 667                else
 668                        bw = chip->bt_afh_span_bw20;
 669        } else if (chip->afh_5g_num > 1) {
 670                for (i = 0; i < chip->afh_5g_num; i++) {
 671                        if (center_chan == chip->afh_5g[i].wl_5g_ch) {
 672                                link = 0x3;
 673                                center_chan = chip->afh_5g[i].bt_skip_ch;
 674                                bw = chip->afh_5g[i].bt_skip_span;
 675                                break;
 676                        }
 677                }
 678        }
 679
 680        coex_dm->wl_ch_info[0] = link;
 681        coex_dm->wl_ch_info[1] = center_chan;
 682        coex_dm->wl_ch_info[2] = bw;
 683
 684        rtw_fw_wl_ch_info(rtwdev, link, center_chan, bw);
 685}
 686
 687static void rtw_coex_set_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl)
 688{
 689        struct rtw_coex *coex = &rtwdev->coex;
 690        struct rtw_coex_dm *coex_dm = &coex->dm;
 691
 692        if (bt_pwr_dec_lvl == coex_dm->cur_bt_pwr_lvl)
 693                return;
 694
 695        coex_dm->cur_bt_pwr_lvl = bt_pwr_dec_lvl;
 696
 697        rtw_fw_force_bt_tx_power(rtwdev, bt_pwr_dec_lvl);
 698}
 699
 700static void rtw_coex_set_bt_rx_gain(struct rtw_dev *rtwdev, u8 bt_lna_lvl)
 701{
 702        struct rtw_coex *coex = &rtwdev->coex;
 703        struct rtw_coex_dm *coex_dm = &coex->dm;
 704
 705        if (bt_lna_lvl == coex_dm->cur_bt_lna_lvl)
 706                return;
 707
 708        coex_dm->cur_bt_lna_lvl = bt_lna_lvl;
 709
 710        /* notify BT rx gain table changed */
 711        if (bt_lna_lvl < 7) {
 712                rtw_coex_set_lna_constrain_level(rtwdev, bt_lna_lvl);
 713                rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, true);
 714        } else {
 715                rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, false);
 716        }
 717}
 718
 719static void rtw_coex_set_rf_para(struct rtw_dev *rtwdev,
 720                                 struct coex_rf_para para)
 721{
 722        struct rtw_coex *coex = &rtwdev->coex;
 723        struct rtw_coex_stat *coex_stat = &coex->stat;
 724        u8 offset = 0;
 725
 726        if (coex->freerun && coex_stat->wl_noisy_level <= 1)
 727                offset = 3;
 728
 729        rtw_coex_set_wl_tx_power(rtwdev, para.wl_pwr_dec_lvl);
 730        rtw_coex_set_bt_tx_power(rtwdev, para.bt_pwr_dec_lvl + offset);
 731        rtw_coex_set_wl_rx_gain(rtwdev, para.wl_low_gain_en);
 732        rtw_coex_set_bt_rx_gain(rtwdev, para.bt_lna_lvl);
 733}
 734
 735u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr)
 736{
 737        u32 val;
 738
 739        if (!ltecoex_read_reg(rtwdev, addr, &val)) {
 740                rtw_err(rtwdev, "failed to read indirect register\n");
 741                return 0;
 742        }
 743
 744        return val;
 745}
 746EXPORT_SYMBOL(rtw_coex_read_indirect_reg);
 747
 748void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr,
 749                                 u32 mask, u32 val)
 750{
 751        u32 shift = __ffs(mask);
 752        u32 tmp;
 753
 754        tmp = rtw_coex_read_indirect_reg(rtwdev, addr);
 755        tmp = (tmp & (~mask)) | ((val << shift) & mask);
 756
 757        if (!ltecoex_reg_write(rtwdev, addr, tmp))
 758                rtw_err(rtwdev, "failed to write indirect register\n");
 759}
 760EXPORT_SYMBOL(rtw_coex_write_indirect_reg);
 761
 762static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control)
 763{
 764        struct rtw_chip_info *chip = rtwdev->chip;
 765        const struct rtw_hw_reg *btg_reg = chip->btg_reg;
 766
 767        if (wifi_control) {
 768                rtw_write32_set(rtwdev, REG_SYS_SDIO_CTRL, BIT_LTE_MUX_CTRL_PATH);
 769                if (btg_reg)
 770                        rtw_write8_set(rtwdev, btg_reg->addr, btg_reg->mask);
 771        } else {
 772                rtw_write32_clr(rtwdev, REG_SYS_SDIO_CTRL, BIT_LTE_MUX_CTRL_PATH);
 773                if (btg_reg)
 774                        rtw_write8_clr(rtwdev, btg_reg->addr, btg_reg->mask);
 775        }
 776}
 777
 778static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state)
 779{
 780        rtw_coex_write_indirect_reg(rtwdev, 0x38, 0xc000, state);
 781        rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x0c00, state);
 782}
 783
 784static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state)
 785{
 786        rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x3000, state);
 787        rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x0300, state);
 788}
 789
 790static void rtw_coex_set_table(struct rtw_dev *rtwdev, u32 table0, u32 table1)
 791{
 792#define DEF_BRK_TABLE_VAL       0xf0ffffff
 793        rtw_write32(rtwdev, REG_BT_COEX_TABLE0, table0);
 794        rtw_write32(rtwdev, REG_BT_COEX_TABLE1, table1);
 795        rtw_write32(rtwdev, REG_BT_COEX_BRK_TABLE, DEF_BRK_TABLE_VAL);
 796}
 797
 798static void rtw_coex_table(struct rtw_dev *rtwdev, u8 type)
 799{
 800        struct rtw_coex *coex = &rtwdev->coex;
 801        struct rtw_coex_dm *coex_dm = &coex->dm;
 802        struct rtw_chip_info *chip = rtwdev->chip;
 803        struct rtw_efuse *efuse = &rtwdev->efuse;
 804
 805        coex_dm->cur_table = type;
 806
 807        if (efuse->share_ant) {
 808                if (type < chip->table_sant_num)
 809                        rtw_coex_set_table(rtwdev,
 810                                           chip->table_sant[type].bt,
 811                                           chip->table_sant[type].wl);
 812        } else {
 813                type = type - 100;
 814                if (type < chip->table_nsant_num)
 815                        rtw_coex_set_table(rtwdev,
 816                                           chip->table_nsant[type].bt,
 817                                           chip->table_nsant[type].wl);
 818        }
 819}
 820
 821static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable)
 822{
 823        struct rtw_coex *coex = &rtwdev->coex;
 824
 825        if (coex->stop_dm)
 826                return;
 827
 828        rtw_fw_bt_ignore_wlan_action(rtwdev, enable);
 829}
 830
 831static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type,
 832                                      u8 lps_val, u8 rpwm_val)
 833{
 834        struct rtw_coex *coex = &rtwdev->coex;
 835        struct rtw_coex_stat *coex_stat = &coex->stat;
 836        u8 lps_mode = 0x0;
 837
 838        lps_mode = rtwdev->lps_conf.mode;
 839
 840        switch (ps_type) {
 841        case COEX_PS_WIFI_NATIVE:
 842                /* recover to original 32k low power setting */
 843                coex_stat->wl_force_lps_ctrl = false;
 844
 845                rtw_leave_lps(rtwdev);
 846                break;
 847        case COEX_PS_LPS_OFF:
 848                coex_stat->wl_force_lps_ctrl = true;
 849                if (lps_mode)
 850                        rtw_fw_coex_tdma_type(rtwdev, 0x8, 0, 0, 0, 0);
 851
 852                rtw_leave_lps(rtwdev);
 853                break;
 854        default:
 855                break;
 856        }
 857}
 858
 859static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
 860                              u8 byte3, u8 byte4, u8 byte5)
 861{
 862        struct rtw_coex *coex = &rtwdev->coex;
 863        struct rtw_coex_dm *coex_dm = &coex->dm;
 864        struct rtw_chip_info *chip = rtwdev->chip;
 865        u8 ps_type = COEX_PS_WIFI_NATIVE;
 866        bool ap_enable = false;
 867
 868        if (ap_enable && (byte1 & BIT(4) && !(byte1 & BIT(5)))) {
 869                byte1 &= ~BIT(4);
 870                byte1 |= BIT(5);
 871
 872                byte5 |= BIT(5);
 873                byte5 &= ~BIT(6);
 874
 875                ps_type = COEX_PS_WIFI_NATIVE;
 876                rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
 877        } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) {
 878                if (chip->pstdma_type == COEX_PSTDMA_FORCE_LPSOFF)
 879                        ps_type = COEX_PS_LPS_OFF;
 880                else
 881                        ps_type = COEX_PS_LPS_ON;
 882                rtw_coex_power_save_state(rtwdev, ps_type, 0x50, 0x4);
 883        } else {
 884                ps_type = COEX_PS_WIFI_NATIVE;
 885                rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
 886        }
 887
 888        coex_dm->ps_tdma_para[0] = byte1;
 889        coex_dm->ps_tdma_para[1] = byte2;
 890        coex_dm->ps_tdma_para[2] = byte3;
 891        coex_dm->ps_tdma_para[3] = byte4;
 892        coex_dm->ps_tdma_para[4] = byte5;
 893
 894        rtw_fw_coex_tdma_type(rtwdev, byte1, byte2, byte3, byte4, byte5);
 895}
 896
 897static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)
 898{
 899        struct rtw_coex *coex = &rtwdev->coex;
 900        struct rtw_coex_dm *coex_dm = &coex->dm;
 901        struct rtw_coex_stat *coex_stat = &coex->stat;
 902        struct rtw_chip_info *chip = rtwdev->chip;
 903        struct rtw_efuse *efuse = &rtwdev->efuse;
 904        u8 n, type;
 905        bool turn_on;
 906        bool wl_busy = false;
 907
 908        if (tcase & TDMA_4SLOT)/* 4-slot (50ms) mode */
 909                rtw_coex_tdma_timer_base(rtwdev, 3);
 910        else
 911                rtw_coex_tdma_timer_base(rtwdev, 0);
 912
 913        type = (u8)(tcase & 0xff);
 914
 915        turn_on = (type == 0 || type == 100) ? false : true;
 916
 917        if (!force) {
 918                if (turn_on == coex_dm->cur_ps_tdma_on &&
 919                    type == coex_dm->cur_ps_tdma) {
 920                        return;
 921                }
 922        }
 923
 924        /* enable TBTT interrupt */
 925        if (turn_on)
 926                rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
 927
 928        wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
 929
 930        if ((coex_stat->bt_a2dp_exist &&
 931             (coex_stat->bt_inq_remain || coex_stat->bt_multi_link)) ||
 932            !wl_busy)
 933                rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, false);
 934        else
 935                rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true);
 936
 937        if (efuse->share_ant) {
 938                if (type < chip->tdma_sant_num)
 939                        rtw_coex_set_tdma(rtwdev,
 940                                          chip->tdma_sant[type].para[0],
 941                                          chip->tdma_sant[type].para[1],
 942                                          chip->tdma_sant[type].para[2],
 943                                          chip->tdma_sant[type].para[3],
 944                                          chip->tdma_sant[type].para[4]);
 945        } else {
 946                n = type - 100;
 947                if (n < chip->tdma_nsant_num)
 948                        rtw_coex_set_tdma(rtwdev,
 949                                          chip->tdma_nsant[n].para[0],
 950                                          chip->tdma_nsant[n].para[1],
 951                                          chip->tdma_nsant[n].para[2],
 952                                          chip->tdma_nsant[n].para[3],
 953                                          chip->tdma_nsant[n].para[4]);
 954        }
 955
 956        /* update pre state */
 957        coex_dm->cur_ps_tdma_on = turn_on;
 958        coex_dm->cur_ps_tdma = type;
 959
 960        rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: coex tdma type (%d)\n", type);
 961}
 962
 963static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
 964{
 965        struct rtw_coex *coex = &rtwdev->coex;
 966        struct rtw_coex_stat *coex_stat = &coex->stat;
 967        struct rtw_coex_dm *coex_dm = &coex->dm;
 968        u8 ctrl_type = COEX_SWITCH_CTRL_MAX;
 969        u8 pos_type = COEX_SWITCH_TO_MAX;
 970
 971        if (!force && coex_dm->cur_ant_pos_type == phase)
 972                return;
 973
 974        coex_dm->cur_ant_pos_type = phase;
 975
 976        /* avoid switch coex_ctrl_owner during BT IQK */
 977        rtw_coex_check_rfk(rtwdev);
 978
 979        switch (phase) {
 980        case COEX_SET_ANT_POWERON:
 981                /* set path control owner to BT at power-on */
 982                if (coex_stat->bt_disabled)
 983                        rtw_coex_coex_ctrl_owner(rtwdev, true);
 984                else
 985                        rtw_coex_coex_ctrl_owner(rtwdev, false);
 986
 987                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
 988                pos_type = COEX_SWITCH_TO_BT;
 989                break;
 990        case COEX_SET_ANT_INIT:
 991                if (coex_stat->bt_disabled) {
 992                        /* set GNT_BT to SW low */
 993                        rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);
 994
 995                        /* set GNT_WL to SW high */
 996                        rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
 997                } else {
 998                        /* set GNT_BT to SW high */
 999                        rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
1000
1001                        /* set GNT_WL to SW low */
1002                        rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_LOW);
1003                }
1004
1005                /* set path control owner to wl at initial step */
1006                rtw_coex_coex_ctrl_owner(rtwdev, true);
1007
1008                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1009                pos_type = COEX_SWITCH_TO_BT;
1010                break;
1011        case COEX_SET_ANT_WONLY:
1012                /* set GNT_BT to SW Low */
1013                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);
1014
1015                /* Set GNT_WL to SW high */
1016                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
1017
1018                /* set path control owner to wl at initial step */
1019                rtw_coex_coex_ctrl_owner(rtwdev, true);
1020
1021                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1022                pos_type = COEX_SWITCH_TO_WLG;
1023                break;
1024        case COEX_SET_ANT_WOFF:
1025                /* set path control owner to BT */
1026                rtw_coex_coex_ctrl_owner(rtwdev, false);
1027
1028                ctrl_type = COEX_SWITCH_CTRL_BY_BT;
1029                pos_type = COEX_SWITCH_TO_NOCARE;
1030                break;
1031        case COEX_SET_ANT_2G:
1032                /* set GNT_BT to PTA */
1033                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
1034
1035                /* set GNT_WL to PTA */
1036                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);
1037
1038                /* set path control owner to wl at runtime step */
1039                rtw_coex_coex_ctrl_owner(rtwdev, true);
1040
1041                ctrl_type = COEX_SWITCH_CTRL_BY_PTA;
1042                pos_type = COEX_SWITCH_TO_NOCARE;
1043                break;
1044        case COEX_SET_ANT_5G:
1045                /* set GNT_BT to PTA */
1046                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
1047
1048                /* set GNT_WL to SW high */
1049                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
1050
1051                /* set path control owner to wl at runtime step */
1052                rtw_coex_coex_ctrl_owner(rtwdev, true);
1053
1054                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1055                pos_type = COEX_SWITCH_TO_WLA;
1056                break;
1057        case COEX_SET_ANT_2G_FREERUN:
1058                /* set GNT_BT to SW high */
1059                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
1060
1061                /* Set GNT_WL to SW high */
1062                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
1063
1064                /* set path control owner to wl at runtime step */
1065                rtw_coex_coex_ctrl_owner(rtwdev, true);
1066
1067                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1068                pos_type = COEX_SWITCH_TO_WLG_BT;
1069                break;
1070        case COEX_SET_ANT_2G_WLBT:
1071                /* set GNT_BT to SW high */
1072                rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
1073
1074                /* Set GNT_WL to SW high */
1075                rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);
1076
1077                /* set path control owner to wl at runtime step */
1078                rtw_coex_coex_ctrl_owner(rtwdev, true);
1079
1080                ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
1081                pos_type = COEX_SWITCH_TO_WLG_BT;
1082                break;
1083        default:
1084                WARN(1, "unknown phase when setting antenna path\n");
1085                return;
1086        }
1087
1088        if (ctrl_type < COEX_SWITCH_CTRL_MAX && pos_type < COEX_SWITCH_TO_MAX)
1089                rtw_coex_set_ant_switch(rtwdev, ctrl_type, pos_type);
1090}
1091
1092static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev)
1093{
1094        struct rtw_coex *coex = &rtwdev->coex;
1095        struct rtw_coex_stat *coex_stat = &coex->stat;
1096        u8 algorithm = COEX_ALGO_NOPROFILE;
1097        u8 profile_map = 0;
1098
1099        if (coex_stat->bt_hfp_exist)
1100                profile_map |= BPM_HFP;
1101        if (coex_stat->bt_hid_exist)
1102                profile_map |= BPM_HID;
1103        if (coex_stat->bt_a2dp_exist)
1104                profile_map |= BPM_A2DP;
1105        if (coex_stat->bt_pan_exist)
1106                profile_map |= BPM_PAN;
1107
1108        switch (profile_map) {
1109        case BPM_HFP:
1110                algorithm = COEX_ALGO_HFP;
1111                break;
1112        case           BPM_HID:
1113        case BPM_HFP + BPM_HID:
1114                algorithm = COEX_ALGO_HID;
1115                break;
1116        case BPM_HFP           + BPM_A2DP:
1117        case           BPM_HID + BPM_A2DP:
1118        case BPM_HFP + BPM_HID + BPM_A2DP:
1119                algorithm = COEX_ALGO_A2DP_HID;
1120                break;
1121        case BPM_HFP                      + BPM_PAN:
1122        case           BPM_HID            + BPM_PAN:
1123        case BPM_HFP + BPM_HID            + BPM_PAN:
1124                algorithm = COEX_ALGO_PAN_HID;
1125                break;
1126        case BPM_HFP           + BPM_A2DP + BPM_PAN:
1127        case           BPM_HID + BPM_A2DP + BPM_PAN:
1128        case BPM_HFP + BPM_HID + BPM_A2DP + BPM_PAN:
1129                algorithm = COEX_ALGO_A2DP_PAN_HID;
1130                break;
1131        case                                BPM_PAN:
1132                algorithm = COEX_ALGO_PAN;
1133                break;
1134        case                     BPM_A2DP + BPM_PAN:
1135                algorithm = COEX_ALGO_A2DP_PAN;
1136                break;
1137        case                     BPM_A2DP:
1138                if (coex_stat->bt_multi_link) {
1139                        if (coex_stat->bt_hid_pair_num > 0)
1140                                algorithm = COEX_ALGO_A2DP_HID;
1141                        else
1142                                algorithm = COEX_ALGO_A2DP_PAN;
1143                } else {
1144                        algorithm = COEX_ALGO_A2DP;
1145                }
1146                break;
1147        default:
1148                algorithm = COEX_ALGO_NOPROFILE;
1149                break;
1150        }
1151
1152        return algorithm;
1153}
1154
1155static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev)
1156{
1157        struct rtw_efuse *efuse = &rtwdev->efuse;
1158        struct rtw_chip_info *chip = rtwdev->chip;
1159        u8 table_case, tdma_case;
1160
1161        if (efuse->share_ant) {
1162                /* Shared-Ant */
1163                table_case = 2;
1164                tdma_case = 0;
1165        } else {
1166                /* Non-Shared-Ant */
1167                table_case = 100;
1168                tdma_case = 100;
1169        }
1170
1171        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1172        rtw_coex_table(rtwdev, table_case);
1173        rtw_coex_tdma(rtwdev, false, tdma_case);
1174}
1175
1176static void rtw_coex_action_freerun(struct rtw_dev *rtwdev)
1177{
1178        struct rtw_coex *coex = &rtwdev->coex;
1179        struct rtw_coex_stat *coex_stat = &coex->stat;
1180        struct rtw_coex_dm *coex_dm = &coex->dm;
1181        struct rtw_efuse *efuse = &rtwdev->efuse;
1182        struct rtw_chip_info *chip = rtwdev->chip;
1183        u8 level = 0;
1184
1185        if (efuse->share_ant)
1186                return;
1187
1188        coex->freerun = true;
1189
1190        if (coex_stat->wl_connected)
1191                rtw_coex_update_wl_ch_info(rtwdev, COEX_MEDIA_CONNECT);
1192
1193        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);
1194
1195        rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
1196
1197        if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[0]))
1198                level = 2;
1199        else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
1200                level = 3;
1201        else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[2]))
1202                level = 4;
1203        else
1204                level = 5;
1205
1206        if (level > chip->wl_rf_para_num - 1)
1207                level = chip->wl_rf_para_num - 1;
1208
1209        if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
1210                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[level]);
1211        else
1212                rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[level]);
1213
1214        rtw_coex_table(rtwdev, 100);
1215        rtw_coex_tdma(rtwdev, false, 100);
1216}
1217
1218static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev)
1219{
1220        struct rtw_efuse *efuse = &rtwdev->efuse;
1221        struct rtw_chip_info *chip = rtwdev->chip;
1222        u8 table_case, tdma_case;
1223
1224        if (efuse->share_ant) {
1225                /* Shared-Ant */
1226                table_case = 2;
1227                tdma_case = 0;
1228        } else {
1229                /* Non-Shared-Ant */
1230                table_case = 100;
1231                tdma_case = 100;
1232        }
1233
1234        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1235        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1236        rtw_coex_table(rtwdev, table_case);
1237        rtw_coex_tdma(rtwdev, false, tdma_case);
1238}
1239
1240static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)
1241{
1242        struct rtw_efuse *efuse = &rtwdev->efuse;
1243        struct rtw_chip_info *chip = rtwdev->chip;
1244        u8 table_case, tdma_case;
1245
1246        if (efuse->share_ant) {
1247                /* Shared-Ant */
1248                table_case = 1;
1249                tdma_case = 0;
1250        } else {
1251                /* Non-Shared-Ant */
1252                table_case = 100;
1253                tdma_case = 100;
1254        }
1255
1256        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1257        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1258        rtw_coex_table(rtwdev, table_case);
1259        rtw_coex_tdma(rtwdev, false, tdma_case);
1260}
1261
1262static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
1263{
1264        struct rtw_coex *coex = &rtwdev->coex;
1265        struct rtw_coex_stat *coex_stat = &coex->stat;
1266        struct rtw_coex_dm *coex_dm = &coex->dm;
1267        struct rtw_efuse *efuse = &rtwdev->efuse;
1268        struct rtw_chip_info *chip = rtwdev->chip;
1269        struct rtw_coex_rfe *coex_rfe = &coex->rfe;
1270        u8 table_case = 0xff, tdma_case = 0xff;
1271
1272        if (coex_rfe->ant_switch_with_bt &&
1273            coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
1274                if (efuse->share_ant &&
1275                    COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) {
1276                        table_case = 0;
1277                        tdma_case = 0;
1278                } else if (!efuse->share_ant) {
1279                        table_case = 100;
1280                        tdma_case = 100;
1281                }
1282        }
1283
1284        if (table_case != 0xff && tdma_case != 0xff) {
1285                rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);
1286                rtw_coex_table(rtwdev, table_case);
1287                rtw_coex_tdma(rtwdev, false, tdma_case);
1288                return;
1289        }
1290
1291        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1292
1293        if (efuse->share_ant) {
1294                /* Shared-Ant */
1295                if (!coex_stat->wl_gl_busy) {
1296                        table_case = 10;
1297                        tdma_case = 3;
1298                } else if (coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
1299                        table_case = 6;
1300                        tdma_case = 7;
1301                } else {
1302                        table_case = 12;
1303                        tdma_case = 7;
1304                }
1305        } else {
1306                /* Non-Shared-Ant */
1307                if (!coex_stat->wl_gl_busy) {
1308                        table_case = 112;
1309                        tdma_case = 104;
1310                } else if ((coex_stat->bt_ble_scan_type & 0x2) &&
1311                            coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
1312                        table_case = 114;
1313                        tdma_case = 103;
1314                } else {
1315                        table_case = 112;
1316                        tdma_case = 103;
1317                }
1318        }
1319
1320        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1321        rtw_coex_table(rtwdev, table_case);
1322        rtw_coex_tdma(rtwdev, false, tdma_case);
1323}
1324
1325static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
1326{
1327        struct rtw_coex *coex = &rtwdev->coex;
1328        struct rtw_coex_stat *coex_stat = &coex->stat;
1329        struct rtw_efuse *efuse = &rtwdev->efuse;
1330        struct rtw_chip_info *chip = rtwdev->chip;
1331        bool wl_hi_pri = false;
1332        u8 table_case, tdma_case;
1333        u32 slot_type = 0;
1334
1335        if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 ||
1336            coex_stat->wl_hi_pri_task2)
1337                wl_hi_pri = true;
1338
1339        if (efuse->share_ant) {
1340                /* Shared-Ant */
1341                if (wl_hi_pri) {
1342                        table_case = 15;
1343                        if (coex_stat->bt_profile_num > 0)
1344                                tdma_case = 10;
1345                        else if (coex_stat->wl_hi_pri_task1)
1346                                tdma_case = 6;
1347                        else if (!coex_stat->bt_page)
1348                                tdma_case = 8;
1349                        else
1350                                tdma_case = 9;
1351                } else if (coex_stat->wl_gl_busy) {
1352                        if (coex_stat->bt_profile_num == 0) {
1353                                table_case = 12;
1354                                tdma_case = 18;
1355                        } else if (coex_stat->bt_profile_num == 1 &&
1356                                   !coex_stat->bt_a2dp_exist) {
1357                                slot_type = TDMA_4SLOT;
1358                                table_case = 12;
1359                                tdma_case = 20;
1360                        } else {
1361                                slot_type = TDMA_4SLOT;
1362                                table_case = 12;
1363                                tdma_case = 26;
1364                        }
1365                } else if (coex_stat->wl_connected) {
1366                        table_case = 9;
1367                        tdma_case = 27;
1368                } else {
1369                        table_case = 1;
1370                        tdma_case = 0;
1371                }
1372        } else {
1373                /* Non_Shared-Ant */
1374                if (wl_hi_pri) {
1375                        table_case = 113;
1376                        if (coex_stat->bt_a2dp_exist &&
1377                            !coex_stat->bt_pan_exist)
1378                                tdma_case = 111;
1379                        else if (coex_stat->wl_hi_pri_task1)
1380                                tdma_case = 106;
1381                        else if (!coex_stat->bt_page)
1382                                tdma_case = 108;
1383                        else
1384                                tdma_case = 109;
1385                } else if (coex_stat->wl_gl_busy) {
1386                        table_case = 114;
1387                        tdma_case = 121;
1388                } else if (coex_stat->wl_connected) {
1389                        table_case = 100;
1390                        tdma_case = 100;
1391                } else {
1392                        table_case = 101;
1393                        tdma_case = 100;
1394                }
1395        }
1396
1397        rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: wifi hi(%d), bt page(%d)\n",
1398                wl_hi_pri, coex_stat->bt_page);
1399
1400        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1401        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1402        rtw_coex_table(rtwdev, table_case);
1403        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
1404}
1405
1406static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
1407{
1408        struct rtw_coex *coex = &rtwdev->coex;
1409        struct rtw_coex_stat *coex_stat = &coex->stat;
1410        struct rtw_efuse *efuse = &rtwdev->efuse;
1411        struct rtw_chip_info *chip = rtwdev->chip;
1412        u8 table_case, tdma_case;
1413
1414        if (efuse->share_ant) {
1415                /* Shared-Ant */
1416                if (coex_stat->bt_multi_link) {
1417                        table_case = 10;
1418                        tdma_case = 17;
1419                } else {
1420                        table_case = 10;
1421                        tdma_case = 5;
1422                }
1423        } else {
1424                /* Non-Shared-Ant */
1425                if (coex_stat->bt_multi_link) {
1426                        table_case = 112;
1427                        tdma_case = 117;
1428                } else {
1429                        table_case = 105;
1430                        tdma_case = 100;
1431                }
1432        }
1433
1434        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1435        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1436        rtw_coex_table(rtwdev, table_case);
1437        rtw_coex_tdma(rtwdev, false, tdma_case);
1438}
1439
1440static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)
1441{
1442        struct rtw_coex *coex = &rtwdev->coex;
1443        struct rtw_coex_stat *coex_stat = &coex->stat;
1444        struct rtw_efuse *efuse = &rtwdev->efuse;
1445        struct rtw_chip_info *chip = rtwdev->chip;
1446        u8 table_case, tdma_case;
1447        u32 wl_bw;
1448
1449        wl_bw = rtwdev->hal.current_band_width;
1450
1451        if (efuse->share_ant) {
1452                /* Shared-Ant */
1453                if (coex_stat->bt_ble_exist) {
1454                        /* RCU */
1455                        if (!coex_stat->wl_gl_busy)
1456                                table_case = 14;
1457                        else
1458                                table_case = 15;
1459
1460                        if (coex_stat->bt_a2dp_active || wl_bw == 0)
1461                                tdma_case = 18;
1462                        else if (coex_stat->wl_gl_busy)
1463                                tdma_case = 8;
1464                        else
1465                                tdma_case = 4;
1466                } else {
1467                        if (coex_stat->bt_a2dp_active || wl_bw == 0) {
1468                                table_case = 8;
1469                                tdma_case = 4;
1470                        } else {
1471                                /* for 4/18 HID */
1472                                if (coex_stat->bt_418_hid_exist &&
1473                                    coex_stat->wl_gl_busy)
1474                                        table_case = 12;
1475                                else
1476                                        table_case = 10;
1477                                tdma_case = 4;
1478                        }
1479                }
1480        } else {
1481                /* Non-Shared-Ant */
1482                if (coex_stat->bt_a2dp_active) {
1483                        table_case = 113;
1484                        tdma_case = 118;
1485                } else if (coex_stat->bt_ble_exist) {
1486                        /* BLE */
1487                        table_case = 113;
1488
1489                        if (coex_stat->wl_gl_busy)
1490                                tdma_case = 106;
1491                        else
1492                                tdma_case = 104;
1493                } else {
1494                        table_case = 113;
1495                        tdma_case = 104;
1496                }
1497        }
1498
1499        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1500        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1501        rtw_coex_table(rtwdev, table_case);
1502        rtw_coex_tdma(rtwdev, false, tdma_case);
1503}
1504
1505static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)
1506{
1507        struct rtw_coex *coex = &rtwdev->coex;
1508        struct rtw_coex_stat *coex_stat = &coex->stat;
1509        struct rtw_coex_dm *coex_dm = &coex->dm;
1510        struct rtw_efuse *efuse = &rtwdev->efuse;
1511        struct rtw_chip_info *chip = rtwdev->chip;
1512        u8 table_case, tdma_case;
1513        u32 slot_type = 0;
1514
1515        if (efuse->share_ant) {
1516                /* Shared-Ant */
1517                slot_type = TDMA_4SLOT;
1518
1519                if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)
1520                        table_case = 10;
1521                else
1522                        table_case = 9;
1523
1524                if (coex_stat->wl_gl_busy)
1525                        tdma_case = 13;
1526                else
1527                        tdma_case = 14;
1528        } else {
1529                /* Non-Shared-Ant */
1530                table_case = 112;
1531
1532                if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
1533                        tdma_case = 112;
1534                else
1535                        tdma_case = 113;
1536        }
1537
1538        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1539        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1540        rtw_coex_table(rtwdev, table_case);
1541        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
1542}
1543
1544static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev)
1545{
1546        struct rtw_coex *coex = &rtwdev->coex;
1547        struct rtw_coex_stat *coex_stat = &coex->stat;
1548        struct rtw_efuse *efuse = &rtwdev->efuse;
1549        struct rtw_chip_info *chip = rtwdev->chip;
1550        u8 table_case, tdma_case;
1551        bool ap_enable = false;
1552
1553        if (efuse->share_ant) { /* Shared-Ant */
1554                if (ap_enable) {
1555                        table_case = 2;
1556                        tdma_case = 0;
1557                } else if (coex_stat->wl_gl_busy) {
1558                        table_case = 28;
1559                        tdma_case = 20;
1560                } else {
1561                        table_case = 28;
1562                        tdma_case = 26;
1563                }
1564        } else { /* Non-Shared-Ant */
1565                if (ap_enable) {
1566                        table_case = 100;
1567                        tdma_case = 100;
1568                } else {
1569                        table_case = 119;
1570                        tdma_case = 120;
1571                }
1572        }
1573
1574        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1575        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1576        rtw_coex_table(rtwdev, table_case);
1577        rtw_coex_tdma(rtwdev, false, tdma_case);
1578}
1579
1580static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)
1581{
1582        struct rtw_coex *coex = &rtwdev->coex;
1583        struct rtw_coex_stat *coex_stat = &coex->stat;
1584        struct rtw_efuse *efuse = &rtwdev->efuse;
1585        struct rtw_chip_info *chip = rtwdev->chip;
1586        u8 table_case, tdma_case;
1587
1588        if (efuse->share_ant) {
1589                /* Shared-Ant */
1590                if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)
1591                        table_case = 14;
1592                else
1593                        table_case = 10;
1594
1595                if (coex_stat->wl_gl_busy)
1596                        tdma_case = 17;
1597                else
1598                        tdma_case = 19;
1599        } else {
1600                /* Non-Shared-Ant */
1601                table_case = 112;
1602
1603                if (coex_stat->wl_gl_busy)
1604                        tdma_case = 117;
1605                else
1606                        tdma_case = 119;
1607        }
1608
1609        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1610        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1611        rtw_coex_table(rtwdev, table_case);
1612        rtw_coex_tdma(rtwdev, false, tdma_case);
1613}
1614
1615static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev)
1616{
1617        struct rtw_coex *coex = &rtwdev->coex;
1618        struct rtw_coex_stat *coex_stat = &coex->stat;
1619        struct rtw_coex_dm *coex_dm = &coex->dm;
1620        struct rtw_efuse *efuse = &rtwdev->efuse;
1621        struct rtw_chip_info *chip = rtwdev->chip;
1622        u8 table_case, tdma_case;
1623        u32 slot_type = 0;
1624
1625        if (efuse->share_ant) {
1626                /* Shared-Ant */
1627                slot_type = TDMA_4SLOT;
1628
1629                if (coex_stat->bt_ble_exist)
1630                        table_case = 26;
1631                else
1632                        table_case = 9;
1633
1634                if (coex_stat->wl_gl_busy) {
1635                        tdma_case = 13;
1636                } else {
1637                        tdma_case = 14;
1638                }
1639        } else {
1640                /* Non-Shared-Ant */
1641                if (coex_stat->bt_ble_exist)
1642                        table_case = 121;
1643                else
1644                        table_case = 113;
1645
1646                if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
1647                        tdma_case = 112;
1648                else
1649                        tdma_case = 113;
1650        }
1651
1652        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1653        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1654        rtw_coex_table(rtwdev, table_case);
1655        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
1656}
1657
1658static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev)
1659{
1660        struct rtw_coex *coex = &rtwdev->coex;
1661        struct rtw_coex_stat *coex_stat = &coex->stat;
1662        struct rtw_efuse *efuse = &rtwdev->efuse;
1663        struct rtw_chip_info *chip = rtwdev->chip;
1664        u8 table_case, tdma_case;
1665
1666        if (efuse->share_ant) {
1667                /* Shared-Ant */
1668                if (coex_stat->wl_gl_busy &&
1669                    coex_stat->wl_noisy_level == 0)
1670                        table_case = 14;
1671                else
1672                        table_case = 10;
1673
1674                if (coex_stat->wl_gl_busy)
1675                        tdma_case = 15;
1676                else
1677                        tdma_case = 20;
1678        } else {
1679                /* Non-Shared-Ant */
1680                table_case = 112;
1681
1682                if (coex_stat->wl_gl_busy)
1683                        tdma_case = 115;
1684                else
1685                        tdma_case = 120;
1686        }
1687
1688        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1689        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1690        rtw_coex_table(rtwdev, table_case);
1691        rtw_coex_tdma(rtwdev, false, tdma_case);
1692}
1693
1694static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev)
1695{
1696        struct rtw_coex *coex = &rtwdev->coex;
1697        struct rtw_coex_stat *coex_stat = &coex->stat;
1698        struct rtw_efuse *efuse = &rtwdev->efuse;
1699        struct rtw_chip_info *chip = rtwdev->chip;
1700        u8 table_case, tdma_case;
1701
1702        if (efuse->share_ant) {
1703                /* Shared-Ant */
1704                table_case = 9;
1705
1706                if (coex_stat->wl_gl_busy)
1707                        tdma_case = 18;
1708                else
1709                        tdma_case = 19;
1710        } else {
1711                /* Non-Shared-Ant */
1712                table_case = 113;
1713
1714                if (coex_stat->wl_gl_busy)
1715                        tdma_case = 117;
1716                else
1717                        tdma_case = 119;
1718        }
1719
1720        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1721        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1722        rtw_coex_table(rtwdev, table_case);
1723        rtw_coex_tdma(rtwdev, false, tdma_case);
1724}
1725
1726static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)
1727{
1728        struct rtw_coex *coex = &rtwdev->coex;
1729        struct rtw_coex_stat *coex_stat = &coex->stat;
1730        struct rtw_efuse *efuse = &rtwdev->efuse;
1731        struct rtw_chip_info *chip = rtwdev->chip;
1732        u8 table_case, tdma_case;
1733
1734        if (efuse->share_ant) {
1735                /* Shared-Ant */
1736                table_case = 10;
1737
1738                if (coex_stat->wl_gl_busy)
1739                        tdma_case = 15;
1740                else
1741                        tdma_case = 20;
1742        } else {
1743                /* Non-Shared-Ant */
1744                table_case = 113;
1745
1746                if (coex_stat->wl_gl_busy)
1747                        tdma_case = 115;
1748                else
1749                        tdma_case = 120;
1750        }
1751
1752        rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
1753        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1754        rtw_coex_table(rtwdev, table_case);
1755        rtw_coex_tdma(rtwdev, false, tdma_case);
1756}
1757
1758static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
1759{
1760        struct rtw_efuse *efuse = &rtwdev->efuse;
1761        struct rtw_chip_info *chip = rtwdev->chip;
1762        u8 table_case, tdma_case;
1763
1764        rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
1765
1766        if (efuse->share_ant) {
1767                /* Shared-Ant */
1768                table_case = 0;
1769                tdma_case = 0;
1770        } else {
1771                /* Non-Shared-Ant */
1772                table_case = 100;
1773                tdma_case = 100;
1774        }
1775
1776        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
1777        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1778        rtw_coex_table(rtwdev, table_case);
1779        rtw_coex_tdma(rtwdev, false, tdma_case);
1780}
1781
1782static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev)
1783{
1784        struct rtw_efuse *efuse = &rtwdev->efuse;
1785        struct rtw_chip_info *chip = rtwdev->chip;
1786        u8 table_case, tdma_case;
1787
1788        if (efuse->share_ant) {
1789                /* Shared-Ant */
1790                table_case = 2;
1791                tdma_case = 0;
1792        } else {
1793                /* Non-Shared-Ant */
1794                table_case = 100;
1795                tdma_case = 100;
1796        }
1797
1798        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
1799        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1800        rtw_coex_table(rtwdev, table_case);
1801        rtw_coex_tdma(rtwdev, false, tdma_case);
1802}
1803
1804static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
1805{
1806        struct rtw_coex *coex = &rtwdev->coex;
1807        struct rtw_efuse *efuse = &rtwdev->efuse;
1808        struct rtw_chip_info *chip = rtwdev->chip;
1809        u8 table_case, tdma_case;
1810
1811        if (coex->under_5g)
1812                return;
1813
1814        if (efuse->share_ant) {
1815                /* Shared-Ant */
1816                table_case = 28;
1817                tdma_case = 0;
1818        } else {
1819                /* Non-Shared-Ant */
1820                table_case = 100;
1821                tdma_case = 100;
1822        }
1823
1824        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
1825        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1826        rtw_coex_table(rtwdev, table_case);
1827        rtw_coex_tdma(rtwdev, false, tdma_case);
1828}
1829
1830static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
1831{
1832        struct rtw_coex *coex = &rtwdev->coex;
1833        struct rtw_coex_stat *coex_stat = &coex->stat;
1834        struct rtw_efuse *efuse = &rtwdev->efuse;
1835        struct rtw_chip_info *chip = rtwdev->chip;
1836        u8 table_case, tdma_case;
1837        u32 slot_type = 0;
1838
1839        if (efuse->share_ant) {
1840                /* Shared-Ant */
1841                if (coex_stat->bt_a2dp_exist) {
1842                        slot_type = TDMA_4SLOT;
1843                        table_case = 9;
1844                        tdma_case = 11;
1845                } else {
1846                        table_case = 9;
1847                        tdma_case = 7;
1848                }
1849        } else {
1850                /* Non-Shared-Ant */
1851                if (coex_stat->bt_a2dp_exist) {
1852                        table_case = 112;
1853                        tdma_case = 111;
1854                } else {
1855                        table_case = 112;
1856                        tdma_case = 107;
1857                }
1858        }
1859
1860        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
1861        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1862        rtw_coex_table(rtwdev, table_case);
1863        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
1864}
1865
1866static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev)
1867{
1868        struct rtw_efuse *efuse = &rtwdev->efuse;
1869        struct rtw_chip_info *chip = rtwdev->chip;
1870        u8 table_case, tdma_case;
1871
1872        if (efuse->share_ant) {
1873                /* Shared-Ant */
1874                table_case = 1;
1875                tdma_case = 0;
1876        } else {
1877                /* Non-Shared-Ant */
1878                table_case = 100;
1879                tdma_case = 100;
1880        }
1881
1882        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
1883        rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
1884        rtw_coex_table(rtwdev, table_case);
1885        rtw_coex_tdma(rtwdev, false, tdma_case);
1886}
1887
1888static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)
1889{
1890        struct rtw_coex *coex = &rtwdev->coex;
1891        struct rtw_coex_stat *coex_stat = &coex->stat;
1892        struct rtw_coex_dm *coex_dm = &coex->dm;
1893        struct rtw_efuse *efuse = &rtwdev->efuse;
1894        u8 algorithm;
1895
1896        /* Non-Shared-Ant */
1897        if (!efuse->share_ant && coex_stat->wl_gl_busy &&
1898            COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
1899            COEX_RSSI_HIGH(coex_dm->bt_rssi_state[0])) {
1900                rtw_coex_action_freerun(rtwdev);
1901                return;
1902        }
1903
1904        algorithm = rtw_coex_algorithm(rtwdev);
1905
1906        switch (algorithm) {
1907        case COEX_ALGO_HFP:
1908                rtw_coex_action_bt_hfp(rtwdev);
1909                break;
1910        case COEX_ALGO_HID:
1911                rtw_coex_action_bt_hid(rtwdev);
1912                break;
1913        case COEX_ALGO_A2DP:
1914                if (coex_stat->bt_a2dp_sink)
1915                        rtw_coex_action_bt_a2dpsink(rtwdev);
1916                else
1917                        rtw_coex_action_bt_a2dp(rtwdev);
1918                break;
1919        case COEX_ALGO_PAN:
1920                rtw_coex_action_bt_pan(rtwdev);
1921                break;
1922        case COEX_ALGO_A2DP_HID:
1923                rtw_coex_action_bt_a2dp_hid(rtwdev);
1924                break;
1925        case COEX_ALGO_A2DP_PAN:
1926                rtw_coex_action_bt_a2dp_pan(rtwdev);
1927                break;
1928        case COEX_ALGO_PAN_HID:
1929                rtw_coex_action_bt_pan_hid(rtwdev);
1930                break;
1931        case COEX_ALGO_A2DP_PAN_HID:
1932                rtw_coex_action_bt_a2dp_pan_hid(rtwdev);
1933                break;
1934        default:
1935        case COEX_ALGO_NOPROFILE:
1936                rtw_coex_action_bt_idle(rtwdev);
1937                break;
1938        }
1939}
1940
1941static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
1942{
1943        struct rtw_coex *coex = &rtwdev->coex;
1944        struct rtw_coex_dm *coex_dm = &coex->dm;
1945        struct rtw_coex_stat *coex_stat = &coex->stat;
1946
1947        lockdep_assert_held(&rtwdev->mutex);
1948
1949        if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags))
1950                return;
1951
1952        coex_dm->reason = reason;
1953
1954        /* update wifi_link_info_ext variable */
1955        rtw_coex_update_wl_link_info(rtwdev, reason);
1956
1957        rtw_coex_monitor_bt_enable(rtwdev);
1958
1959        if (coex->stop_dm)
1960                return;
1961
1962        if (coex_stat->wl_under_ips)
1963                return;
1964
1965        if (coex->freeze && coex_dm->reason == COEX_RSN_BTINFO &&
1966            !coex_stat->bt_setup_link)
1967                return;
1968
1969        coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++;
1970        coex->freerun = false;
1971
1972        /* Pure-5G Coex Process */
1973        if (coex->under_5g) {
1974                coex_stat->wl_coex_mode = COEX_WLINK_5G;
1975                rtw_coex_action_wl_under5g(rtwdev);
1976                goto exit;
1977        }
1978
1979        coex_stat->wl_coex_mode = COEX_WLINK_2G1PORT;
1980        rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
1981        if (coex_stat->bt_disabled) {
1982                rtw_coex_action_wl_only(rtwdev);
1983                goto exit;
1984        }
1985
1986        if (coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) {
1987                rtw_coex_action_wl_native_lps(rtwdev);
1988                goto exit;
1989        }
1990
1991        if (coex_stat->bt_whck_test) {
1992                rtw_coex_action_bt_whql_test(rtwdev);
1993                goto exit;
1994        }
1995
1996        if (coex_stat->bt_setup_link) {
1997                rtw_coex_action_bt_relink(rtwdev);
1998                goto exit;
1999        }
2000
2001        if (coex_stat->bt_inq_page) {
2002                rtw_coex_action_bt_inquiry(rtwdev);
2003                goto exit;
2004        }
2005
2006        if ((coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE ||
2007             coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE) &&
2008             coex_stat->wl_connected) {
2009                rtw_coex_action_bt_idle(rtwdev);
2010                goto exit;
2011        }
2012
2013        if (coex_stat->wl_linkscan_proc) {
2014                rtw_coex_action_wl_linkscan(rtwdev);
2015                goto exit;
2016        }
2017
2018        if (coex_stat->wl_connected)
2019                rtw_coex_action_wl_connected(rtwdev);
2020        else
2021                rtw_coex_action_wl_not_connected(rtwdev);
2022
2023exit:
2024        rtw_coex_set_gnt_fix(rtwdev);
2025        rtw_coex_limited_wl(rtwdev);
2026}
2027
2028static void rtw_coex_init_coex_var(struct rtw_dev *rtwdev)
2029{
2030        struct rtw_coex *coex = &rtwdev->coex;
2031        struct rtw_coex_stat *coex_stat = &coex->stat;
2032        struct rtw_coex_dm *coex_dm = &coex->dm;
2033        u8 i;
2034
2035        memset(coex_dm, 0, sizeof(*coex_dm));
2036        memset(coex_stat, 0, sizeof(*coex_stat));
2037
2038        for (i = 0; i < COEX_CNT_WL_MAX; i++)
2039                coex_stat->cnt_wl[i] = 0;
2040
2041        for (i = 0; i < COEX_CNT_BT_MAX; i++)
2042                coex_stat->cnt_bt[i] = 0;
2043
2044        for (i = 0; i < ARRAY_SIZE(coex_dm->bt_rssi_state); i++)
2045                coex_dm->bt_rssi_state[i] = COEX_RSSI_STATE_LOW;
2046
2047        for (i = 0; i < ARRAY_SIZE(coex_dm->wl_rssi_state); i++)
2048                coex_dm->wl_rssi_state[i] = COEX_RSSI_STATE_LOW;
2049
2050        coex_stat->wl_coex_mode = COEX_WLINK_MAX;
2051}
2052
2053static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
2054{
2055        struct rtw_coex *coex = &rtwdev->coex;
2056
2057        rtw_coex_init_coex_var(rtwdev);
2058        rtw_coex_monitor_bt_enable(rtwdev);
2059        rtw_coex_set_rfe_type(rtwdev);
2060        rtw_coex_set_init(rtwdev);
2061
2062        /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */
2063        rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_RSP, 1);
2064
2065        /* set Tx beacon = Hi-Pri */
2066        rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACON, 1);
2067
2068        /* set Tx beacon queue = Hi-Pri */
2069        rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACONQ, 1);
2070
2071        /* antenna config */
2072        if (coex->wl_rf_off) {
2073                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);
2074                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);
2075                coex->stop_dm = true;
2076        } else if (wifi_only) {
2077                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WONLY);
2078                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN,
2079                                    true);
2080                coex->stop_dm = true;
2081        } else {
2082                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_INIT);
2083                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN,
2084                                    true);
2085                coex->stop_dm = false;
2086                coex->freeze = true;
2087        }
2088
2089        /* PTA parameter */
2090        rtw_coex_table(rtwdev, 0);
2091        rtw_coex_tdma(rtwdev, true, 0);
2092        rtw_coex_query_bt_info(rtwdev);
2093}
2094
2095void rtw_coex_power_on_setting(struct rtw_dev *rtwdev)
2096{
2097        struct rtw_coex *coex = &rtwdev->coex;
2098
2099        coex->stop_dm = true;
2100        coex->wl_rf_off = false;
2101
2102        /* enable BB, we can write 0x948 */
2103        rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1));
2104
2105        rtw_coex_monitor_bt_enable(rtwdev);
2106        rtw_coex_set_rfe_type(rtwdev);
2107
2108        /* set antenna path to BT */
2109        rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_POWERON);
2110
2111        /* red x issue */
2112        rtw_write8(rtwdev, 0xff1a, 0x0);
2113}
2114
2115void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
2116{
2117        __rtw_coex_init_hw_config(rtwdev, wifi_only);
2118}
2119
2120void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type)
2121{
2122        struct rtw_coex *coex = &rtwdev->coex;
2123        struct rtw_coex_stat *coex_stat = &coex->stat;
2124
2125        if (coex->stop_dm)
2126                return;
2127
2128        if (type == COEX_IPS_ENTER) {
2129                coex_stat->wl_under_ips = true;
2130
2131                /* for lps off */
2132                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);
2133
2134                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);
2135                rtw_coex_action_coex_all_off(rtwdev);
2136        } else if (type == COEX_IPS_LEAVE) {
2137                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
2138
2139                /* run init hw config (exclude wifi only) */
2140                __rtw_coex_init_hw_config(rtwdev, false);
2141                /* sw all off */
2142
2143                coex_stat->wl_under_ips = false;
2144        }
2145}
2146
2147void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type)
2148{
2149        struct rtw_coex *coex = &rtwdev->coex;
2150        struct rtw_coex_stat *coex_stat = &coex->stat;
2151
2152        if (coex->stop_dm)
2153                return;
2154
2155        if (type == COEX_LPS_ENABLE) {
2156                coex_stat->wl_under_lps = true;
2157
2158                if (coex_stat->wl_force_lps_ctrl) {
2159                        /* for ps-tdma */
2160                        rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
2161                } else {
2162                        /* for native ps */
2163                        rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false);
2164
2165                        rtw_coex_run_coex(rtwdev, COEX_RSN_LPS);
2166                }
2167        } else if (type == COEX_LPS_DISABLE) {
2168                coex_stat->wl_under_lps = false;
2169
2170                /* for lps off */
2171                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
2172
2173                if (!coex_stat->wl_force_lps_ctrl)
2174                        rtw_coex_query_bt_info(rtwdev);
2175        }
2176}
2177
2178void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type)
2179{
2180        struct rtw_coex *coex = &rtwdev->coex;
2181        struct rtw_coex_stat *coex_stat = &coex->stat;
2182
2183        if (coex->stop_dm)
2184                return;
2185
2186        coex->freeze = false;
2187
2188        if (type != COEX_SCAN_FINISH)
2189                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN |
2190                                    COEX_SCBD_ONOFF, true);
2191
2192        if (type == COEX_SCAN_START_5G) {
2193                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2194                rtw_coex_run_coex(rtwdev, COEX_RSN_5GSCANSTART);
2195        } else if ((type == COEX_SCAN_START_2G) || (type == COEX_SCAN_START)) {
2196                coex_stat->wl_hi_pri_task2 = true;
2197
2198                /* Force antenna setup for no scan result issue */
2199                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
2200                rtw_coex_run_coex(rtwdev, COEX_RSN_2GSCANSTART);
2201        } else {
2202                coex_stat->wl_hi_pri_task2 = false;
2203                rtw_coex_run_coex(rtwdev, COEX_RSN_SCANFINISH);
2204        }
2205}
2206
2207void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type)
2208{
2209        struct rtw_coex *coex = &rtwdev->coex;
2210
2211        if (coex->stop_dm)
2212                return;
2213
2214        if (type == COEX_SWITCH_TO_5G)
2215                rtw_coex_run_coex(rtwdev, COEX_RSN_5GSWITCHBAND);
2216        else if (type == COEX_SWITCH_TO_24G_NOFORSCAN)
2217                rtw_coex_run_coex(rtwdev, COEX_RSN_2GSWITCHBAND);
2218        else
2219                rtw_coex_scan_notify(rtwdev, COEX_SCAN_START_2G);
2220}
2221
2222void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type)
2223{
2224        struct rtw_coex *coex = &rtwdev->coex;
2225        struct rtw_coex_stat *coex_stat = &coex->stat;
2226
2227        if (coex->stop_dm)
2228                return;
2229
2230        rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN |
2231                            COEX_SCBD_ONOFF, true);
2232
2233        if (type == COEX_ASSOCIATE_5G_START) {
2234                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2235                rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONSTART);
2236        } else if (type == COEX_ASSOCIATE_5G_FINISH) {
2237                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2238                rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONFINISH);
2239        } else if (type == COEX_ASSOCIATE_START) {
2240                coex_stat->wl_hi_pri_task1 = true;
2241                coex_stat->cnt_wl[COEX_CNT_WL_CONNPKT] = 2;
2242
2243                /* Force antenna setup for no scan result issue */
2244                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
2245
2246                rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONSTART);
2247
2248                /* To keep TDMA case during connect process,
2249                 * to avoid changed by Btinfo and runcoexmechanism
2250                 */
2251                coex->freeze = true;
2252                ieee80211_queue_delayed_work(rtwdev->hw, &coex->defreeze_work,
2253                                             5 * HZ);
2254        } else {
2255                coex_stat->wl_hi_pri_task1 = false;
2256                coex->freeze = false;
2257
2258                rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONFINISH);
2259        }
2260}
2261
2262void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type)
2263{
2264        struct rtw_coex *coex = &rtwdev->coex;
2265        struct rtw_coex_stat *coex_stat = &coex->stat;
2266        u8 para[6] = {0};
2267
2268        if (coex->stop_dm)
2269                return;
2270
2271        if (type == COEX_MEDIA_CONNECT_5G) {
2272                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
2273
2274                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
2275                rtw_coex_run_coex(rtwdev, COEX_RSN_5GMEDIA);
2276        } else if (type == COEX_MEDIA_CONNECT) {
2277                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
2278
2279                /* Force antenna setup for no scan result issue */
2280                rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
2281
2282                /* Set CCK Rx high Pri */
2283                rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 1);
2284
2285                /* always enable 5ms extend if connect */
2286                para[0] = COEX_H2C69_WL_LEAKAP;
2287                para[1] = PARA1_H2C69_EN_5MS; /* enable 5ms extend */
2288                rtw_fw_bt_wifi_control(rtwdev, para[0], &para[1]);
2289                coex_stat->wl_slot_extend = true;
2290                rtw_coex_run_coex(rtwdev, COEX_RSN_2GMEDIA);
2291        } else {
2292                rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false);
2293
2294                rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 0);
2295
2296                rtw_coex_run_coex(rtwdev, COEX_RSN_MEDIADISCON);
2297        }
2298
2299        rtw_coex_update_wl_ch_info(rtwdev, type);
2300}
2301
2302void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
2303{
2304        struct rtw_coex *coex = &rtwdev->coex;
2305        struct rtw_coex_stat *coex_stat = &coex->stat;
2306        struct rtw_chip_info *chip = rtwdev->chip;
2307        unsigned long bt_relink_time;
2308        u8 i, rsp_source = 0, type;
2309        bool inq_page = false;
2310
2311        rsp_source = buf[0] & 0xf;
2312        if (rsp_source >= COEX_BTINFO_SRC_MAX)
2313                rsp_source = COEX_BTINFO_SRC_WL_FW;
2314
2315        if (rsp_source == COEX_BTINFO_SRC_BT_IQK) {
2316                coex_stat->bt_iqk_state = buf[1];
2317                if (coex_stat->bt_iqk_state == 1)
2318                        coex_stat->cnt_bt[COEX_CNT_BT_IQK]++;
2319                else if (coex_stat->bt_iqk_state == 2)
2320                        coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]++;
2321
2322                return;
2323        }
2324
2325        if (rsp_source == COEX_BTINFO_SRC_BT_SCBD) {
2326                rtw_coex_monitor_bt_enable(rtwdev);
2327                if (coex_stat->bt_disabled != coex_stat->bt_disabled_pre) {
2328                        coex_stat->bt_disabled_pre = coex_stat->bt_disabled;
2329                        rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
2330                }
2331                return;
2332        }
2333
2334        if (rsp_source == COEX_BTINFO_SRC_BT_RSP ||
2335            rsp_source == COEX_BTINFO_SRC_BT_ACT) {
2336                if (coex_stat->bt_disabled) {
2337                        coex_stat->bt_disabled = false;
2338                        coex_stat->bt_reenable = true;
2339                        ieee80211_queue_delayed_work(rtwdev->hw,
2340                                                     &coex->bt_reenable_work,
2341                                                     15 * HZ);
2342                }
2343        }
2344
2345        for (i = 0; i < length; i++) {
2346                if (i < COEX_BTINFO_LENGTH_MAX)
2347                        coex_stat->bt_info_c2h[rsp_source][i] = buf[i];
2348                else
2349                        break;
2350        }
2351
2352        if (rsp_source == COEX_BTINFO_SRC_WL_FW) {
2353                rtw_coex_update_bt_link_info(rtwdev);
2354                rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
2355                return;
2356        }
2357
2358        /* get the same info from bt, skip it */
2359        if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 &&
2360            coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 &&
2361            coex_stat->bt_info_c2h[rsp_source][3] == coex_stat->bt_info_hb0 &&
2362            coex_stat->bt_info_c2h[rsp_source][4] == coex_stat->bt_info_hb1 &&
2363            coex_stat->bt_info_c2h[rsp_source][5] == coex_stat->bt_info_hb2 &&
2364            coex_stat->bt_info_c2h[rsp_source][6] == coex_stat->bt_info_hb3)
2365                return;
2366
2367        coex_stat->bt_info_lb2 = coex_stat->bt_info_c2h[rsp_source][1];
2368        coex_stat->bt_info_lb3 = coex_stat->bt_info_c2h[rsp_source][2];
2369        coex_stat->bt_info_hb0 = coex_stat->bt_info_c2h[rsp_source][3];
2370        coex_stat->bt_info_hb1 = coex_stat->bt_info_c2h[rsp_source][4];
2371        coex_stat->bt_info_hb2 = coex_stat->bt_info_c2h[rsp_source][5];
2372        coex_stat->bt_info_hb3 = coex_stat->bt_info_c2h[rsp_source][6];
2373
2374        /* 0xff means BT is under WHCK test */
2375        coex_stat->bt_whck_test = (coex_stat->bt_info_lb2 == 0xff);
2376
2377        inq_page = ((coex_stat->bt_info_lb2 & BIT(2)) == BIT(2));
2378
2379        if (inq_page != coex_stat->bt_inq_page) {
2380                cancel_delayed_work_sync(&coex->bt_remain_work);
2381                coex_stat->bt_inq_page = inq_page;
2382
2383                if (inq_page)
2384                        coex_stat->bt_inq_remain = true;
2385                else
2386                        ieee80211_queue_delayed_work(rtwdev->hw,
2387                                                     &coex->bt_remain_work,
2388                                                     4 * HZ);
2389        }
2390        coex_stat->bt_acl_busy = ((coex_stat->bt_info_lb2 & BIT(3)) == BIT(3));
2391        coex_stat->cnt_bt[COEX_CNT_BT_RETRY] = coex_stat->bt_info_lb3 & 0xf;
2392        if (coex_stat->cnt_bt[COEX_CNT_BT_RETRY] >= 1)
2393                coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]++;
2394
2395        coex_stat->bt_fix_2M = ((coex_stat->bt_info_lb3 & BIT(4)) == BIT(4));
2396        coex_stat->bt_inq = ((coex_stat->bt_info_lb3 & BIT(5)) == BIT(5));
2397        if (coex_stat->bt_inq)
2398                coex_stat->cnt_bt[COEX_CNT_BT_INQ]++;
2399
2400        coex_stat->bt_page = ((coex_stat->bt_info_lb3 & BIT(7)) == BIT(7));
2401        if (coex_stat->bt_page) {
2402                coex_stat->cnt_bt[COEX_CNT_BT_PAGE]++;
2403                if (coex_stat->wl_linkscan_proc ||
2404                    coex_stat->wl_hi_pri_task1 ||
2405                    coex_stat->wl_hi_pri_task2 || coex_stat->wl_gl_busy)
2406                        rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, true);
2407                else
2408                        rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);
2409        } else {
2410                rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);
2411        }
2412
2413        /* unit: % (value-100 to translate to unit: dBm in coex info) */
2414        if (chip->bt_rssi_type == COEX_BTRSSI_RATIO) {
2415                coex_stat->bt_rssi = coex_stat->bt_info_hb0 * 2 + 10;
2416        } else { /* original unit: dbm -> unit: % ->  value-100 in coex info */
2417                if (coex_stat->bt_info_hb0 <= 127)
2418                        coex_stat->bt_rssi = 100;
2419                else if (256 - coex_stat->bt_info_hb0 <= 100)
2420                        coex_stat->bt_rssi = 100 - (256 - coex_stat->bt_info_hb0);
2421                else
2422                        coex_stat->bt_rssi = 0;
2423        }
2424
2425        coex_stat->bt_ble_exist = ((coex_stat->bt_info_hb1 & BIT(0)) == BIT(0));
2426        if (coex_stat->bt_info_hb1 & BIT(1))
2427                coex_stat->cnt_bt[COEX_CNT_BT_REINIT]++;
2428
2429        if (coex_stat->bt_info_hb1 & BIT(2)) {
2430                coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK]++;
2431                coex_stat->bt_setup_link = true;
2432                if (coex_stat->bt_reenable)
2433                        bt_relink_time = 6 * HZ;
2434                else
2435                        bt_relink_time = 2 * HZ;
2436
2437                ieee80211_queue_delayed_work(rtwdev->hw,
2438                                             &coex->bt_relink_work,
2439                                             bt_relink_time);
2440        }
2441
2442        if (coex_stat->bt_info_hb1 & BIT(3))
2443                coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT]++;
2444
2445        coex_stat->bt_ble_voice = ((coex_stat->bt_info_hb1 & BIT(4)) == BIT(4));
2446        coex_stat->bt_ble_scan_en = ((coex_stat->bt_info_hb1 & BIT(5)) == BIT(5));
2447        if (coex_stat->bt_info_hb1 & BIT(6))
2448                coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH]++;
2449
2450        coex_stat->bt_multi_link = ((coex_stat->bt_info_hb1 & BIT(7)) == BIT(7));
2451        /* resend wifi info to bt, it is reset and lost the info */
2452        if ((coex_stat->bt_info_hb1 & BIT(1))) {
2453                if (coex_stat->wl_connected)
2454                        type = COEX_MEDIA_CONNECT;
2455                else
2456                        type = COEX_MEDIA_DISCONNECT;
2457                rtw_coex_update_wl_ch_info(rtwdev, type);
2458        }
2459
2460        /* if ignore_wlan_act && not set_up_link */
2461        if ((coex_stat->bt_info_hb1 & BIT(3)) &&
2462            (!(coex_stat->bt_info_hb1 & BIT(2))))
2463                rtw_coex_ignore_wlan_act(rtwdev, false);
2464
2465        coex_stat->bt_opp_exist = ((coex_stat->bt_info_hb2 & BIT(0)) == BIT(0));
2466        if (coex_stat->bt_info_hb2 & BIT(1))
2467                coex_stat->cnt_bt[COEX_CNT_BT_AFHUPDATE]++;
2468
2469        coex_stat->bt_a2dp_active = (coex_stat->bt_info_hb2 & BIT(2)) == BIT(2);
2470        coex_stat->bt_slave = ((coex_stat->bt_info_hb2 & BIT(3)) == BIT(3));
2471        coex_stat->bt_hid_slot = (coex_stat->bt_info_hb2 & 0x30) >> 4;
2472        coex_stat->bt_hid_pair_num = (coex_stat->bt_info_hb2 & 0xc0) >> 6;
2473        if (coex_stat->bt_hid_pair_num > 0 && coex_stat->bt_hid_slot >= 2)
2474                coex_stat->bt_418_hid_exist = true;
2475        else if (coex_stat->bt_hid_pair_num == 0)
2476                coex_stat->bt_418_hid_exist = false;
2477
2478        if ((coex_stat->bt_info_lb2 & 0x49) == 0x49)
2479                coex_stat->bt_a2dp_bitpool = (coex_stat->bt_info_hb3 & 0x7f);
2480        else
2481                coex_stat->bt_a2dp_bitpool = 0;
2482
2483        coex_stat->bt_a2dp_sink = ((coex_stat->bt_info_hb3 & BIT(7)) == BIT(7));
2484
2485        rtw_coex_update_bt_link_info(rtwdev);
2486        rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
2487}
2488
2489void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
2490{
2491        struct rtw_coex *coex = &rtwdev->coex;
2492        struct rtw_coex_stat *coex_stat = &coex->stat;
2493        u8 val;
2494        int i;
2495
2496        if (WARN(length < 8, "invalid wl info c2h length\n"))
2497                return;
2498
2499        if (buf[0] != 0x08)
2500                return;
2501
2502        for (i = 1; i < 8; i++) {
2503                val = coex_stat->wl_fw_dbg_info_pre[i];
2504                if (buf[i] >= val)
2505                        coex_stat->wl_fw_dbg_info[i] = buf[i] - val;
2506                else
2507                        coex_stat->wl_fw_dbg_info[i] = val - buf[i];
2508
2509                coex_stat->wl_fw_dbg_info_pre[i] = buf[i];
2510        }
2511
2512        coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]++;
2513        rtw_coex_wl_ccklock_action(rtwdev);
2514        rtw_coex_wl_ccklock_detect(rtwdev);
2515}
2516
2517void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev)
2518{
2519        struct rtw_coex *coex = &rtwdev->coex;
2520
2521        if (coex->stop_dm)
2522                return;
2523
2524        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
2525}
2526
2527void rtw_coex_bt_relink_work(struct work_struct *work)
2528{
2529        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
2530                                              coex.bt_relink_work.work);
2531        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
2532
2533        mutex_lock(&rtwdev->mutex);
2534        coex_stat->bt_setup_link = false;
2535        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
2536        mutex_unlock(&rtwdev->mutex);
2537}
2538
2539void rtw_coex_bt_reenable_work(struct work_struct *work)
2540{
2541        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
2542                                              coex.bt_reenable_work.work);
2543        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
2544
2545        mutex_lock(&rtwdev->mutex);
2546        coex_stat->bt_reenable = false;
2547        mutex_unlock(&rtwdev->mutex);
2548}
2549
2550void rtw_coex_defreeze_work(struct work_struct *work)
2551{
2552        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
2553                                              coex.defreeze_work.work);
2554        struct rtw_coex *coex = &rtwdev->coex;
2555        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
2556
2557        mutex_lock(&rtwdev->mutex);
2558        coex->freeze = false;
2559        coex_stat->wl_hi_pri_task1 = false;
2560        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
2561        mutex_unlock(&rtwdev->mutex);
2562}
2563
2564void rtw_coex_wl_remain_work(struct work_struct *work)
2565{
2566        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
2567                                              coex.wl_remain_work.work);
2568        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
2569
2570        mutex_lock(&rtwdev->mutex);
2571        coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
2572        rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
2573        mutex_unlock(&rtwdev->mutex);
2574}
2575
2576void rtw_coex_bt_remain_work(struct work_struct *work)
2577{
2578        struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
2579                                              coex.bt_remain_work.work);
2580        struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
2581
2582        mutex_lock(&rtwdev->mutex);
2583        coex_stat->bt_inq_remain = coex_stat->bt_inq_page;
2584        rtw_coex_run_coex(rtwdev, COEX_RSN_BTSTATUS);
2585        mutex_unlock(&rtwdev->mutex);
2586}
2587
2588#ifdef CONFIG_RTW88_DEBUGFS
2589#define INFO_SIZE       80
2590
2591#define case_BTINFO(src) \
2592        case COEX_BTINFO_SRC_##src: return #src
2593
2594static const char *rtw_coex_get_bt_info_src_string(u8 bt_info_src)
2595{
2596        switch (bt_info_src) {
2597        case_BTINFO(WL_FW);
2598        case_BTINFO(BT_RSP);
2599        case_BTINFO(BT_ACT);
2600        default:
2601                return "Unknown";
2602        }
2603}
2604
2605#define case_RSN(src) \
2606        case COEX_RSN_##src: return #src
2607
2608static const char *rtw_coex_get_reason_string(u8 reason)
2609{
2610        switch (reason) {
2611        case_RSN(2GSCANSTART);
2612        case_RSN(5GSCANSTART);
2613        case_RSN(SCANFINISH);
2614        case_RSN(2GSWITCHBAND);
2615        case_RSN(5GSWITCHBAND);
2616        case_RSN(2GCONSTART);
2617        case_RSN(5GCONSTART);
2618        case_RSN(2GCONFINISH);
2619        case_RSN(5GCONFINISH);
2620        case_RSN(2GMEDIA);
2621        case_RSN(5GMEDIA);
2622        case_RSN(MEDIADISCON);
2623        case_RSN(BTINFO);
2624        case_RSN(LPS);
2625        case_RSN(WLSTATUS);
2626        default:
2627                return "Unknown";
2628        }
2629}
2630
2631static int rtw_coex_addr_info(struct rtw_dev *rtwdev,
2632                              const struct rtw_reg_domain *reg,
2633                              char addr_info[], int n)
2634{
2635        const char *rf_prefix = "";
2636        const char *sep = n == 0 ? "" : "/ ";
2637        int ffs, fls;
2638        int max_fls;
2639
2640        if (INFO_SIZE - n <= 0)
2641                return 0;
2642
2643        switch (reg->domain) {
2644        case RTW_REG_DOMAIN_MAC32:
2645                max_fls = 31;
2646                break;
2647        case RTW_REG_DOMAIN_MAC16:
2648                max_fls = 15;
2649                break;
2650        case RTW_REG_DOMAIN_MAC8:
2651                max_fls = 7;
2652                break;
2653        case RTW_REG_DOMAIN_RF_A:
2654        case RTW_REG_DOMAIN_RF_B:
2655                rf_prefix = "RF_";
2656                max_fls = 19;
2657                break;
2658        default:
2659                return 0;
2660        }
2661
2662        ffs = __ffs(reg->mask);
2663        fls = __fls(reg->mask);
2664
2665        if (ffs == 0 && fls == max_fls)
2666                return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x",
2667                                 sep, rf_prefix, reg->addr);
2668        else if (ffs == fls)
2669                return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x[%d]",
2670                                 sep, rf_prefix, reg->addr, ffs);
2671        else
2672                return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x[%d:%d]",
2673                                 sep, rf_prefix, reg->addr, fls, ffs);
2674}
2675
2676static int rtw_coex_val_info(struct rtw_dev *rtwdev,
2677                             const struct rtw_reg_domain *reg,
2678                             char val_info[], int n)
2679{
2680        const char *sep = n == 0 ? "" : "/ ";
2681        u8 rf_path;
2682
2683        if (INFO_SIZE - n <= 0)
2684                return 0;
2685
2686        switch (reg->domain) {
2687        case RTW_REG_DOMAIN_MAC32:
2688                return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,
2689                                 rtw_read32_mask(rtwdev, reg->addr, reg->mask));
2690        case RTW_REG_DOMAIN_MAC16:
2691                return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,
2692                                 rtw_read16_mask(rtwdev, reg->addr, reg->mask));
2693        case RTW_REG_DOMAIN_MAC8:
2694                return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,
2695                                 rtw_read8_mask(rtwdev, reg->addr, reg->mask));
2696        case RTW_REG_DOMAIN_RF_A:
2697                rf_path = RF_PATH_A;
2698                break;
2699        case RTW_REG_DOMAIN_RF_B:
2700                rf_path = RF_PATH_B;
2701                break;
2702        default:
2703                return 0;
2704        }
2705
2706        /* only RF go through here */
2707        return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,
2708                         rtw_read_rf(rtwdev, rf_path, reg->addr, reg->mask));
2709}
2710
2711static void rtw_coex_set_coexinfo_hw(struct rtw_dev *rtwdev, struct seq_file *m)
2712{
2713        struct rtw_chip_info *chip = rtwdev->chip;
2714        const struct rtw_reg_domain *reg;
2715        char addr_info[INFO_SIZE];
2716        int n_addr = 0;
2717        char val_info[INFO_SIZE];
2718        int n_val = 0;
2719        int i;
2720
2721        for (i = 0; i < chip->coex_info_hw_regs_num; i++) {
2722                reg = &chip->coex_info_hw_regs[i];
2723
2724                n_addr += rtw_coex_addr_info(rtwdev, reg, addr_info, n_addr);
2725                n_val += rtw_coex_val_info(rtwdev, reg, val_info, n_val);
2726
2727                if (reg->domain == RTW_REG_DOMAIN_NL) {
2728                        seq_printf(m, "%-40s = %s\n", addr_info, val_info);
2729                        n_addr = 0;
2730                        n_val = 0;
2731                }
2732        }
2733
2734        if (n_addr != 0 && n_val != 0)
2735                seq_printf(m, "%-40s = %s\n", addr_info, val_info);
2736}
2737
2738static bool rtw_coex_get_bt_reg(struct rtw_dev *rtwdev,
2739                                u8 type, u16 addr, u16 *val)
2740{
2741        struct rtw_coex_info_req req = {0};
2742        struct sk_buff *skb;
2743        __le16 le_addr;
2744        u8 *payload;
2745
2746        le_addr = cpu_to_le16(addr);
2747        req.op_code = BT_MP_INFO_OP_READ_REG;
2748        req.para1 = type;
2749        req.para2 = le16_get_bits(le_addr, GENMASK(7, 0));
2750        req.para3 = le16_get_bits(le_addr, GENMASK(15, 8));
2751        skb = rtw_coex_info_request(rtwdev, &req);
2752        if (!skb) {
2753                *val = 0xeaea;
2754                return false;
2755        }
2756
2757        payload = get_payload_from_coex_resp(skb);
2758        *val = GET_COEX_RESP_BT_REG_VAL(payload);
2759
2760        return true;
2761}
2762
2763static bool rtw_coex_get_bt_patch_version(struct rtw_dev *rtwdev,
2764                                          u32 *patch_version)
2765{
2766        struct rtw_coex_info_req req = {0};
2767        struct sk_buff *skb;
2768        u8 *payload;
2769        bool ret = false;
2770
2771        req.op_code = BT_MP_INFO_OP_PATCH_VER;
2772        skb = rtw_coex_info_request(rtwdev, &req);
2773        if (!skb)
2774                goto out;
2775
2776        payload = get_payload_from_coex_resp(skb);
2777        *patch_version = GET_COEX_RESP_BT_PATCH_VER(payload);
2778        ret = true;
2779
2780out:
2781        return ret;
2782}
2783
2784static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev,
2785                                              u32 *supported_version)
2786{
2787        struct rtw_coex_info_req req = {0};
2788        struct sk_buff *skb;
2789        u8 *payload;
2790        bool ret = false;
2791
2792        req.op_code = BT_MP_INFO_OP_SUPP_VER;
2793        skb = rtw_coex_info_request(rtwdev, &req);
2794        if (!skb)
2795                goto out;
2796
2797        payload = get_payload_from_coex_resp(skb);
2798        *supported_version = GET_COEX_RESP_BT_SUPP_VER(payload);
2799        ret = true;
2800
2801out:
2802        return ret;
2803}
2804
2805static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev,
2806                                              u32 *supported_feature)
2807{
2808        struct rtw_coex_info_req req = {0};
2809        struct sk_buff *skb;
2810        u8 *payload;
2811        bool ret = false;
2812
2813        req.op_code = BT_MP_INFO_OP_SUPP_FEAT;
2814        skb = rtw_coex_info_request(rtwdev, &req);
2815        if (!skb)
2816                goto out;
2817
2818        payload = get_payload_from_coex_resp(skb);
2819        *supported_feature = GET_COEX_RESP_BT_SUPP_FEAT(payload);
2820        ret = true;
2821
2822out:
2823        return ret;
2824}
2825
2826struct rtw_coex_sta_stat_iter_data {
2827        struct rtw_vif *rtwvif;
2828        struct seq_file *file;
2829};
2830
2831static void rtw_coex_sta_stat_iter(void *data, struct ieee80211_sta *sta)
2832{
2833        struct rtw_coex_sta_stat_iter_data *sta_iter_data = data;
2834        struct rtw_vif *rtwvif = sta_iter_data->rtwvif;
2835        struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
2836        struct seq_file *m = sta_iter_data->file;
2837        struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
2838        u8 rssi;
2839
2840        if (si->vif != vif)
2841                return;
2842
2843        rssi = ewma_rssi_read(&si->avg_rssi);
2844        seq_printf(m, "\tPeer %3d\n", si->mac_id);
2845        seq_printf(m, "\t\t%-24s = %d\n", "RSSI", rssi);
2846        seq_printf(m, "\t\t%-24s = %d\n", "BW mode", si->bw_mode);
2847}
2848
2849struct rtw_coex_vif_stat_iter_data {
2850        struct rtw_dev *rtwdev;
2851        struct seq_file *file;
2852};
2853
2854static void rtw_coex_vif_stat_iter(void *data, u8 *mac,
2855                                   struct ieee80211_vif *vif)
2856{
2857        struct rtw_coex_vif_stat_iter_data *vif_iter_data = data;
2858        struct rtw_coex_sta_stat_iter_data sta_iter_data;
2859        struct rtw_dev *rtwdev = vif_iter_data->rtwdev;
2860        struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
2861        struct seq_file *m = vif_iter_data->file;
2862        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
2863
2864        seq_printf(m, "Iface on Port (%d)\n", rtwvif->port);
2865        seq_printf(m, "\t%-32s = %d\n",
2866                   "Beacon interval", bss_conf->beacon_int);
2867        seq_printf(m, "\t%-32s = %d\n",
2868                   "Network Type", rtwvif->net_type);
2869
2870        sta_iter_data.rtwvif = rtwvif;
2871        sta_iter_data.file = m;
2872        rtw_iterate_stas_atomic(rtwdev, rtw_coex_sta_stat_iter,
2873                                &sta_iter_data);
2874}
2875
2876void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
2877{
2878        struct rtw_chip_info *chip = rtwdev->chip;
2879        struct rtw_dm_info *dm_info = &rtwdev->dm_info;
2880        struct rtw_coex *coex = &rtwdev->coex;
2881        struct rtw_coex_stat *coex_stat = &coex->stat;
2882        struct rtw_coex_dm *coex_dm = &coex->dm;
2883        struct rtw_hal *hal = &rtwdev->hal;
2884        struct rtw_efuse *efuse = &rtwdev->efuse;
2885        struct rtw_fw_state *fw = &rtwdev->fw;
2886        struct rtw_coex_vif_stat_iter_data vif_iter_data;
2887        u8 reason = coex_dm->reason;
2888        u8 sys_lte;
2889        u16 score_board_WB, score_board_BW;
2890        u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc;
2891        u32 lte_coex, bt_coex;
2892        u32 bt_hi_pri, bt_lo_pri;
2893        int i;
2894
2895        score_board_BW = rtw_coex_read_scbd(rtwdev);
2896        score_board_WB = coex_stat->score_board;
2897        wl_reg_6c0 = rtw_read32(rtwdev, 0x6c0);
2898        wl_reg_6c4 = rtw_read32(rtwdev, 0x6c4);
2899        wl_reg_6c8 = rtw_read32(rtwdev, 0x6c8);
2900        wl_reg_6cc = rtw_read32(rtwdev, 0x6cc);
2901        wl_reg_778 = rtw_read32(rtwdev, 0x778);
2902        bt_hi_pri = rtw_read32(rtwdev, 0x770);
2903        bt_lo_pri = rtw_read32(rtwdev, 0x774);
2904        rtw_write8(rtwdev, 0x76e, 0xc);
2905        sys_lte = rtw_read8(rtwdev, 0x73);
2906        lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38);
2907        bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54);
2908
2909        if (!coex_stat->bt_disabled && !coex_stat->bt_mailbox_reply) {
2910                rtw_coex_get_bt_supported_version(rtwdev,
2911                                &coex_stat->bt_supported_version);
2912                rtw_coex_get_bt_patch_version(rtwdev, &coex_stat->patch_ver);
2913                rtw_coex_get_bt_supported_feature(rtwdev,
2914                                &coex_stat->bt_supported_feature);
2915                rtw_coex_get_bt_reg(rtwdev, 3, 0xae, &coex_stat->bt_reg_vendor_ae);
2916                rtw_coex_get_bt_reg(rtwdev, 3, 0xac, &coex_stat->bt_reg_vendor_ac);
2917
2918                if (coex_stat->patch_ver != 0)
2919                        coex_stat->bt_mailbox_reply = true;
2920        }
2921
2922        seq_printf(m, "**********************************************\n");
2923        seq_printf(m, "\t\tBT Coexist info %x\n", chip->id);
2924        seq_printf(m, "**********************************************\n");
2925        seq_printf(m, "%-40s = %s/ %d\n",
2926                   "Mech/ RFE",
2927                   efuse->share_ant ? "Shared" : "Non-Shared",
2928                   efuse->rfe_option);
2929        seq_printf(m, "%-40s = %08x/ 0x%02x/ 0x%08x %s\n",
2930                   "Coex Ver/ BT Dez/ BT Rpt",
2931                   chip->coex_para_ver, chip->bt_desired_ver,
2932                   coex_stat->bt_supported_version,
2933                   coex_stat->bt_disabled ? "(BT disabled)" :
2934                   coex_stat->bt_supported_version >= chip->bt_desired_ver ?
2935                   "(Match)" : "(Mismatch)");
2936        seq_printf(m, "%-40s = %s/ %u/ %d\n",
2937                   "Role/ RoleSwCnt/ IgnWL/ Feature",
2938                   coex_stat->bt_slave ? "Slave" : "Master",
2939                   coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH],
2940                   coex_dm->ignore_wl_act);
2941        seq_printf(m, "%-40s = %u.%u/ 0x%x/ %c\n",
2942                   "WL FW/ BT FW/ KT",
2943                   fw->version, fw->sub_version,
2944                   coex_stat->patch_ver, coex_stat->kt_ver + 65);
2945        seq_printf(m, "%-40s = %u/ %u/ %u/ ch-(%u)\n",
2946                   "AFH Map",
2947                   coex_dm->wl_ch_info[0], coex_dm->wl_ch_info[1],
2948                   coex_dm->wl_ch_info[2], hal->current_channel);
2949
2950        seq_printf(m, "**********************************************\n");
2951        seq_printf(m, "\t\tBT Status\n");
2952        seq_printf(m, "**********************************************\n");
2953        seq_printf(m, "%-40s = %s/ %ddBm/ %u/ %u\n",
2954                   "BT status/ rssi/ retry/ pop",
2955                   coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE ? "non-conn" :
2956                   coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE ? "conn-idle" : "busy",
2957                   coex_stat->bt_rssi - 100,
2958                   coex_stat->cnt_bt[COEX_CNT_BT_RETRY],
2959                   coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]);
2960        seq_printf(m, "%-40s = %s%s%s%s%s (multi-link %d)\n",
2961                   "Profiles",
2962                   coex_stat->bt_a2dp_exist ? (coex_stat->bt_a2dp_sink ?
2963                                               "A2DP sink," : "A2DP,") : "",
2964                   coex_stat->bt_hfp_exist ? "HFP," : "",
2965                   coex_stat->bt_hid_exist ?
2966                   (coex_stat->bt_ble_exist ? "HID(RCU)," :
2967                    coex_stat->bt_hid_slot >= 2 ? "HID(4/18)" :
2968                    "HID(2/18),") : "",
2969                   coex_stat->bt_pan_exist ? coex_stat->bt_opp_exist ?
2970                   "OPP," : "PAN," : "",
2971                   coex_stat->bt_ble_voice ? "Voice," : "",
2972                   coex_stat->bt_multi_link);
2973        seq_printf(m, "%-40s = %u/ %u/ %u/ 0x%08x\n",
2974                   "Reinit/ Relink/ IgnWl/ Feature",
2975                   coex_stat->cnt_bt[COEX_CNT_BT_REINIT],
2976                   coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK],
2977                   coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT],
2978                   coex_stat->bt_supported_feature);
2979        seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",
2980                   "Page/ Inq/ iqk/ iqk fail",
2981                   coex_stat->cnt_bt[COEX_CNT_BT_PAGE],
2982                   coex_stat->cnt_bt[COEX_CNT_BT_INQ],
2983                   coex_stat->cnt_bt[COEX_CNT_BT_IQK],
2984                   coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]);
2985        seq_printf(m, "%-40s = 0x%04x/ 0x%04x/ 0x%04x/ 0x%04x\n",
2986                   "0xae/ 0xac/ score board (W->B)/ (B->W)",
2987                   coex_stat->bt_reg_vendor_ae,
2988                   coex_stat->bt_reg_vendor_ac,
2989                   score_board_WB, score_board_BW);
2990        seq_printf(m, "%-40s = %u/%u, %u/%u\n",
2991                   "Hi-Pri TX/RX, Lo-Pri TX/RX",
2992                   bt_hi_pri & 0xffff, bt_hi_pri >> 16,
2993                   bt_lo_pri & 0xffff, bt_lo_pri >> 16);
2994        for (i = 0; i < COEX_BTINFO_SRC_BT_IQK; i++)
2995                seq_printf(m, "%-40s = %7ph\n",
2996                           rtw_coex_get_bt_info_src_string(i),
2997                           coex_stat->bt_info_c2h[i]);
2998
2999        seq_printf(m, "**********************************************\n");
3000        seq_printf(m, "\t\tWiFi Status\n");
3001        seq_printf(m, "**********************************************\n");
3002        seq_printf(m, "%-40s = %d\n",
3003                   "Scanning", test_bit(RTW_FLAG_SCANNING, rtwdev->flags));
3004        seq_printf(m, "%-40s = %u/ TX %d Mbps/ RX %d Mbps\n",
3005                   "G_busy/ TX/ RX",
3006                   coex_stat->wl_gl_busy,
3007                   rtwdev->stats.tx_throughput, rtwdev->stats.rx_throughput);
3008        seq_printf(m, "%-40s = %u/ %u/ %u\n",
3009                   "IPS/ Low Power/ PS mode",
3010                   test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags),
3011                   test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags),
3012                   rtwdev->lps_conf.mode);
3013
3014        vif_iter_data.rtwdev = rtwdev;
3015        vif_iter_data.file = m;
3016        rtw_iterate_vifs_atomic(rtwdev, rtw_coex_vif_stat_iter, &vif_iter_data);
3017
3018        seq_printf(m, "**********************************************\n");
3019        seq_printf(m, "\t\tMechanism\n");
3020        seq_printf(m, "**********************************************\n");
3021        seq_printf(m, "%-40s = %5ph (case-%d)\n",
3022                   "TDMA",
3023                   coex_dm->ps_tdma_para, coex_dm->cur_ps_tdma);
3024        seq_printf(m, "%-40s = %d\n",
3025                   "Timer base", coex_stat->tdma_timer_base);
3026        seq_printf(m, "%-40s = %d/ 0x%08x/ 0x%08x/ 0x%08x\n",
3027                   "Table/ 0x6c0/ 0x6c4/ 0x6c8",
3028                   coex_dm->cur_table, wl_reg_6c0, wl_reg_6c4, wl_reg_6c8);
3029        seq_printf(m, "%-40s = 0x%08x/ 0x%08x/ reason (%s)\n",
3030                   "0x778/ 0x6cc/ Reason",
3031                   wl_reg_778, wl_reg_6cc, rtw_coex_get_reason_string(reason));
3032        seq_printf(m, "%-40s = %u/ %u/ %u/ %u/ %u\n",
3033                   "Null All/ Retry/ Ack/ BT Empty/ BT Late",
3034                   coex_stat->wl_fw_dbg_info[1], coex_stat->wl_fw_dbg_info[2],
3035                   coex_stat->wl_fw_dbg_info[3], coex_stat->wl_fw_dbg_info[4],
3036                   coex_stat->wl_fw_dbg_info[5]);
3037        seq_printf(m, "%-40s = %u/ %u/ %s/ %u\n",
3038                   "Cnt TDMA Toggle/ Lk 5ms/ Lk 5ms on/ FW",
3039                   coex_stat->wl_fw_dbg_info[6],
3040                   coex_stat->wl_fw_dbg_info[7],
3041                   coex_stat->wl_slot_extend ? "Yes" : "No",
3042                   coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]);
3043
3044        seq_printf(m, "**********************************************\n");
3045        seq_printf(m, "\t\tHW setting\n");
3046        seq_printf(m, "**********************************************\n");
3047        seq_printf(m, "%-40s = %s/ %s\n",
3048                   "LTE Coex/ Path Owner",
3049                   lte_coex & BIT(7) ? "ON" : "OFF",
3050                   sys_lte & BIT(2) ? "WL" : "BT");
3051        seq_printf(m, "%-40s = RF:%s_BB:%s/ RF:%s_BB:%s/ %s\n",
3052                   "GNT_WL_CTRL/ GNT_BT_CTRL/ Dbg",
3053                   lte_coex & BIT(12) ? "SW" : "HW",
3054                   lte_coex & BIT(8) ? "SW" : "HW",
3055                   lte_coex & BIT(14) ? "SW" : "HW",
3056                   lte_coex & BIT(10) ? "SW" : "HW",
3057                   sys_lte & BIT(3) ? "On" : "Off");
3058        seq_printf(m, "%-40s = %lu/ %lu\n",
3059                   "GNT_WL/ GNT_BT",
3060                   (bt_coex & BIT(2)) >> 2, (bt_coex & BIT(3)) >> 3);
3061        seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",
3062                   "CRC OK CCK/ OFDM/ HT/ VHT",
3063                   dm_info->cck_ok_cnt, dm_info->ofdm_ok_cnt,
3064                   dm_info->ht_ok_cnt, dm_info->vht_ok_cnt);
3065        seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",
3066                   "CRC ERR CCK/ OFDM/ HT/ VHT",
3067                   dm_info->cck_err_cnt, dm_info->ofdm_err_cnt,
3068                   dm_info->ht_err_cnt, dm_info->vht_err_cnt);
3069        seq_printf(m, "%-40s = %s/ %s/ %s/ %u\n",
3070                   "HiPr/ Locking/ Locked/ Noisy",
3071                   coex_stat->wl_hi_pri_task1 ? "Y" : "N",
3072                   coex_stat->wl_cck_lock ? "Y" : "N",
3073                   coex_stat->wl_cck_lock_ever ? "Y" : "N",
3074                   coex_stat->wl_noisy_level);
3075
3076        rtw_coex_set_coexinfo_hw(rtwdev, m);
3077}
3078#endif /* CONFIG_RTW88_DEBUGFS */
3079