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