/******************************************************************************
*
* Copyright(c) 2016 - 2017 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*****************************************************************************/
#include "mp_precomp.h"
#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1)
static u8 *trace_buf = &gl_btc_trace_buf[0];
static const u32 coex_ver_date = 20200103;
static const u32 coex_ver = 0x17;
static const u32 wl_fw_desired_ver = 0x70011;
static u8
rtw_btc_rssi_state(struct btc_coexist *btc, u8 pre_state,
u8 rssi, u8 rssi_thresh)
{
const struct btc_chip_para *chip_para = btc->chip_para;
u8 next_state, tol = chip_para->rssi_tolerance;
if (pre_state == BTC_RSSI_STATE_LOW ||
pre_state == BTC_RSSI_STATE_STAY_LOW) {
if (rssi >= (rssi_thresh + tol))
next_state = BTC_RSSI_STATE_HIGH;
else
next_state = BTC_RSSI_STATE_STAY_LOW;
} else {
if (rssi < rssi_thresh)
next_state = BTC_RSSI_STATE_LOW;
else
next_state = BTC_RSSI_STATE_STAY_HIGH;
}
return next_state;
}
static void
rtw_btc_limited_tx(struct btc_coexist *btc, boolean force_exec,
boolean tx_limit_en, boolean ampdu_limit_en)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
const struct btc_chip_para *chip_para = btc->chip_para;
boolean wl_b_mode = FALSE;
if (!chip_para->scbd_support)
return;
/* Force Max Tx retry limit = 8 */
if (!force_exec && tx_limit_en == coex_sta->wl_tx_limit_en &&
ampdu_limit_en == coex_sta->wl_ampdu_limit_en)
return;
/* backup MAC reg */
if (!coex_sta->wl_tx_limit_en) {
coex_sta->wl_arfb1 = btc->btc_read_4byte(btc, REG_DARFRC);
coex_sta->wl_arfb2 = btc->btc_read_4byte(btc, REG_DARFRCH);
coex_sta->wl_txlimit = btc->btc_read_2byte(btc,
REG_RETRY_LIMIT);
}
if (!coex_sta->wl_ampdu_limit_en)
coex_sta->wl_ampdulen =
btc->btc_read_1byte(btc, REG_AMPDU_MAX_TIME_V1);
coex_sta->wl_tx_limit_en = tx_limit_en;
coex_sta->wl_ampdu_limit_en = ampdu_limit_en;
if (tx_limit_en) {
/* Set BT polluted packet on for Tx rate adaptive
* Set queue life time to avoid can't reach tx retry limit
* if tx is always break by GNT_BT.
*/
btc->btc_write_1byte_bitmask(btc, REG_TX_HANG_CTRL,
BIT_EN_GNT_BT_AWAKE, 0x1);
/* queue life time can't on if 2-port */
if (link_info_ext->num_of_active_port <= 1)
btc->btc_write_1byte_bitmask(btc, REG_LIFETIME_EN, 0xf,
0xf);
/* Max Tx retry limit = 8*/
btc->btc_write_2byte(btc, REG_RETRY_LIMIT, 0x0808);
btc->btc_get(btc, BTC_GET_BL_WIFI_UNDER_B_MODE, &wl_b_mode);
/* Auto rate fallback step within 8 retry*/
if (wl_b_mode) {
btc->btc_write_4byte(btc, REG_DARFRC, 0x1000000);
btc->btc_write_4byte(btc, REG_DARFRCH, 0x1010101);
} else {
btc->btc_write_4byte(btc, REG_DARFRC, 0x1000000);
btc->btc_write_4byte(btc, REG_DARFRCH, 0x4030201);
}
} else {
/* Set BT polluted packet on for Tx rate adaptive not
*including Tx retry break by PTA, 0x45c[19] =1
*/
btc->btc_write_1byte_bitmask(btc, REG_TX_HANG_CTRL,
BIT_EN_GNT_BT_AWAKE, 0x0);
/* Set queue life time to avoid can't reach tx retry limit
* if tx is always break by GNT_BT.
*/
btc->btc_write_1byte_bitmask(btc, REG_LIFETIME_EN, 0xf, 0x0);
/* Recovery Max Tx retry limit*/
btc->btc_write_2byte(btc, REG_RETRY_LIMIT,
coex_sta->wl_txlimit);
btc->btc_write_4byte(btc, REG_DARFRC, coex_sta->wl_arfb1);
btc->btc_write_4byte(btc, REG_DARFRCH, coex_sta->wl_arfb2);
}
if (ampdu_limit_en)
btc->btc_write_1byte(btc, REG_AMPDU_MAX_TIME_V1, 0x20);
else
btc->btc_write_1byte(btc, REG_AMPDU_MAX_TIME_V1,
coex_sta->wl_ampdulen);
}
static void
rtw_btc_low_penalty_ra(struct btc_coexist *btc, boolean force_exec,
boolean low_penalty_ra, u8 thres)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
if (!force_exec) {
if (low_penalty_ra == coex_dm->cur_low_penalty_ra &&
thres == coex_sta->wl_ra_thres)
return;
}
if (low_penalty_ra)
btc->btc_phydm_modify_RA_PCR_threshold(btc, 0, thres);
else
btc->btc_phydm_modify_RA_PCR_threshold(btc, 0, 0);
coex_dm->cur_low_penalty_ra = low_penalty_ra;
coex_sta->wl_ra_thres = thres;
}
static void
rtw_btc_limited_wl(struct btc_coexist *btc)
{
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
if (link_info_ext->is_all_under_5g ||
link_info_ext->num_of_active_port == 0 ||
coex_dm->bt_status == BTC_BTSTATUS_NCON_IDLE) {
rtw_btc_low_penalty_ra(btc, NM_EXCU, FALSE, 0);
rtw_btc_limited_tx(btc, NM_EXCU, FALSE, FALSE);
} else if (link_info_ext->num_of_active_port > 1) {
rtw_btc_low_penalty_ra(btc, NM_EXCU, TRUE, 30);
rtw_btc_limited_tx(btc, NM_EXCU, TRUE, TRUE);
} else {
if (link_info_ext->is_p2p_connected)
rtw_btc_low_penalty_ra(btc, NM_EXCU, TRUE, 30);
else
rtw_btc_low_penalty_ra(btc, NM_EXCU, TRUE, 15);
if (coex_sta->bt_hid_exist || coex_sta->bt_hid_pair_num > 0 ||
coex_sta->bt_hfp_exist)
rtw_btc_limited_tx(btc, NM_EXCU, TRUE, TRUE);
else
rtw_btc_limited_tx(btc, NM_EXCU, TRUE, FALSE);
}
}
static void
rtw_btc_mailbox_operation(struct btc_coexist *btc, u8 h2c_id, u8 h2c_len,
u8 *h2c_para)
{
const struct btc_chip_para *chip_para = btc->chip_para;
u8 buf[6] = {0};
if (chip_para->mailbox_support) {
btc->btc_fill_h2c(btc, h2c_id, h2c_len, h2c_para);
return;
}
switch (h2c_id) {
case 0x61:
buf[0] = 3;
buf[1] = 0x1; /* polling enable, 1=enable, 0=disable */
buf[2] = 0x2; /* polling time in seconds */
buf[3] = 0x1; /* auto report enable, 1=enable, 0=disable */
btc->btc_set(btc, BTC_SET_ACT_CTRL_BT_INFO, (void *)&buf[0]);
break;
case 0x62:
buf[0] = 4;
buf[1] = 0x3; /* OP_Code */
buf[2] = 0x2; /* OP_Code_Length */
buf[3] = (h2c_para[0] != 0) ? 0x1 : 0x0; /* OP_Code_Content */
buf[4] = h2c_para[0];/* pwr_level */
btc->btc_set(btc, BTC_SET_ACT_CTRL_BT_COEX, (void *)&buf[0]);
break;
case 0x63:
buf[0] = 3;
buf[1] = 0x1; /* OP_Code */
buf[2] = 0x1; /* OP_Code_Length */
buf[3] = (h2c_para[0] == 0x1) ? 0x1 : 0x0; /* OP_Code_Content */
btc->btc_set(btc, BTC_SET_ACT_CTRL_BT_COEX, (void *)&buf[0]);
break;
case 0x66:
buf[0] = 5;
buf[1] = 0x5; /* OP_Code */
buf[2] = 0x3; /* OP_Code_Length */
buf[3] = h2c_para[0]; /* OP_Code_Content */
buf[4] = h2c_para[1];
buf[5] = h2c_para[2];
btc->btc_set(btc, BTC_SET_ACT_CTRL_BT_COEX, (void *)&buf[0]);
break;
}
}
static boolean
rtw_btc_freerun_check(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
u8 bt_rssi;
if (coex_sta->force_freerun)
return TRUE;
if (coex_sta->force_tdd)
return FALSE;
if (coex_sta->bt_disabled)
return FALSE;
if (btc->board_info.btdm_ant_num == 1 ||
btc->board_info.ant_distance <= 5 || !coex_sta->wl_gl_busy)
return FALSE;
if (btc->board_info.ant_distance >= 40 ||
coex_sta->bt_hid_pair_num >= 2)
return TRUE;
/* ant_distance = 5 ~ 40 */
if (BTC_RSSI_HIGH(coex_dm->wl_rssi_state[1]) &&
BTC_RSSI_HIGH(coex_dm->bt_rssi_state[0]))
return TRUE;
if (link_info_ext->traffic_dir == BTC_WIFI_TRAFFIC_TX)
bt_rssi = coex_dm->bt_rssi_state[0];
else
bt_rssi = coex_dm->bt_rssi_state[1];
if (BTC_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
BTC_RSSI_HIGH(bt_rssi) &&
coex_sta->cnt_wl[BTC_CNT_WL_SCANAP] <= 5)
return TRUE;
return FALSE;
}
static void
rtw_btc_wl_leakap(struct btc_coexist *btc, boolean enable)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 h2c_para[2] = {0xc, 0};
if (coex_sta->wl_leak_ap == enable)
return;
if (enable) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], turn on Leak-AP Rx Protection!!\n");
h2c_para[1] = 0x0;
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], turn off Leak-AP Rx Protection!!\n");
h2c_para[1] = 0x1;
}
BTC_TRACE(trace_buf);
btc->btc_fill_h2c(btc, 0x69, 2, h2c_para);
coex_sta->wl_leak_ap = enable;
coex_sta->cnt_wl[BTC_CNT_WL_LEAKAP_NORX] = 0;
}
static void
rtw_btc_wl_ccklock_action(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 h2c_parameter[2] = {0}, ap_leak_rx_cnt = 0;
boolean wifi_busy = FALSE;
if (btc->manual_control || btc->stop_coex_dm)
return;
if (!coex_sta->wl_gl_busy ||
coex_sta->wl_iot_peer == BTC_IOT_PEER_CISCO) {
coex_sta->cnt_wl[BTC_CNT_WL_LEAKAP_NORX] = 0;
return;
}
ap_leak_rx_cnt = coex_sta->wl_fw_dbg_info[7];
/* Get realtime wifi_busy status */
btc->btc_get(btc, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
if (coex_sta->wl_leak_ap && coex_sta->wl_force_lps_ctrl &&
!coex_sta->wl_cck_lock_ever) {
if (ap_leak_rx_cnt <= 5 && wifi_busy)
coex_sta->cnt_wl[BTC_CNT_WL_LEAKAP_NORX]++;
else
coex_sta->cnt_wl[BTC_CNT_WL_LEAKAP_NORX] = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], Leak-AP Rx extend cnt = %d!!\n",
coex_sta->cnt_wl[BTC_CNT_WL_LEAKAP_NORX]);
BTC_TRACE(trace_buf);
/* If 7-streak ap_leak_rx_cnt <= 5, turn off leak-AP for TP*/
if (coex_sta->cnt_wl[BTC_CNT_WL_LEAKAP_NORX] >= 7)
rtw_btc_wl_leakap(btc, FALSE);
} else if (!coex_sta->wl_leak_ap && coex_sta->wl_cck_lock) {
rtw_btc_wl_leakap(btc, TRUE);
}
}
static void
rtw_btc_wl_ccklock_detect(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
boolean is_cck_lock_rate = FALSE;
if (coex_dm->bt_status == BTC_BTSTATUS_INQ_PAGE ||
coex_sta->bt_setup_link)
return;
if (coex_sta->wl_rx_rate <= BTC_CCK_2 ||
coex_sta->wl_rts_rx_rate <= BTC_CCK_2)
is_cck_lock_rate = TRUE;
if (link_info_ext->is_connected && coex_sta->wl_gl_busy &&
BTC_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
(coex_dm->bt_status == BTC_BTSTATUS_ACL_BUSY ||
coex_dm->bt_status == BTC_BTSTATUS_ACL_SCO_BUSY ||
coex_dm->bt_status == BTC_BTSTATUS_SCO_BUSY)) {
if (is_cck_lock_rate) {
coex_sta->wl_cck_lock = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], cck locking...\n");
BTC_TRACE(trace_buf);
} else {
coex_sta->wl_cck_lock = FALSE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], cck unlock...\n");
BTC_TRACE(trace_buf);
}
} else {
coex_sta->wl_cck_lock = FALSE;
}
/* CCK lock identification */
if (coex_sta->wl_cck_lock && !coex_sta->wl_cck_lock_pre)
btc->btc_set_timer(btc, BTC_TIMER_WL_CCKLOCK, 3);
coex_sta->wl_cck_lock_pre = coex_sta->wl_cck_lock;
}
static void
rtw_btc_set_extend_btautoslot(struct btc_coexist *btc, u8 thres)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 h2c_para[2] = {0x9, 0x32};
if (coex_sta->bt_ext_autoslot_thres == thres)
return;
h2c_para[1] = thres; /* thres must be 50 ~ 80*/
coex_sta->bt_ext_autoslot_thres = h2c_para[1];
btc->btc_fill_h2c(btc, 0x69, 2, h2c_para);
}
static void
rtw_btc_set_tdma_timer_base(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u16 tbtt_interval = 100;
u8 h2c_para[2] = {0xb, 0x1};
btc->btc_get(btc, BTC_GET_U2_BEACON_PERIOD, &tbtt_interval);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], tbtt_interval = %d\n", tbtt_interval);
BTC_TRACE(trace_buf);
/* Add for JIRA coex-256 */
if (type == 3 && tbtt_interval >= 100) { /* 50ms-slot */
if (coex_sta->tdma_timer_base == 3)
return;
h2c_para[1] = (tbtt_interval / 50) - 1;
h2c_para[1] = h2c_para[1] | 0xc0; /* 50ms-slot */
coex_sta->tdma_timer_base = 3;
} else if (tbtt_interval < 80 && tbtt_interval > 0) {
if (coex_sta->tdma_timer_base == 2)
return;
h2c_para[1] = (100 / tbtt_interval);
if (100 % tbtt_interval != 0)
h2c_para[1] = h2c_para[1] + 1;
h2c_para[1] = h2c_para[1] & 0x3f;
coex_sta->tdma_timer_base = 2;
} else if (tbtt_interval >= 180) {
if (coex_sta->tdma_timer_base == 1)
return;
h2c_para[1] = (tbtt_interval / 100);
if (tbtt_interval % 100 <= 80)
h2c_para[1] = h2c_para[1] - 1;
h2c_para[1] = h2c_para[1] & 0x3f;
h2c_para[1] = h2c_para[1] | 0x80;
coex_sta->tdma_timer_base = 1;
} else {
if (coex_sta->tdma_timer_base == 0)
return;
h2c_para[1] = 0x1;
coex_sta->tdma_timer_base = 0;
}
btc->btc_fill_h2c(btc, 0x69, 2, h2c_para);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): h2c_0x69 = 0x%x\n", __func__, h2c_para[1]);
BTC_TRACE(trace_buf);
/* no 5ms_wl_slot_extend for 4-slot mode */
if (coex_sta->tdma_timer_base == 3)
rtw_btc_wl_ccklock_action(btc);
}
static void
rtw_btc_set_wl_pri_mask(struct btc_coexist *btc, u8 bitmap, u8 data)
{
u32 addr;
addr = REG_BT_COEX_TABLE_H + (bitmap / 8);
bitmap = bitmap % 8;
btc->btc_write_1byte_bitmask(btc, addr, BIT(bitmap), data);
}
static void
rtw_btc_set_bt_golden_rx_range(struct btc_coexist *btc, boolean force_exec,
u8 profile_id, u8 shift_level)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u16 para;
if (profile_id > 3)
return;
if (!force_exec &&
shift_level == coex_sta->bt_golden_rx_shift[profile_id])
return;
coex_sta->bt_golden_rx_shift[profile_id] = shift_level;
para = (profile_id << 8) | ((0x100 - shift_level) & 0xff);
btc->btc_set(btc, BTC_SET_BL_BT_GOLDEN_RX_RANGE, ¶);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): para = 0x%04x\n", __func__, para);
BTC_TRACE(trace_buf);
}
static void
rtw_btc_query_bt_info(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 h2c_parameter[1] = {0x1};
if (coex_sta->bt_disabled)
return;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_mailbox_operation(btc, 0x61, 1, h2c_parameter);
}
static void
rtw_btc_gnt_debug(struct btc_coexist *btc, boolean isenable)
{
if (!isenable)
btc->btc_write_1byte_bitmask(btc, 0x73, 0x8, 0x0);
else
btc->chip_para->chip_setup(btc, BTC_CSETUP_GNT_DEBUG);
}
static void
rtw_btc_gnt_workaround(struct btc_coexist *btc, boolean force_exec, u8 mode)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (!force_exec) {
if (coex_sta->gnt_workaround_state == coex_sta->wl_coex_mode)
return;
}
coex_sta->gnt_workaround_state = coex_sta->wl_coex_mode;
btc->chip_para->chip_setup(btc, BTC_CSETUP_GNT_FIX);
}
static void
rtw_btc_monitor_bt_enable(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
boolean bt_disabled = FALSE;
u16 scbd;
if (chip_para->scbd_support) {
btc->btc_read_scbd(btc, &scbd);
bt_disabled = (scbd & BTC_SCBD_BT_ONOFF) ? FALSE : TRUE;
} else {
if (coex_sta->cnt_bt[BTC_CNT_BT_DISABLE] >= 2)
bt_disabled = TRUE;
}
btc->btc_set(btc, BTC_SET_BL_BT_DISABLE, &bt_disabled);
if (coex_sta->bt_disabled != bt_disabled) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], BT is from %s to %s!!\n",
(coex_sta->bt_disabled ? "disabled" : "enabled"),
(bt_disabled ? "disabled" : "enabled"));
BTC_TRACE(trace_buf);
coex_sta->bt_disabled = bt_disabled;
coex_sta->bt_supported_feature = 0;
coex_sta->bt_supported_version = 0;
coex_sta->bt_ble_scan_type = 0;
coex_sta->bt_ble_scan_para[0] = 0;
coex_sta->bt_ble_scan_para[1] = 0;
coex_sta->bt_ble_scan_para[2] = 0;
coex_sta->bt_reg_vendor_ac = 0xffff;
coex_sta->bt_reg_vendor_ae = 0xffff;
coex_sta->bt_a2dp_vendor_id = 0;
coex_sta->bt_a2dp_device_name = 0;
coex_sta->bt_iqk_state = 0;
coex_dm->cur_bt_lna_lvl = 0;
btc->bt_info.bt_get_fw_ver = 0;
/*for win10 BT disable->enable trigger wifi scan issue */
if (!coex_sta->bt_disabled) {
coex_sta->bt_reenable = TRUE;
btc->btc_set_timer(btc, BTC_TIMER_BT_REENABLE, 15);
} else {
coex_sta->bt_reenable = FALSE;
}
}
}
static void
rtw_btc_update_bt_sut_info(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u32 val = 0;
if (coex_sta->bt_profile_num == 0) {
/* clear golden rx range if no PAN exist */
if (coex_sta->bt_golden_rx_shift[3] != 0)
rtw_btc_set_bt_golden_rx_range(btc, FC_EXCU, 3, 0);
return;
}
if (coex_sta->bt_a2dp_exist)
rtw_btc_set_bt_golden_rx_range(btc, FC_EXCU, 2, 0);
else
coex_sta->bt_sut_pwr_lvl[2] = 0xff;
if (coex_sta->bt_hfp_exist)
rtw_btc_set_bt_golden_rx_range(btc, FC_EXCU, 0, 0);
else
coex_sta->bt_sut_pwr_lvl[0] = 0xff;
if (coex_sta->bt_hid_exist)
rtw_btc_set_bt_golden_rx_range(btc, FC_EXCU, 1, 0);
else
coex_sta->bt_sut_pwr_lvl[1] = 0xff;
if (coex_sta->bt_pan_exist) {
rtw_btc_set_bt_golden_rx_range(btc, FC_EXCU, 3,
coex_sta->bt_golden_rx_shift[3]);
} else {
coex_sta->bt_golden_rx_shift[3] = 0;
coex_sta->bt_sut_pwr_lvl[3] = 0xff;
}
}
static void
rtw_btc_update_wl_link_info(struct btc_coexist *btc, u8 reason)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_wifi_link_info_ext *linfo_ext = &btc->wifi_link_info_ext;
struct btc_wifi_link_info linfo;
const struct btc_chip_para *chip_para = btc->chip_para;
u8 wifi_central_chnl = 0, num_of_wifi_link = 0, i, rssi_state;
u32 wifi_link_status = 0, wifi_bw;
s32 wl_rssi;
boolean isunder5G = FALSE, ismcc25g = FALSE, is_p2p_connected = FALSE,
plus_bt = FALSE;
btc->btc_get(btc, BTC_GET_BL_WIFI_SCAN, &linfo_ext->is_scan);
btc->btc_get(btc, BTC_GET_BL_WIFI_LINK, &linfo_ext->is_link);
btc->btc_get(btc, BTC_GET_BL_WIFI_ROAM, &linfo_ext->is_roam);
btc->btc_get(btc, BTC_GET_BL_WIFI_LW_PWR_STATE, &linfo_ext->is_32k);
btc->btc_get(btc, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &linfo_ext->is_4way);
btc->btc_get(btc, BTC_GET_BL_WIFI_CONNECTED, &linfo_ext->is_connected);
btc->btc_get(btc, BTC_GET_U4_WIFI_TRAFFIC_DIR, &linfo_ext->traffic_dir);
btc->btc_get(btc, BTC_GET_U4_WIFI_BW, &linfo_ext->wifi_bw);
btc->btc_get(btc, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status);
linfo_ext->port_connect_status = wifi_link_status & 0xffff;
btc->btc_get(btc, BTC_GET_BL_WIFI_LINK_INFO, &linfo);
btc->wifi_link_info = linfo;
btc->btc_get(btc, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifi_central_chnl);
coex_sta->wl_center_ch = wifi_central_chnl;
btc->btc_get(btc, BTC_GET_S4_WIFI_RSSI, &wl_rssi);
for (i = 0; i < 4; i++) {
rssi_state = coex_dm->wl_rssi_state[i];
rssi_state = rtw_btc_rssi_state(btc, rssi_state,
(u8)(wl_rssi & 0xff),
chip_para->wl_rssi_step[i]);
coex_dm->wl_rssi_state[i] = rssi_state;
}
if (coex_sta->wl_linkscan_proc || coex_sta->wl_hi_pri_task1 ||
coex_sta->wl_hi_pri_task2 || coex_sta->wl_gl_busy)
btc->btc_write_scbd(btc, BTC_SCBD_SCAN, TRUE);
else
btc->btc_write_scbd(btc, BTC_SCBD_SCAN, FALSE);
/* Check scan/connect/special-pkt action first */
switch (reason) {
case BTC_RSN_5GSCANSTART:
case BTC_RSN_5GSWITCHBAND:
case BTC_RSN_5GCONSTART:
isunder5G = TRUE;
break;
case BTC_RSN_2GSCANSTART:
case BTC_RSN_2GSWITCHBAND:
case BTC_RSN_2GCONSTART:
isunder5G = FALSE;
break;
case BTC_RSN_2GCONFINISH:
case BTC_RSN_5GCONFINISH:
case BTC_RSN_2GMEDIA:
case BTC_RSN_5GMEDIA:
case BTC_RSN_BTINFO:
case BTC_RSN_PERIODICAL:
case BTC_RSN_TIMERUP:
case BTC_RSN_WLSTATUS:
case BTC_RSN_2GSPECIALPKT:
case BTC_RSN_5GSPECIALPKT:
default:
switch (linfo.link_mode) {
case BTC_LINK_5G_MCC_GO_STA:
case BTC_LINK_5G_MCC_GC_STA:
case BTC_LINK_5G_SCC_GO_STA:
case BTC_LINK_5G_SCC_GC_STA:
isunder5G = TRUE;
break;
case BTC_LINK_2G_MCC_GO_STA:
case BTC_LINK_2G_MCC_GC_STA:
case BTC_LINK_2G_SCC_GO_STA:
case BTC_LINK_2G_SCC_GC_STA:
isunder5G = FALSE;
break;
case BTC_LINK_25G_MCC_GO_STA:
case BTC_LINK_25G_MCC_GC_STA:
isunder5G = FALSE;
ismcc25g = TRUE;
break;
case BTC_LINK_ONLY_STA:
if (linfo.sta_center_channel > 14)
isunder5G = TRUE;
else
isunder5G = FALSE;
break;
case BTC_LINK_ONLY_GO:
case BTC_LINK_ONLY_GC:
case BTC_LINK_ONLY_AP:
default:
if (linfo.p2p_center_channel > 14)
isunder5G = TRUE;
else
isunder5G = FALSE;
break;
}
break;
}
linfo_ext->is_all_under_5g = isunder5G;
linfo_ext->is_mcc_25g = ismcc25g;
if (wifi_link_status & WIFI_STA_CONNECTED)
num_of_wifi_link++;
if (wifi_link_status & WIFI_AP_CONNECTED)
num_of_wifi_link++;
if (wifi_link_status & WIFI_P2P_GO_CONNECTED) {
if (!(wifi_link_status & WIFI_AP_CONNECTED))
num_of_wifi_link++;
is_p2p_connected = TRUE;
}
if (wifi_link_status & WIFI_P2P_GC_CONNECTED) {
num_of_wifi_link++;
is_p2p_connected = TRUE;
}
linfo_ext->num_of_active_port = num_of_wifi_link;
linfo_ext->is_p2p_connected = is_p2p_connected;
if (linfo.link_mode == BTC_LINK_ONLY_GO && linfo.bhotspot)
linfo_ext->is_ap_mode = TRUE;
else
linfo_ext->is_ap_mode = FALSE;
if (linfo_ext->is_p2p_connected && coex_sta->bt_link_exist)
plus_bt = TRUE;
btc->btc_set(btc, BTC_SET_BL_MIRACAST_PLUS_BT, &plus_bt);
if (linfo_ext->is_scan || linfo_ext->is_link ||
linfo_ext->is_roam || linfo_ext->is_4way ||
reason == BTC_RSN_2GSCANSTART ||
reason == BTC_RSN_2GSWITCHBAND ||
reason == BTC_RSN_2GCONSTART ||
reason == BTC_RSN_2GSPECIALPKT)
coex_sta->wl_linkscan_proc = TRUE;
else
coex_sta->wl_linkscan_proc = FALSE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], scan = %d, link = %d, roam = %d 4way = %d!!!\n",
linfo_ext->is_scan, linfo_ext->is_link,
linfo_ext->is_roam,
linfo_ext->is_4way);
BTC_TRACE(trace_buf);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], wifi_link_info: link_mode=%d, STA_Ch=%d, P2P_Ch=%d, AnyClient_Join_Go=%d !\n",
linfo.link_mode,
linfo.sta_center_channel,
linfo.p2p_center_channel,
linfo.bany_client_join_go);
BTC_TRACE(trace_buf);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], wifi_link_info: center_ch=%d, is_all_under_5g=%d, is_mcc_25g=%d!\n",
coex_sta->wl_center_ch,
linfo_ext->is_all_under_5g,
linfo_ext->is_mcc_25g);
BTC_TRACE(trace_buf);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], wifi_link_info: port_connect_status=0x%x, active_port_cnt=%d, P2P_Connect=%d!\n",
linfo_ext->port_connect_status,
linfo_ext->num_of_active_port,
linfo_ext->is_p2p_connected);
BTC_TRACE(trace_buf);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], Update reason = %s\n",
run_reason_string[reason]);
BTC_TRACE(trace_buf);
if (btc->manual_control || btc->stop_coex_dm)
return;
/* coex-276 P2P-Go beacon request can't release issue
* Only PCIe/USB can set 0x454[6] = 1 to solve this issue,
* WL SDIO/USB interface need driver support.
*/
#ifdef PLATFORM_WINDOWS
if (btc->chip_interface != BTC_INTF_SDIO)
btc->btc_write_1byte_bitmask(btc, REG_CCK_CHECK,
BIT_EN_BCN_PKT_REL, 0x1);
else
btc->btc_write_1byte_bitmask(btc, REG_CCK_CHECK,
BIT_EN_BCN_PKT_REL, 0x0);
#endif
}
static void
rtw_btc_update_bt_link_info(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
boolean bt_busy = FALSE, increase_scan_dev_num = FALSE,
scan_type_change = FALSE;
u8 i, scan_type, rssi_state;
/* update wl/bt rssi by btinfo */
for (i = 0; i < 4; i++) {
rssi_state = coex_dm->bt_rssi_state[i];
rssi_state = rtw_btc_rssi_state(btc, rssi_state,
coex_sta->bt_rssi,
chip_para->bt_rssi_step[i]);
coex_dm->bt_rssi_state[i] = rssi_state;
}
if (coex_sta->bt_ble_scan_en) {
scan_type = btc->btc_get_ble_scan_type_from_bt(btc);
if (scan_type != coex_sta->bt_ble_scan_type)
scan_type_change = TRUE;
coex_sta->bt_ble_scan_type = scan_type;
}
if (scan_type_change) {
u32 *p = NULL;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], BTinfo HiByte1[5] check, query BLE Scan type!!\n");
BTC_TRACE(trace_buf);
if ((coex_sta->bt_ble_scan_type & 0x1) == 0x1) {
coex_sta->bt_init_scan = TRUE;
p = &coex_sta->bt_ble_scan_para[0];
*p = btc->btc_get_ble_scan_para_from_bt(btc, 0x1);
} else {
coex_sta->bt_init_scan = FALSE;
}
if ((coex_sta->bt_ble_scan_type & 0x2) == 0x2) {
p = &coex_sta->bt_ble_scan_para[1];
*p = btc->btc_get_ble_scan_para_from_bt(btc, 0x2);
}
if ((coex_sta->bt_ble_scan_type & 0x4) == 0x4) {
p = &coex_sta->bt_ble_scan_para[2];
*p = btc->btc_get_ble_scan_para_from_bt(btc, 0x4);
}
}
coex_sta->bt_profile_num = 0;
/* set link exist status */
if (!(coex_sta->bt_info_lb2 & BTC_INFO_CONNECTION)) {
coex_sta->bt_link_exist = FALSE;
coex_sta->bt_pan_exist = FALSE;
coex_sta->bt_a2dp_exist = FALSE;
coex_sta->bt_hid_exist = FALSE;
coex_sta->bt_hfp_exist = FALSE;
coex_sta->bt_msft_mr_exist = FALSE;
} else { /* connection exists */
coex_sta->bt_link_exist = TRUE;
if (coex_sta->bt_info_lb2 & BTC_INFO_FTP) {
coex_sta->bt_pan_exist = TRUE;
coex_sta->bt_profile_num++;
} else {
coex_sta->bt_pan_exist = FALSE;
}
if (coex_sta->bt_info_lb2 & BTC_INFO_A2DP) {
coex_sta->bt_a2dp_exist = TRUE;
coex_sta->bt_profile_num++;
} else {
coex_sta->bt_a2dp_exist = FALSE;
}
if (coex_sta->bt_info_lb2 & BTC_INFO_HID) {
coex_sta->bt_hid_exist = TRUE;
coex_sta->bt_profile_num++;
} else {
coex_sta->bt_hid_exist = FALSE;
}
if (coex_sta->bt_info_lb2 & BTC_INFO_SCO_ESCO) {
coex_sta->bt_hfp_exist = TRUE;
coex_sta->bt_profile_num++;
} else {
coex_sta->bt_hfp_exist = FALSE;
}
}
if (coex_sta->bt_info_lb2 & BTC_INFO_INQ_PAGE) {
coex_dm->bt_status = BTC_BTSTATUS_INQ_PAGE;
} else if (!(coex_sta->bt_info_lb2 & BTC_INFO_CONNECTION)) {
coex_dm->bt_status = BTC_BTSTATUS_NCON_IDLE;
coex_sta->bt_multi_link_remain = FALSE;
} else if (coex_sta->bt_info_lb2 == BTC_INFO_CONNECTION) {
if (coex_sta->bt_msft_mr_exist)
coex_dm->bt_status = BTC_BTSTATUS_ACL_BUSY;
else
coex_dm->bt_status = BTC_BTSTATUS_CON_IDLE;
} else if ((coex_sta->bt_info_lb2 & BTC_INFO_SCO_ESCO) ||
(coex_sta->bt_info_lb2 & BTC_INFO_SCO_BUSY)) {
if (coex_sta->bt_info_lb2 & BTC_INFO_ACL_BUSY)
coex_dm->bt_status = BTC_BTSTATUS_ACL_SCO_BUSY;
else
coex_dm->bt_status = BTC_BTSTATUS_SCO_BUSY;
} else if (coex_sta->bt_info_lb2 & BTC_INFO_ACL_BUSY) {
coex_dm->bt_status = BTC_BTSTATUS_ACL_BUSY;
} else {
coex_dm->bt_status = BTC_BTSTATUS_MAX;
}
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s(), %s!!!\n",
__func__, bt_status_string[coex_dm->bt_status]);
BTC_TRACE(trace_buf);
if (coex_dm->bt_status == BTC_BTSTATUS_ACL_BUSY ||
coex_dm->bt_status == BTC_BTSTATUS_SCO_BUSY ||
coex_dm->bt_status == BTC_BTSTATUS_ACL_SCO_BUSY) {
bt_busy = TRUE;
increase_scan_dev_num = TRUE;
} else {
bt_busy = FALSE;
increase_scan_dev_num = FALSE;
}
btc->btc_set(btc, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
btc->btc_set(btc, BTC_SET_BL_INC_SCAN_DEV_NUM, &increase_scan_dev_num);
if (coex_sta->bt_profile_num != coex_sta->bt_profile_num_pre) {
rtw_btc_update_bt_sut_info(btc);
coex_sta->bt_profile_num_pre = coex_sta->bt_profile_num;
if (!coex_sta->bt_a2dp_exist) {
coex_sta->bt_a2dp_vendor_id = 0;
coex_sta->bt_a2dp_device_name = 0;
coex_sta->bt_a2dp_flush_time = 0;
}
}
coex_sta->cnt_bt[BTC_CNT_BT_INFOUPDATE]++;
}
static void
rtw_btc_update_wl_ch_info(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
struct btc_wifi_link_info *link_info = &btc->wifi_link_info;
u8 h2c_para[3] = {0}, i, wl_center_ch = 0;
if (btc->manual_control)
return;
if (btc->stop_coex_dm || btc->wl_rf_state_off) {
wl_center_ch = 0;
} else if (type != BTC_MEDIA_DISCONNECT ||
(type == BTC_MEDIA_DISCONNECT &&
link_info_ext->num_of_active_port > 0)) {
if (link_info_ext->num_of_active_port == 1) {
if (link_info_ext->is_p2p_connected)
wl_center_ch = link_info->p2p_center_channel;
else
wl_center_ch = link_info->sta_center_channel;
} else { /* port > 2 */
if (link_info->p2p_center_channel > 14 &&
link_info->sta_center_channel > 14)
wl_center_ch = link_info->p2p_center_channel;
else if (link_info->p2p_center_channel <= 14)
wl_center_ch = link_info->p2p_center_channel;
else if (link_info->sta_center_channel <= 14)
wl_center_ch = link_info->sta_center_channel;
}
}
if (wl_center_ch == 0 ||
(btc->board_info.btdm_ant_num == 1 && wl_center_ch <= 14)) {
h2c_para[0] = 0;
h2c_para[1] = 0;
h2c_para[2] = 0;
} else if (wl_center_ch <= 14) {
h2c_para[0] = 0x1;
h2c_para[1] = wl_center_ch;
if (link_info_ext->wifi_bw == BTC_WIFI_BW_HT40)
h2c_para[2] = chip_para->bt_afh_span_bw40;
else
h2c_para[2] = chip_para->bt_afh_span_bw20;
} else if (chip_para->afh_5g_num > 1) { /* for 5G */
for (i = 0; i < chip_para->afh_5g_num; i++) {
if (wl_center_ch == chip_para->afh_5g[i].wl_5g_ch) {
h2c_para[0] = 0x3;
h2c_para[1] = chip_para->afh_5g[i].bt_skip_ch;
h2c_para[2] = chip_para->afh_5g[i].bt_skip_span;
break;
}
}
}
coex_dm->wl_chnl_info[0] = h2c_para[0];
coex_dm->wl_chnl_info[1] = h2c_para[1];
coex_dm->wl_chnl_info[2] = h2c_para[2];
rtw_btc_mailbox_operation(btc, 0x66, 3, h2c_para);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s: para[0:2] = 0x%x 0x%x 0x%x\n",
__func__, h2c_para[0], h2c_para[1], h2c_para[2]);
BTC_TRACE(trace_buf);
}
static void
rtw_btc_set_wl_tx_power(struct btc_coexist *btc,
boolean force_exec, u8 wl_pwr_dec_lvl)
{
const struct btc_chip_para *chip_para = btc->chip_para;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
if (!force_exec && wl_pwr_dec_lvl == coex_dm->cur_wl_pwr_lvl)
return;
coex_dm->cur_wl_pwr_lvl = wl_pwr_dec_lvl;
chip_para->chip_setup(btc, BTC_CSETUP_WL_TX_POWER);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s(): level = %d\n",
__func__, wl_pwr_dec_lvl);
BTC_TRACE(trace_buf);
}
static void
rtw_btc_set_bt_tx_power(struct btc_coexist *btc,
boolean force_exec, u8 bt_pwr_dec_lvl)
{
struct btc_coex_dm *coex_dm = &btc->coex_dm;
u8 h2c_para[1] = {0};
if (!force_exec && bt_pwr_dec_lvl == coex_dm->cur_bt_pwr_lvl)
return;
h2c_para[0] = (0x100 - bt_pwr_dec_lvl) & 0xff;
rtw_btc_mailbox_operation(btc, 0x62, 1, h2c_para);
coex_dm->cur_bt_pwr_lvl = bt_pwr_dec_lvl;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(), bt_tx_power = 0x%x, level = %d\n",
__func__, h2c_para[0], bt_pwr_dec_lvl);
BTC_TRACE(trace_buf);
}
static void
rtw_btc_set_wl_rx_gain(struct btc_coexist *btc, boolean force_exec,
boolean low_gain_en)
{
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
if (!force_exec && low_gain_en == coex_dm->cur_wl_rx_low_gain_en)
return;
coex_dm->cur_wl_rx_low_gain_en = low_gain_en;
if (low_gain_en)
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Hi-L Rx!\n");
else
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Nm-L Rx!\n");
BTC_TRACE(trace_buf);
chip_para->chip_setup(btc, BTC_CSETUP_WL_RX_GAIN);
}
static void
rtw_btc_set_bt_rx_gain(struct btc_coexist *btc, boolean force_exec, u8 lna_lvl)
{
struct btc_coex_dm *coex_dm = &btc->coex_dm;
if (!force_exec && lna_lvl == coex_dm->cur_bt_lna_lvl)
return;
if (lna_lvl < 7) {
btc->btc_set(btc, BTC_SET_BL_BT_LNA_CONSTRAIN_LEVEL, &lna_lvl);
/* use scoreboard[4] to notify BT Rx gain table change */
btc->btc_write_scbd(btc, BTC_SCBD_RXGAIN, TRUE);
} else {
btc->btc_write_scbd(btc, BTC_SCBD_RXGAIN, FALSE);
}
coex_dm->cur_bt_lna_lvl = lna_lvl;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): bt_rx_LNA_level = %d\n",
__func__, lna_lvl);
BTC_TRACE(trace_buf);
}
static void
rtw_btc_set_rf_para(struct btc_coexist *btc, boolean force_exec,
struct btc_rf_para para)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 tmp = 0;
if (coex_sta->coex_freerun) {
if (coex_sta->cnt_wl[BTC_CNT_WL_SCANAP] <= 5)
tmp = 3;
}
rtw_btc_set_wl_tx_power(btc, force_exec, para.wl_pwr_dec_lvl);
rtw_btc_set_bt_tx_power(btc, force_exec, para.bt_pwr_dec_lvl + tmp);
rtw_btc_set_wl_rx_gain(btc, force_exec, para.wl_low_gain_en);
rtw_btc_set_bt_rx_gain(btc, force_exec, para.bt_lna_lvl);
}
static void
rtw_btc_coex_ctrl_owner(struct btc_coexist *btc, boolean wifi_control)
{
u8 val;
val = (wifi_control) ? 1 : 0; /* 0x70[26] */
btc->btc_write_1byte_bitmask(btc, REG_SYS_SDIO_CTRL3, BIT(2), val);
if (!wifi_control)
btc->chip_para->chip_setup(btc, BTC_CSETUP_WLAN_ACT_IPS);
}
static void
rtw_btc_set_gnt_bt(struct btc_coexist *btc, u8 state)
{
btc->btc_write_linderct(btc, REG_LTE_IDR_COEX_CTRL, 0xc000, state);
btc->btc_write_linderct(btc, REG_LTE_IDR_COEX_CTRL, 0x0c00, state);
}
static void
rtw_btc_set_gnt_wl(struct btc_coexist *btc, u8 state)
{
btc->btc_write_linderct(btc, REG_LTE_IDR_COEX_CTRL, 0x3000, state);
btc->btc_write_linderct(btc, REG_LTE_IDR_COEX_CTRL, 0x0300, state);
}
#ifdef PLATFORM_WINDOWS
static void
rtw_btc_mimo_ps(struct btc_coexist *btc, boolean force_exec,
u8 state)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (!force_exec && state == coex_sta->wl_mimo_ps)
return;
coex_sta->wl_mimo_ps = state;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): state = %d\n", __func__, state);
BTC_TRACE(trace_buf);
btc->btc_set(btc, BTC_SET_MIMO_PS_MODE, &state);
}
#endif
static void
rtw_btc_wltoggle_tableA(IN struct btc_coexist *btc,
IN boolean force_exec, IN u32 table_case)
{
const struct btc_chip_para *chip_para = btc->chip_para;
u8 h2c_para[6] = {0};
u32 table_wl = 0x5a5a5a5a;
h2c_para[0] = 0xd; /* op_code, 0xd= wlan slot toggle-A*/
h2c_para[1] = 0x1; /* no definition */
if (btc->board_info.btdm_ant_num == 1) {
if (table_case < chip_para->table_sant_num)
table_wl = chip_para->table_sant[table_case].wl;
} else {
if (table_case < chip_para->table_nsant_num)
table_wl = chip_para->table_nsant[table_case].wl;
}
/* tell WL FW WL slot toggle table-A*/
h2c_para[2] = (u8)(table_wl & 0xff);
h2c_para[3] = (u8)((table_wl & 0xff00) >> 8);
h2c_para[4] = (u8)((table_wl & 0xff0000) >> 16);
h2c_para[5] = (u8)((table_wl & 0xff000000) >> 24);
btc->btc_fill_h2c(btc, 0x69, 6, h2c_para);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n",
__func__, h2c_para[0], h2c_para[1], h2c_para[2],
h2c_para[3], h2c_para[4], h2c_para[5]);
BTC_TRACE(trace_buf);
}
static void
rtw_btc_wltoggle_tableB(IN struct btc_coexist *btc, IN boolean force_exec,
IN u8 interval, IN u32 table)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 cur_h2c_para[6] = {0};
u8 i, match_cnt = 0;
cur_h2c_para[0] = 0x7; /* op_code, 0x7= wlan slot toggle-B*/
cur_h2c_para[1] = interval;
cur_h2c_para[2] = (u8)(table & 0xff);
cur_h2c_para[3] = (u8)((table & 0xff00) >> 8);
cur_h2c_para[4] = (u8)((table & 0xff0000) >> 16);
cur_h2c_para[5] = (u8)((table & 0xff000000) >> 24);
if (ARRAY_SIZE(coex_sta->wl_toggle_para) != 6)
return;
coex_sta->wl_toggle_interval = interval;
for (i = 0; i <= 5; i++)
coex_sta->wl_toggle_para[i] = cur_h2c_para[i];
btc->btc_fill_h2c(btc, 0x69, 6, cur_h2c_para);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n",
__func__, cur_h2c_para[0], cur_h2c_para[1], cur_h2c_para[2],
cur_h2c_para[3], cur_h2c_para[4], cur_h2c_para[5]);
BTC_TRACE(trace_buf);
}
static void
rtw_btc_set_table(struct btc_coexist *btc, boolean force_exec, u32 val0x6c0,
u32 val0x6c4)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
/* If last tdma is wl slot toggle, force write table*/
if (!force_exec && coex_sta->coex_run_reason != BTC_RSN_LPS) {
if (val0x6c0 == btc->btc_read_4byte(btc, REG_BT_COEX_TABLE0) &&
val0x6c4 == btc->btc_read_4byte(btc, REG_BT_COEX_TABLE1))
return;
}
btc->btc_write_4byte(btc, REG_BT_COEX_TABLE0, val0x6c0);
btc->btc_write_4byte(btc, REG_BT_COEX_TABLE1, val0x6c4);
btc->btc_write_4byte(btc, REG_BT_COEX_BRK_TABLE, 0xf0ffffff);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): 0x6c0 = %x, 0x6c4 = %x\n",
__func__, val0x6c0, val0x6c4);
BTC_TRACE(trace_buf);
}
static void
rtw_btc_table(struct btc_coexist *btc, boolean force_exec, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
const struct btc_chip_para *chip_para = btc->chip_para;
u8 h2c_para[6] = {0};
u32 table_wl = 0x0;
coex_sta->coex_table_type = type;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], ***** Coex_Table - %d *****\n", type);
BTC_TRACE(trace_buf);
h2c_para[0] = 0xd;
h2c_para[1] = 0x1;
if (btc->board_info.btdm_ant_num == 1) {
if (type < chip_para->table_sant_num)
rtw_btc_set_table(btc, force_exec,
chip_para->table_sant[type].bt,
chip_para->table_sant[type].wl);
} else {
type = type - 100;
if (type < chip_para->table_nsant_num)
rtw_btc_set_table(btc, force_exec,
chip_para->table_nsant[type].bt,
chip_para->table_nsant[type].wl);
}
if (coex_sta->wl_slot_toggle_change)
rtw_btc_wltoggle_tableA(btc, FC_EXCU, type);
}
static void
rtw_btc_ignore_wlan_act(struct btc_coexist *btc, boolean force_exec,
boolean enable)
{
struct btc_coex_dm *coex_dm = &btc->coex_dm;
u8 h2c_para[1] = {0};
if (btc->manual_control || btc->stop_coex_dm)
return;
if (!force_exec && enable == coex_dm->cur_ignore_wlan_act)
return;
if (enable)
h2c_para[0] = 0x1; /* function enable */
rtw_btc_mailbox_operation(btc, 0x63, 1, h2c_para);
coex_dm->cur_ignore_wlan_act = enable;
}
static void
rtw_btc_lps_rpwm(struct btc_coexist *btc, boolean force_exec, u8 lps_val,
u8 rpwm_val)
{
struct btc_coex_dm *coex_dm = &btc->coex_dm;
if (!force_exec) {
if (lps_val == coex_dm->cur_lps &&
rpwm_val == coex_dm->cur_rpwm)
return;
}
btc->btc_set(btc, BTC_SET_U1_LPS_VAL, &lps_val);
btc->btc_set(btc, BTC_SET_U1_RPWM_VAL, &rpwm_val);
coex_dm->cur_lps = lps_val;
coex_dm->cur_rpwm = rpwm_val;
}
static void
rtw_btc_power_save_state(struct btc_coexist *btc, u8 ps_type, u8 lps_val,
u8 rpwm_val)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
boolean low_pwr_dis = FALSE;
u8 lps_mode = 0x0;
u8 h2c_para[5] = {0, 0, 0, 0, 0};
btc->btc_get(btc, BTC_GET_U1_LPS_MODE, &lps_mode);
switch (ps_type) {
case BTC_PS_WIFI_NATIVE:
/* recover to original 32k low power setting */
coex_sta->wl_force_lps_ctrl = FALSE;
btc->btc_set(btc, BTC_SET_ACT_PRE_NORMAL_LPS, NULL);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BTC_PS_WIFI_NATIVE\n", __func__);
break;
case BTC_PS_LPS_ON:
coex_sta->wl_force_lps_ctrl = TRUE;
/*set tdma off if LPS off */
if (!lps_mode)
btc->btc_fill_h2c(btc, 0x60, 5, h2c_para);
rtw_btc_lps_rpwm(btc, NM_EXCU, lps_val, rpwm_val);
/* when coex force to enter LPS, do not enter 32k low power. */
low_pwr_dis = TRUE;
btc->btc_set(btc, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_dis);
/* power save must executed before psTdma. */
btc->btc_set(btc, BTC_SET_ACT_ENTER_LPS, NULL);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BTC_PS_LPS_ON\n", __func__);
break;
case BTC_PS_LPS_OFF:
coex_sta->wl_force_lps_ctrl = TRUE;
/*set tdma off if LPS on */
if (lps_mode)
btc->btc_fill_h2c(btc, 0x60, 5, h2c_para);
if (btc->btc_set(btc, BTC_SET_ACT_LEAVE_LPS, NULL))
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BTC_PS_LPS_OFF\n",
__func__);
else
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BTC_PS_LPS_OFF Fail!!\n",
__func__);
break;
default:
break;
}
BTC_TRACE(trace_buf);
}
static void
rtw_btc_set_tdma(struct btc_coexist *btc, u8 byte1, u8 byte2, u8 byte3,
u8 byte4, u8 byte5)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_wifi_link_info_ext *linfo_ext = &btc->wifi_link_info_ext;
u8 ps_type = BTC_PS_WIFI_NATIVE,
real_byte1 = byte1, real_byte5 = byte5;
if (linfo_ext->is_ap_mode && (byte1 & BIT(4) && !(byte1 & BIT(5)))) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): AP mode\n", __func__);
BTC_TRACE(trace_buf);
real_byte1 &= ~BIT(4);
real_byte1 |= BIT(5);
real_byte5 |= BIT(5);
real_byte5 &= ~BIT(6);
ps_type = BTC_PS_WIFI_NATIVE;
rtw_btc_power_save_state(btc, ps_type, 0x0, 0x0);
} else if (byte1 & BIT(4) && !(byte1 & BIT(5))) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): Force LPS (byte1 = 0x%x)\n",
__func__, byte1);
BTC_TRACE(trace_buf);
if (btc->chip_para->pstdma_type == BTC_PSTDMA_FORCE_LPSOFF)
ps_type = BTC_PS_LPS_OFF;
else
ps_type = BTC_PS_LPS_ON;
rtw_btc_power_save_state(btc, ps_type, 0x50, 0x4);
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): native power save (byte1 = 0x%x)\n",
__func__, byte1);
BTC_TRACE(trace_buf);
ps_type = BTC_PS_WIFI_NATIVE;
rtw_btc_power_save_state(btc, ps_type, 0x0, 0x0);
}
coex_dm->ps_tdma_para[0] = real_byte1;
coex_dm->ps_tdma_para[1] = byte2;
coex_dm->ps_tdma_para[2] = byte3;
coex_dm->ps_tdma_para[3] = byte4;
coex_dm->ps_tdma_para[4] = real_byte5;
btc->btc_fill_h2c(btc, 0x60, 5, coex_dm->ps_tdma_para);
/* Always forec excute rtw_btc_set_table To avoid
* coex table error if wl slot toggle mode on ->off
* ex: 5508031054 next state -> rtw_btc_table + 5108031054
* rtw_btc_table may be changed by 5508031054
*/
if (real_byte1 & BIT(2)) {
coex_sta->wl_slot_toggle = TRUE;
coex_sta->wl_slot_toggle_change = FALSE;
} else {
coex_sta->wl_slot_toggle_change = coex_sta->wl_slot_toggle;
coex_sta->wl_slot_toggle = FALSE;
}
if (ps_type == BTC_PS_WIFI_NATIVE)
btc->btc_set(btc, BTC_SET_ACT_POST_NORMAL_LPS, NULL);
}
static
void rtw_btc_tdma(struct btc_coexist *btc, boolean force_exec, u32 tcase)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
u8 type;
boolean turn_on;
btc->btc_set_atomic(btc, &coex_dm->setting_tdma, TRUE);
/* tcase: bit0~7 --> tdma case index
* bit8 --> for 4-slot (50ms) mode
*/
if (tcase & TDMA_4SLOT)/* 4-slot (50ms) mode */
rtw_btc_set_tdma_timer_base(btc, 3);
else
rtw_btc_set_tdma_timer_base(btc, 0);
type = (u8)(tcase & 0xff);
turn_on = (type == 0 || type == 100) ? FALSE : TRUE;
/* To avoid TDMA H2C fail before Last LPS enter */
if (!force_exec && coex_sta->coex_run_reason != BTC_RSN_LPS) {
if (turn_on == coex_dm->cur_ps_tdma_on &&
type == coex_dm->cur_ps_tdma) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], Skip TDMA because no change TDMA(%s, %d)\n",
(coex_dm->cur_ps_tdma_on ? "on" : "off"),
coex_dm->cur_ps_tdma);
BTC_TRACE(trace_buf);
btc->btc_set_atomic(btc, &coex_dm->setting_tdma, FALSE);
return;
}
}
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], ***** TDMA - %d *****\n", type);
BTC_TRACE(trace_buf);
/* TRUE -> Page scan > ACL */
if (!turn_on ||
(coex_sta->bt_a2dp_exist && coex_sta->bt_inq_page_remain))
btc->btc_write_scbd(btc, BTC_SCBD_TDMA, FALSE);
else
btc->btc_write_scbd(btc, BTC_SCBD_TDMA, TRUE);
if (btc->board_info.btdm_ant_num == 1) {
if (type < chip_para->tdma_sant_num)
rtw_btc_set_tdma(btc,
chip_para->tdma_sant[type].para[0],
chip_para->tdma_sant[type].para[1],
chip_para->tdma_sant[type].para[2],
chip_para->tdma_sant[type].para[3],
chip_para->tdma_sant[type].para[4]);
} else {
type = type - 100;
if (type < chip_para->tdma_nsant_num)
rtw_btc_set_tdma(btc,
chip_para->tdma_nsant[type].para[0],
chip_para->tdma_nsant[type].para[1],
chip_para->tdma_nsant[type].para[2],
chip_para->tdma_nsant[type].para[3],
chip_para->tdma_nsant[type].para[4]);
}
coex_dm->cur_ps_tdma_on = turn_on;
coex_dm->cur_ps_tdma = type;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "change TDMA(%s, %d)\n",
(coex_dm->cur_ps_tdma_on ? "on" : "off"),
coex_dm->cur_ps_tdma);
BTC_TRACE(trace_buf);
btc->btc_set_atomic(btc, &coex_dm->setting_tdma, FALSE);
}
static
void rtw_btc_set_ant_switch(struct btc_coexist *btc, boolean force_exec,
u8 ctrl_type, u8 pos_type)
{
struct btc_coex_dm *coex_dm = &btc->coex_dm;
if (!force_exec) {
if (((ctrl_type << 8) + pos_type) == coex_dm->cur_switch_status)
return;
}
coex_dm->cur_switch_status = (ctrl_type << 8) + pos_type;
btc->chip_para->chip_setup(btc, BTC_CSETUP_ANT_SWITCH);
}
static
void rtw_btc_set_ant_path(struct btc_coexist *btc, boolean force_exec,
u8 phase)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_rfe_type *rfe_type = &btc->rfe_type;
u8 ctrl_type = BTC_SWITCH_CTRL_MAX,
pos_type = BTC_SWITCH_TO_MAX, cnt = 0;
u16 scbd = 0;
boolean is_btk, is_wlk;
if (!force_exec && coex_dm->cur_ant_pos_type == phase)
return;
coex_dm->cur_ant_pos_type = phase;
/* To avoid switch coex_ctrl_owner during BT IQK */
if (rfe_type->wlg_at_btg && btc->chip_para->scbd_support &&
coex_sta->bt_iqk_state != 0xff) {
/* BT RFK */
is_btk = ((btc->btc_read_scbd(btc, &scbd) & BIT(5)) == BIT(5));
/* WL RFK */
is_wlk = ((btc->btc_read_1byte(btc, 0x49c) & BIT(0)) == BIT(0));
while (++cnt < 12 && (is_btk || is_wlk)) {
delay_ms(50);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], Ant Setup Delay by IQK\n, wlk=%d, btk=%d, cnt=%d\n",
is_wlk, is_btk, cnt);
BTC_TRACE(trace_buf);
}
/* wait timeout */
if (cnt >= 12)
coex_sta->bt_iqk_state = 0xff;
}
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], coex_sta->bt_disabled = 0x%x\n",
coex_sta->bt_disabled);
BTC_TRACE(trace_buf);
switch (phase) {
case BTC_ANT_POWERON:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_COEX_POWERON\n", __func__);
BTC_TRACE(trace_buf);
/* set Path control owner to BT at power-on step */
if (coex_sta->bt_disabled)
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
else
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_BT);
/*Caution: Don't indirect access while power on phase */
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_BT;
break;
case BTC_ANT_INIT:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_COEX_INIT\n", __func__);
BTC_TRACE(trace_buf);
if (coex_sta->bt_disabled) {
/* set GNT_BT to SW low */
rtw_btc_set_gnt_bt(btc, BTC_GNT_SW_LOW);
/* set GNT_WL to SW high */
rtw_btc_set_gnt_wl(btc, BTC_GNT_SW_HIGH);
} else {
/* set GNT_BT to SW high */
rtw_btc_set_gnt_bt(btc, BTC_GNT_SW_HIGH);
/* set GNT_WL to SW low */
rtw_btc_set_gnt_wl(btc, BTC_GNT_SW_LOW);
}
/* set Path control owner to WL at initial step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_BT;
break;
case BTC_ANT_WONLY:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_WLANONLY_INIT\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to SW Low */
rtw_btc_set_gnt_bt(btc, BTC_GNT_SW_LOW);
/* Set GNT_WL to SW high */
rtw_btc_set_gnt_wl(btc, BTC_GNT_SW_HIGH);
/* set Path control owner to WL at initial step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_WLG;
break;
case BTC_ANT_WOFF:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_WLAN_OFF\n", __func__);
BTC_TRACE(trace_buf);
/* set Path control owner to BT */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_BT);
ctrl_type = BTC_SWITCH_CTRL_BY_BT;
pos_type = BTC_SWITCH_TO_NOCARE;
break;
case BTC_ANT_2G:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_2G_RUNTIME\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to PTA */
rtw_btc_set_gnt_bt(btc, BTC_GNT_HW_PTA);
/* Set GNT_WL to PTA */
rtw_btc_set_gnt_wl(btc, BTC_GNT_HW_PTA);
/* set Path control owner to WL at runtime step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_PTA;
pos_type = BTC_SWITCH_TO_NOCARE;
break;
case BTC_ANT_5G:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_5G_RUNTIME\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to SW PTA */
rtw_btc_set_gnt_bt(btc, BTC_GNT_HW_PTA);
/* Set GNT_WL to SW Hi */
rtw_btc_set_gnt_wl(btc, BTC_GNT_SW_HIGH);
/* set Path control owner to WL at runtime step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_WLA;
break;
case BTC_ANT_2G_FREERUN:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_2G_FREERUN\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to SW PTA */
rtw_btc_set_gnt_bt(btc, BTC_GNT_HW_PTA);
/* Set GNT_WL to SW Hi */
rtw_btc_set_gnt_wl(btc, BTC_GNT_SW_HIGH);
/* set Path control owner to WL at runtime step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_WLG_BT;
break;
case BTC_ANT_2G_WLBT:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_2G_WLBT\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to HW PTA */
rtw_btc_set_gnt_bt(btc, BTC_GNT_HW_PTA);
/* Set GNT_WL to HW PTA */
rtw_btc_set_gnt_wl(btc, BTC_GNT_HW_PTA);
/* set Path control owner to WL at runtime step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_WLG_BT;
break;
case BTC_ANT_2G_WL:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_2G_WL\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to PTA */
rtw_btc_set_gnt_bt(btc, BTC_GNT_HW_PTA);
/* Set GNT_WL to PTA */
rtw_btc_set_gnt_wl(btc, BTC_GNT_HW_PTA);
/* set Path control owner to WL at runtime step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_WLG;
break;
case BTC_ANT_2G_BT:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_2G_WL\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to PTA */
rtw_btc_set_gnt_bt(btc, BTC_GNT_HW_PTA);
/* Set GNT_WL to PTA */
rtw_btc_set_gnt_wl(btc, BTC_GNT_HW_PTA);
/* set Path control owner to WL at runtime step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_BT;
break;
case BTC_ANT_BTMP:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_BTMP\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to SW Hi */
rtw_btc_set_gnt_bt(btc, BTC_GNT_SW_HIGH);
/* Set GNT_WL to SW Lo */
rtw_btc_set_gnt_wl(btc, BTC_GNT_SW_LOW);
/* set Path control owner to WL */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
btc->stop_coex_dm = TRUE;
ctrl_type = BTC_SWITCH_CTRL_BY_BBSW;
pos_type = BTC_SWITCH_TO_BT;
break;
case BTC_ANT_MCC:
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s() - PHASE_MCC\n", __func__);
BTC_TRACE(trace_buf);
/* set GNT_BT to PTA */
rtw_btc_set_gnt_bt(btc, BTC_GNT_HW_PTA);
/* Set GNT_WL to PTA */
rtw_btc_set_gnt_wl(btc, BTC_GNT_HW_PTA);
/* set Path control owner to WL at runtime step */
rtw_btc_coex_ctrl_owner(btc, BTC_OWNER_WL);
ctrl_type = BTC_SWITCH_CTRL_BY_FW;
pos_type = BTC_SWITCH_TO_NOCARE;
break;
}
if (ctrl_type < BTC_SWITCH_CTRL_MAX && pos_type < BTC_SWITCH_TO_MAX &&
rfe_type->ant_switch_exist)
rtw_btc_set_ant_switch(btc, force_exec, ctrl_type, pos_type);
}
static u8 rtw_btc_algorithm(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 algorithm = BTC_COEX_NOPROFILE;
u8 profile_map = 0;
if (coex_sta->bt_hfp_exist)
profile_map = profile_map | BTC_BTPROFILE_HFP;
if (coex_sta->bt_hid_exist)
profile_map = profile_map | BTC_BTPROFILE_HID;
if (coex_sta->bt_a2dp_exist)
profile_map = profile_map | BTC_BTPROFILE_A2DP;
if (coex_sta->bt_pan_exist)
profile_map = profile_map | BTC_BTPROFILE_PAN;
switch (profile_map) {
case BTC_BTPROFILE_NONE:
algorithm = BTC_COEX_NOPROFILE;
break;
case BTC_BTPROFILE_HFP:
algorithm = BTC_COEX_HFP;
break;
case BTC_BTPROFILE_HID:
algorithm = BTC_COEX_HID;
break;
case (BTC_BTPROFILE_HID | BTC_BTPROFILE_HFP):
algorithm = BTC_COEX_HID;
break;
case BTC_BTPROFILE_A2DP:
/* OPP may disappear during CPT_for_WiFi test */
if (coex_sta->bt_multi_link && coex_sta->bt_hid_pair_num > 0)
algorithm = BTC_COEX_A2DP_HID;
else if (coex_sta->bt_multi_link)
algorithm = BTC_COEX_A2DP_PAN;
else
algorithm = BTC_COEX_A2DP;
break;
case (BTC_BTPROFILE_A2DP | BTC_BTPROFILE_HFP):
algorithm = BTC_COEX_A2DP_HID;
break;
case (BTC_BTPROFILE_A2DP | BTC_BTPROFILE_HID):
algorithm = BTC_COEX_A2DP_HID;
break;
case (BTC_BTPROFILE_A2DP | BTC_BTPROFILE_HID | BTC_BTPROFILE_HFP):
algorithm = BTC_COEX_A2DP_HID;
break;
case BTC_BTPROFILE_PAN:
algorithm = BTC_COEX_PAN;
break;
case (BTC_BTPROFILE_PAN | BTC_BTPROFILE_HFP):
algorithm = BTC_COEX_PAN_HID;
break;
case (BTC_BTPROFILE_PAN | BTC_BTPROFILE_HID):
algorithm = BTC_COEX_PAN_HID;
break;
case (BTC_BTPROFILE_PAN | BTC_BTPROFILE_HID | BTC_BTPROFILE_HFP):
algorithm = BTC_COEX_PAN_HID;
break;
case (BTC_BTPROFILE_PAN | BTC_BTPROFILE_A2DP):
algorithm = BTC_COEX_A2DP_PAN;
break;
case (BTC_BTPROFILE_PAN | BTC_BTPROFILE_A2DP | BTC_BTPROFILE_HFP):
algorithm = BTC_COEX_A2DP_PAN_HID;
break;
case (BTC_BTPROFILE_PAN | BTC_BTPROFILE_A2DP | BTC_BTPROFILE_HID):
algorithm = BTC_COEX_A2DP_PAN_HID;
break;
case BTC_BTPROFILE_MAX:
algorithm = BTC_COEX_A2DP_PAN_HID;
break;
}
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], BT Profile = %s => Algorithm = %s\n",
bt_profile_string[profile_map],
coex_algo_string[algorithm]);
BTC_TRACE(trace_buf);
return algorithm;
}
static void rtw_btc_action_coex_all_off(struct btc_coexist *btc)
{
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
/* To avoid rtw_btc_set_ant_path here */
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 2;
tdma_case = 0;
} else { /* Non-Shared-Ant */
table_case = 100;
tdma_case = 100;
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_freerun(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *cpara = btc->chip_para;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
u8 level = 0, i;
boolean bt_afh_loss = TRUE;
if (btc->board_info.btdm_ant_num != 2)
return;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
coex_sta->coex_freerun = TRUE;
for (i = 0; i <= 8; i++) {
if (coex_sta->bt_afh_map[i] != 0xff) {
bt_afh_loss = FALSE;
break;
}
}
if (bt_afh_loss)
rtw_btc_update_wl_ch_info(btc, BTC_MEDIA_CONNECT);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G_FREERUN);
btc->btc_write_scbd(btc, BTC_SCBD_FIX2M, FALSE);
/* decrease more BT Tx power for clear case */
if (BTC_RSSI_HIGH(coex_dm->wl_rssi_state[0]))
level = 2;
else if (BTC_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
level = 3;
else if (BTC_RSSI_HIGH(coex_dm->wl_rssi_state[2]))
level = 4;
else
level = 5;
if (level > cpara->wl_rf_para_tx_num - 1)
level = cpara->wl_rf_para_tx_num - 1;
if (coex_sta->wl_coex_mode != BTC_WLINK_2G1PORT)
rtw_btc_set_rf_para(btc, NM_EXCU, cpara->wl_rf_para_rx[0]);
else if (link_info_ext->traffic_dir == BTC_WIFI_TRAFFIC_TX)
rtw_btc_set_rf_para(btc, NM_EXCU, cpara->wl_rf_para_tx[level]);
else
rtw_btc_set_rf_para(btc, NM_EXCU, cpara->wl_rf_para_rx[level]);
rtw_btc_table(btc, NM_EXCU, 100);
rtw_btc_tdma(btc, NM_EXCU, 100);
}
static void rtw_btc_action_rf4ce(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
const struct btc_chip_para *chip_para = btc->chip_para;
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_rf_para(btc, NM_EXCU, chip_para->wl_rf_para_rx[0]);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
switch (coex_sta->ext_chip_mode) {
case 0:
table_case = 112;
tdma_case = 115;
if (coex_sta->bt_slave)
rtw_btc_set_extend_btautoslot(btc, 0x3c);
else
rtw_btc_set_extend_btautoslot(btc, 0x32);
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
break;
case 1:
table_case = 112;
tdma_case = 121;
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
break;
}
}
static void rtw_btc_action_ext_chip(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (btc->board_info.ext_chip_id == BTC_EXT_CHIP_RF4CE)
rtw_btc_action_rf4ce(btc);
}
u8 rtw_btc_action_rf4ce_new_tdma(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
const struct btc_chip_para *chip_para = btc->chip_para;
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
switch (type) {
case 0: /*BT idle*/
if (coex_sta->ext_chip_mode == BTC_EXTMODE_VOICE)
tdma_case = 121;
else
tdma_case = 117;
break;
case 1: /*BT relink*/
if (coex_sta->ext_chip_mode == BTC_EXTMODE_VOICE)
tdma_case = 121;
else
tdma_case = 117;
break;
case 2: /*WIFI linkscan*/
if (coex_sta->ext_chip_mode == BTC_EXTMODE_VOICE) {
tdma_case = 125;
} else{
if (coex_sta->bt_slave)
rtw_btc_set_extend_btautoslot(btc, 0x3c);
else
rtw_btc_set_extend_btautoslot(btc, 0x32);
tdma_case = 124;
}
break;
case 3: /*WIFI only*/
if (coex_sta->ext_chip_mode == BTC_EXTMODE_VOICE) {
tdma_case = 121;
} else{
if (coex_sta->bt_slave)
rtw_btc_set_extend_btautoslot(btc, 0x3c);
else
rtw_btc_set_extend_btautoslot(btc, 0x32);
tdma_case = 115;
}
break;
default:
tdma_case = 0;
break;
}
return tdma_case;
}
u8 rtw_btc_ext_chip_new_tdma(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 tdma_case = 0;
if (btc->board_info.ext_chip_id == BTC_EXT_CHIP_RF4CE)
tdma_case = rtw_btc_action_rf4ce_new_tdma(btc, type);
return tdma_case;
}
static void rtw_btc_action_bt_whql_test(struct btc_coexist *btc)
{
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 2;
tdma_case = 0;
} else { /* Non-Shared-Ant */
table_case = 100;
tdma_case = 100;
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_bt_relink(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
u32 slot_type = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (coex_sta->wl_gl_busy) {
table_case = 26;
if (coex_sta->bt_hid_exist &&
coex_sta->bt_profile_num == 1) {
slot_type = TDMA_4SLOT;
tdma_case = 20;
} else {
tdma_case = 20;
}
} else {
table_case = 1;
tdma_case = 0;
}
} else { /* Non-Shared-Ant */
if (coex_sta->wl_gl_busy)
table_case = 115;
else
table_case = 100;
tdma_case = 100;
if (coex_sta->wl_gl_busy &&
btc->board_info.ext_chip_id != BTC_EXT_CHIP_NONE)
tdma_case = rtw_btc_ext_chip_new_tdma(btc, 1);
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case | slot_type);
}
static void rtw_btc_action_bt_idle(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_rfe_type *rfe_type = &btc->rfe_type;
struct btc_wifi_link_info *link_info = &btc->wifi_link_info;
u8 table_case = 0xff, tdma_case = 0xff;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (rfe_type->ant_switch_with_bt &&
coex_dm->bt_status == BTC_BTSTATUS_NCON_IDLE) {
if (btc->board_info.btdm_ant_num == 1 &&
BTC_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
coex_sta->wl_gl_busy) {
table_case = 0;
tdma_case = 0;
} else if (btc->board_info.btdm_ant_num == 2) {
table_case = 100;
tdma_case = 100;
}
if (table_case != 0xff && tdma_case != 0xff) {
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G_FREERUN);
goto exit;
}
}
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
#ifndef PLATFORM_WINDOWS
if (coex_sta->wl_noisy_level > 0) {
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 1;
tdma_case = 0;
} else { /* Non-Shared-Ant */
table_case = 123;
tdma_case = 0;
}
goto exit;
}
#endif
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (!coex_sta->wl_gl_busy) {
table_case = 10;
tdma_case = 3;
} else if (coex_sta->bt_mesh) {
table_case = 26;
tdma_case = 7;
} else if (coex_dm->bt_status == BTC_BTSTATUS_NCON_IDLE) {
table_case = 11;
if (coex_sta->bt_ctr_ok &&
(coex_sta->lo_pri_rx + coex_sta->lo_pri_tx > 250))
tdma_case = 17;
else
tdma_case = 7;
} else {
table_case = 12;
tdma_case = 7;
}
} else { /* Non-Shared-Ant */
if (!coex_sta->wl_gl_busy) {
table_case = 112;
tdma_case = 104;
} else if ((coex_sta->bt_ble_scan_type & 0x2) &&
coex_dm->bt_status == BTC_BTSTATUS_NCON_IDLE) {
table_case = 114;
tdma_case = 103;
} else {
table_case = 112;
tdma_case = 103;
}
if (coex_sta->wl_gl_busy &&
btc->board_info.ext_chip_id != BTC_EXT_CHIP_NONE)
tdma_case = rtw_btc_ext_chip_new_tdma(btc, 0);
}
exit:
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_bt_inquiry(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
boolean wl_hi_pri = FALSE;
u8 table_case, tdma_case;
u32 slot_type = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (coex_sta->wl_linkscan_proc || coex_sta->wl_hi_pri_task1 ||
coex_sta->wl_hi_pri_task2)
wl_hi_pri = TRUE;
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (wl_hi_pri) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt inq/page + wifi hi-pri task\n");
table_case = 15;
if (coex_sta->bt_profile_num > 0)
tdma_case = 10;
else if (coex_sta->wl_hi_pri_task1)
tdma_case = 6;
else if (!coex_sta->bt_page)
tdma_case = 8;
else
tdma_case = 9;
} else if (coex_sta->wl_gl_busy) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt inq/page + wifi busy\n");
#if 0
table_case = 15;
tdma_case = 20;
#else
if (coex_sta->bt_profile_num == 0) {
table_case = 12;
tdma_case = 18;
} else if (coex_sta->bt_profile_num == 1 &&
!coex_sta->bt_a2dp_exist) {
slot_type = TDMA_4SLOT;
table_case = 12;
tdma_case = 20;
} else {
slot_type = TDMA_4SLOT;
table_case = 12;
tdma_case = 26;
}
#endif
} else if (link_info_ext->is_connected) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt inq/page + wifi connected\n");
table_case = 9;
tdma_case = 27;
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt inq/page + wifi not-connected\n");
table_case = 1;
tdma_case = 0;
}
} else { /* Non_Shared-Ant */
if (wl_hi_pri) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt inq/page + wifi hi-pri task\n");
table_case = 114;
if (coex_sta->bt_profile_num > 0)
tdma_case = 110;
else if (coex_sta->wl_hi_pri_task1)
tdma_case = 106;
else if (!coex_sta->bt_page)
tdma_case = 108;
else
tdma_case = 109;
} else if (coex_sta->wl_gl_busy) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt inq/page + wifi busy\n");
table_case = 114;
tdma_case = 121;
} else if (link_info_ext->is_connected) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt inq/page + wifi connected\n");
table_case = 101;
tdma_case = 100;
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt inq/page + wifi not-connected\n");
table_case = 101;
tdma_case = 100;
}
}
BTC_TRACE(trace_buf);
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case | slot_type);
}
static void rtw_btc_action_bt_hfp(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
#ifdef PLATFORM_WINDOWS
if (coex_sta->wl_cck_lock_ever) {
coex_sta->wl_coex_mode = BTC_WLINK_2GFREE;
table_case = 33;
tdma_case = 0;
} else
#endif
if (coex_sta->bt_multi_link) {
table_case = 10;
tdma_case = 17;
} else {
table_case = 10;
tdma_case = 5;
}
} else { /* Non-Shared-Ant */
if (coex_sta->bt_multi_link) {
table_case = 112;
tdma_case = 117;
} else {
table_case = 105;
tdma_case = 100;
}
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_bt_hid(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
boolean is_toggle_table = FALSE, is_bt_ctr_hi = FALSE;
u32 slot_type = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (coex_sta->bt_ctr_ok &&
(coex_sta->lo_pri_rx + coex_sta->lo_pri_tx > 360))
is_bt_ctr_hi = TRUE;
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
#ifdef PLATFORM_WINDOWS
if (coex_sta->wl_cck_lock_ever) {
coex_sta->wl_coex_mode = BTC_WLINK_2GFREE;
table_case = 33;
tdma_case = 0;
} else
#endif
if (coex_sta->bt_ble_exist) { /* RCU */
table_case = 26;
tdma_case = 2;
} else { /* Legacy HID */
if (coex_sta->bt_profile_num == 1 &&
(coex_sta->bt_multi_link ||
is_bt_ctr_hi ||
coex_sta->bt_slave ||
coex_sta->bt_multi_link_remain)) {
slot_type = TDMA_4SLOT;
if (coex_sta->wl_gl_busy &&
(coex_sta->wl_rx_rate <= 3 ||
coex_sta->wl_rts_rx_rate <= 3))
table_case = 13;
else
table_case = 12;
tdma_case = 26;
} else if (coex_sta->bt_a2dp_active) {
table_case = 9;
tdma_case = 18;
} else if (coex_sta->bt_418_hid_exist &&
coex_sta->wl_gl_busy) {
slot_type = TDMA_4SLOT;
table_case = 32;
tdma_case = 27;
} else if (coex_sta->bt_ble_hid_exist &&
coex_sta->wl_gl_busy) {
table_case = 32;
tdma_case = 9;
} else {
table_case = 9;
tdma_case = 9;
}
}
} else { /* Non-Shared-Ant */
if (coex_sta->bt_ble_exist) { /* BLE */
table_case = 110;
tdma_case = 105;
} else if (coex_sta->bt_a2dp_active) {
table_case = 113;
tdma_case = 118;
} else {
table_case = 113;
tdma_case = 104;
}
}
rtw_btc_table(btc, NM_EXCU, table_case);
if (is_toggle_table) {
rtw_btc_wltoggle_tableA(btc, FC_EXCU, table_case);
rtw_btc_wltoggle_tableB(btc, NM_EXCU, 1, 0x5a5a5aaa);
}
rtw_btc_tdma(btc, NM_EXCU, tdma_case | slot_type);
}
static void rtw_btc_action_bt_a2dp(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
u8 table_case, tdma_case;
u32 slot_type = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
slot_type = TDMA_4SLOT;
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (coex_sta->wl_gl_busy && coex_sta->wl_noisy_level == 0)
table_case = 12;
else
table_case = 9;
if (coex_sta->wl_connecting || !coex_sta->wl_gl_busy)
tdma_case = 14;
else
tdma_case = 13;
} else { /* Non-Shared-Ant */
table_case = 121;
tdma_case = 113;
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case | slot_type);
}
static void rtw_btc_action_bt_a2dpsink(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_wifi_link_info_ext *linfo_ext = &btc->wifi_link_info_ext;
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (linfo_ext->is_ap_mode) {
table_case = 2;
tdma_case = 0;
} else if (coex_sta->wl_gl_busy) {
table_case = 28;
tdma_case = 20;
} else {
table_case = 28;
tdma_case = 26;
}
} else { /* Non-Shared-Ant */
if (linfo_ext->is_ap_mode) {
table_case = 100;
tdma_case = 100;
} else {
table_case = 119;
tdma_case = 120;
}
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_bt_pan(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (coex_sta->wl_gl_busy && coex_sta->wl_noisy_level == 0)
table_case = 14;
else
table_case = 10;
if (coex_sta->wl_gl_busy)
tdma_case = 17;
else
tdma_case = 20;
} else { /* Non-Shared-Ant */
table_case = 112;
if (coex_sta->wl_gl_busy)
tdma_case = 117;
else
tdma_case = 119;
}
if (coex_sta->bt_slave && coex_sta->wl_gl_busy)
rtw_btc_set_bt_golden_rx_range(btc, NM_EXCU, 3, 20);
else
rtw_btc_set_bt_golden_rx_range(btc, NM_EXCU, 3, 0);
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_bt_a2dp_hid(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
u8 table_case, tdma_case;
boolean is_toggle_table = FALSE;
u32 slot_type = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (coex_sta->wl_iot_peer != BTC_IOT_PEER_CISCO)
slot_type = TDMA_4SLOT;
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (coex_sta->bt_ble_exist)
table_case = 26; /* for RCU */
else
table_case = 9;
if (coex_sta->wl_connecting || !coex_sta->wl_gl_busy) {
tdma_case = 14;
} else if (coex_sta->bt_418_hid_exist ||
coex_sta->bt_ble_hid_exist) {
is_toggle_table = TRUE;
tdma_case = 23;
} else {
tdma_case = 13;
}
} else { /* Non-Shared-Ant */
if (coex_sta->bt_ble_exist)
table_case = 110;
else
table_case = 121;
tdma_case = 113;
}
rtw_btc_table(btc, NM_EXCU, table_case);
if (is_toggle_table) {
rtw_btc_wltoggle_tableA(btc, FC_EXCU, table_case);
rtw_btc_wltoggle_tableB(btc, NM_EXCU, 1, 0x5a5a5aaa);
}
rtw_btc_tdma(btc, NM_EXCU, tdma_case | slot_type);
}
static void rtw_btc_action_bt_a2dp_pan(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
u8 table_case, tdma_case;
boolean wl_cpt_test = FALSE, bt_cpt_test = FALSE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
if (btc->board_info.customer_id == RT_CID_LENOVO_CHINA &&
coex_sta->cnt_wl[BTC_CNT_WL_SCANAP] <= 10 &&
coex_sta->wl_iot_peer == BTC_IOT_PEER_ATHEROS) {
if (BTC_RSSI_LOW(coex_dm->wl_rssi_state[2]))
wl_cpt_test = TRUE;
else
bt_cpt_test = TRUE;
}
if (wl_cpt_test)
rtw_btc_set_rf_para(btc, NM_EXCU, chip_para->wl_rf_para_rx[1]);
else
rtw_btc_set_rf_para(btc, NM_EXCU, chip_para->wl_rf_para_rx[0]);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (wl_cpt_test) {
if (coex_sta->wl_gl_busy) {
table_case = 20;
tdma_case = 17;
} else {
table_case = 10;
tdma_case = 15;
}
} else if (bt_cpt_test) {
table_case = 26;
tdma_case = 26;
} else {
if (coex_sta->wl_gl_busy &&
coex_sta->wl_noisy_level == 0)
table_case = 14;
else
table_case = 10;
if (coex_sta->wl_gl_busy)
tdma_case = 15;
else
tdma_case = 20;
}
} else { /* Non-Shared-Ant */
table_case = 112;
if (coex_sta->wl_gl_busy)
tdma_case = 115;
else
tdma_case = 120;
}
if (coex_sta->bt_slave)
rtw_btc_set_extend_btautoslot(btc, 0x3c);
else
rtw_btc_set_extend_btautoslot(btc, 0x32);
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_bt_pan_hid(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 9;
if (coex_sta->wl_gl_busy)
tdma_case = 18;
else
tdma_case = 19;
} else { /* Non-Shared-Ant */
table_case = 113;
if (coex_sta->wl_gl_busy)
tdma_case = 117;
else
tdma_case = 119;
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_bt_a2dp_pan_hid(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 10;
if (coex_sta->wl_gl_busy)
tdma_case = 15;
else
tdma_case = 20;
} else { /* Non-Shared-Ant */
table_case = 113;
if (coex_sta->wl_gl_busy)
tdma_case = 115;
else
tdma_case = 120;
}
if (coex_sta->bt_slave)
rtw_btc_set_extend_btautoslot(btc, 0x3c);
else
rtw_btc_set_extend_btautoslot(btc, 0x32);
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_wl_off(struct btc_coexist *btc)
{
rtw_btc_tdma(btc, FC_EXCU, 0);
rtw_btc_ignore_wlan_act(btc, FC_EXCU, TRUE);
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_WOFF);
btc->stop_coex_dm = TRUE;
btc->wl_rf_state_off = TRUE;
/* must place in the last step */
rtw_btc_update_wl_ch_info(btc, BTC_MEDIA_DISCONNECT);
btc->btc_write_scbd(btc, BTC_SCBD_ALL, FALSE);
}
static void rtw_btc_action_wl_under5g(struct btc_coexist *btc)
{
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_5G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
btc->btc_write_scbd(btc, BTC_SCBD_FIX2M, FALSE);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 0;
tdma_case = 0;
} else { /* Non-Shared-Ant */
table_case = 100;
tdma_case = 100;
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_wl_only(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 2;
tdma_case = 0;
} else { /* Non-Shared-Ant */
table_case = 100;
tdma_case = 100;
if (coex_sta->wl_gl_busy &&
btc->board_info.ext_chip_id != BTC_EXT_CHIP_NONE)
tdma_case = rtw_btc_ext_chip_new_tdma(btc, 3);
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_wl_native_lps(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
u8 table_case, tdma_case;
if (link_info_ext->is_all_under_5g)
return;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 28; /*0x6c0 for A2DP, 0x6c4 for non-A2DP*/
tdma_case = 0;
} else { /* Non-Shared-Ant */
table_case = 100;
tdma_case = 100;
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_wl_linkscan(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
u32 slot_type = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (coex_sta->bt_a2dp_exist) {
slot_type = TDMA_4SLOT;
table_case = 9;
tdma_case = 11;
} else {
table_case = 9;
tdma_case = 7;
}
} else { /* Non-Shared-Ant */
if (coex_sta->bt_a2dp_exist) {
slot_type = TDMA_4SLOT;
table_case = 112;
tdma_case = 111;
} else {
table_case = 112;
tdma_case = 107;
}
if (coex_sta->wl_gl_busy &&
btc->board_info.ext_chip_id != BTC_EXT_CHIP_NONE)
tdma_case = rtw_btc_ext_chip_new_tdma(btc, 2);
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case | slot_type);
}
static void rtw_btc_action_wl_not_connected(struct btc_coexist *btc)
{
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
/* CCK Rx, Tx response, Tx beacon = low pri */
if (link_info_ext->num_of_active_port == 0)
rtw_btc_set_wl_pri_mask(btc, BTC_WLPRI_RX_CCK, 0);
coex_sta->wl_cck_lock_ever = FALSE;
coex_sta->wl_cck_lock = FALSE;
coex_sta->cnt_wl[BTC_CNT_WL_2G_TDDTRY] = FALSE;
coex_sta->cnt_wl[BTC_CNT_WL_2G_FDDSTAY] = FALSE;
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
table_case = 1;
tdma_case = 0;
} else { /* Non-Shared-Ant */
table_case = 100;
tdma_case = 100;
}
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_wl_connected(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 algorithm;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
/*Leap-AP protection will reopen when connecting AP*/
rtw_btc_wl_leakap(btc, TRUE);
if ((btc->board_info.btdm_ant_num == 2) &&
(btc->board_info.ext_chip_id != BTC_EXT_CHIP_NONE)) {
rtw_btc_action_ext_chip(btc);
return;
}
algorithm = rtw_btc_algorithm(btc);
switch (algorithm) {
case BTC_COEX_HFP:
rtw_btc_action_bt_hfp(btc);
break;
case BTC_COEX_HID:
if (rtw_btc_freerun_check(btc))
rtw_btc_action_freerun(btc);
else
rtw_btc_action_bt_hid(btc);
break;
case BTC_COEX_A2DP:
if (rtw_btc_freerun_check(btc))
rtw_btc_action_freerun(btc);
else if (coex_sta->bt_a2dp_sink)
rtw_btc_action_bt_a2dpsink(btc);
else
rtw_btc_action_bt_a2dp(btc);
break;
case BTC_COEX_PAN:
rtw_btc_action_bt_pan(btc);
break;
case BTC_COEX_A2DP_HID:
if (rtw_btc_freerun_check(btc))
rtw_btc_action_freerun(btc);
else
rtw_btc_action_bt_a2dp_hid(btc);
break;
case BTC_COEX_A2DP_PAN:
rtw_btc_action_bt_a2dp_pan(btc);
break;
case BTC_COEX_PAN_HID:
rtw_btc_action_bt_pan_hid(btc);
break;
case BTC_COEX_A2DP_PAN_HID:
rtw_btc_action_bt_a2dp_pan_hid(btc);
break;
default:
case BTC_COEX_NOPROFILE:
rtw_btc_action_bt_idle(btc);
break;
}
}
static void rtw_btc_action_wl_mcc25g(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case, tdma_case;
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_MCC);
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
btc->btc_write_scbd(btc, BTC_SCBD_FIX2M, FALSE);
if (btc->board_info.btdm_ant_num == 1) { /* Shared-Ant */
if (coex_sta->bt_setup_link) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT Relink\n", __func__);
table_case = 24;
tdma_case = 0;
} else if (coex_sta->bt_inq_page) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT Inq-Pag\n", __func__);
table_case = 23;
tdma_case = 0;
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT on\n", __func__);
if (coex_sta->wl_gl_busy) {
if (coex_sta->wl_rx_rate <= 3 ||
coex_sta->wl_rts_rx_rate <= 3)
table_case = 31;
else if (coex_sta->bt_418_hid_exist ||
coex_sta->bt_ble_hid_exist)
table_case = 25;
else
table_case = 23;
} else {
table_case = 23;
}
tdma_case = 0;
}
} else { /* Non-Shared-Ant */
if (coex_sta->bt_setup_link) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT Relink\n", __func__);
table_case = 100;
tdma_case = 100;
} else if (coex_sta->bt_inq_page) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT Inq-Pag\n", __func__);
table_case = 118;
tdma_case = 100;
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT on!!\n", __func__);
table_case = 118;
tdma_case = 100;
}
}
BTC_TRACE(trace_buf);
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
static void rtw_btc_action_wl_scc2g(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case = 0xff, tdma_case = 0xff;
boolean is_toggle_table = FALSE;
u32 slot_type = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
if (coex_sta->bt_profile_num == 1) {
if (coex_sta->bt_hid_exist || coex_sta->bt_hfp_exist) {
if (coex_sta->bt_a2dp_active) {
table_case = 9;
tdma_case = 21;
} else if (coex_sta->bt_418_hid_exist) {
table_case = 10;
tdma_case = 24;
is_toggle_table = TRUE;
slot_type = TDMA_4SLOT;
} else {
table_case = 2;
tdma_case = 0;
}
} else if (coex_sta->bt_a2dp_exist) {
table_case = 10;
tdma_case = 22;
slot_type = TDMA_4SLOT;
} else { /* PAN or OPP */
table_case = 10;
tdma_case = 21;
}
} else {
if ((coex_sta->bt_hid_exist || coex_sta->bt_hfp_exist) &&
coex_sta->bt_a2dp_exist) {
table_case = 9;
tdma_case = 22;
slot_type = TDMA_4SLOT;
if (coex_sta->bt_418_hid_exist)
is_toggle_table = TRUE;
} else if (coex_sta->bt_pan_exist && coex_sta->bt_a2dp_exist) {
table_case = 10;
tdma_case = 22;
slot_type = TDMA_4SLOT;
} else { /* hid + pan */
table_case = 9;
tdma_case = 21;
}
}
rtw_btc_table(btc, NM_EXCU, table_case);
if (is_toggle_table) {
rtw_btc_wltoggle_tableA(btc, FC_EXCU, table_case);
rtw_btc_wltoggle_tableB(btc, NM_EXCU, 1, 0x5a5a5aaa);
}
rtw_btc_tdma(btc, NM_EXCU, tdma_case | slot_type);
}
static void rtw_btc_action_wl_p2p2g(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_rfe_type *rfe_type = &btc->rfe_type;
struct btc_wifi_link_info *link_info = &btc->wifi_link_info;
u8 table_case = 0xff, tdma_case = 0xff, ant_phase;
if (rfe_type->ant_switch_with_bt)
ant_phase = BTC_ANT_2G_FREERUN;
else
ant_phase = BTC_ANT_2G;
rtw_btc_set_rf_para(btc, NM_EXCU, btc->chip_para->wl_rf_para_rx[0]);
btc->btc_write_scbd(btc, BTC_SCBD_FIX2M, FALSE);
if (coex_sta->bt_disabled) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT Disable!!\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
table_case = 0;
tdma_case = 0;
} else if (btc->board_info.btdm_ant_num == 2) { /* Non-Shared-Ant */
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): Non_Shared_Ant!!\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_action_freerun(btc);
return;
} else if (coex_sta->bt_setup_link) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT Relink!!\n", __func__);
rtw_btc_set_ant_path(btc, NM_EXCU, ant_phase);
table_case = 1;
tdma_case = 0;
} else if (coex_sta->bt_inq_page) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT Inq-Page!!\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, ant_phase);
table_case = 15;
tdma_case = 2;
} else if (coex_sta->bt_profile_num == 0) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT idle!!\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, NM_EXCU, ant_phase);
if (btc->chip_interface == BTC_INTF_PCI &&
(link_info->link_mode == BTC_LINK_ONLY_GO ||
link_info->link_mode == BTC_LINK_ONLY_GC) &&
coex_sta->wl_gl_busy)
table_case = 3;
else
table_case = 1;
tdma_case = 0;
} else if (coex_sta->wl_linkscan_proc) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL scan!!\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_action_wl_linkscan(btc);
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT busy!!\n", __func__);
BTC_TRACE(trace_buf);
switch (link_info->link_mode) {
case BTC_LINK_2G_SCC_GC_STA:
case BTC_LINK_2G_SCC_GO_STA:
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
rtw_btc_action_wl_scc2g(btc);
break;
case BTC_LINK_ONLY_GO:
case BTC_LINK_ONLY_GC:
rtw_btc_set_ant_path(btc, NM_EXCU, BTC_ANT_2G);
#ifdef PLATFORM_WINDOWS
if (btc->chip_interface == BTC_INTF_PCI &&
coex_sta->bt_a2dp_exist && !coex_sta->bt_multi_link)
table_case = 3;
else
#endif
table_case = 2;
tdma_case = 0;
break;
default:
rtw_btc_set_ant_path(btc, NM_EXCU, ant_phase);
table_case = 2;
tdma_case = 0;
break;
}
}
if (table_case != 0xff && tdma_case != 0xff) {
rtw_btc_table(btc, NM_EXCU, table_case);
rtw_btc_tdma(btc, NM_EXCU, tdma_case);
}
}
static void rtw_btc_run_coex(struct btc_coexist *btc, u8 reason)
{
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
struct btc_wifi_link_info *link_info = &btc->wifi_link_info;
const struct btc_chip_para *chip_para = btc->chip_para;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): reason = %d\n", __func__, reason);
BTC_TRACE(trace_buf);
coex_sta->coex_run_reason = reason;
/* update wifi_link_info_ext variable */
rtw_btc_update_wl_link_info(btc, reason);
rtw_btc_monitor_bt_enable(btc);
if (btc->manual_control) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], return for Manual CTRL!!\n");
BTC_TRACE(trace_buf);
return;
}
if (btc->stop_coex_dm) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], return for Stop Coex DM!!\n");
BTC_TRACE(trace_buf);
return;
}
if (coex_sta->wl_under_ips) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], return for wifi is under IPS!!\n");
BTC_TRACE(trace_buf);
return;
}
if (coex_sta->wl_under_lps && link_info_ext->is_32k) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], return for wifi is under LPS-32K!!\n");
BTC_TRACE(trace_buf);
return;
}
if (coex_sta->coex_freeze && reason == BTC_RSN_BTINFO &&
!coex_sta->bt_setup_link) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], return for coex_freeze!!\n");
BTC_TRACE(trace_buf);
return;
}
coex_sta->cnt_wl[BTC_CNT_WL_COEXRUN]++;
coex_sta->coex_freerun = FALSE;
/* Pure-5G Coex Process */
if (link_info_ext->is_all_under_5g) {
coex_sta->wl_coex_mode = BTC_WLINK_5G;
rtw_btc_action_wl_under5g(btc);
goto exit;
}
if (link_info_ext->is_mcc_25g) {
coex_sta->wl_coex_mode = BTC_WLINK_25GMPORT;
rtw_btc_action_wl_mcc25g(btc);
goto exit;
}
/* if multi-port, P2P-GO, P2P-GC */
if (link_info_ext->num_of_active_port > 1 ||
(link_info->link_mode == BTC_LINK_ONLY_GO &&
!link_info_ext->is_ap_mode) ||
link_info->link_mode == BTC_LINK_ONLY_GC) {
if (link_info->link_mode == BTC_LINK_ONLY_GO)
coex_sta->wl_coex_mode = BTC_WLINK_2GGO;
else if (link_info->link_mode == BTC_LINK_ONLY_GC)
coex_sta->wl_coex_mode = BTC_WLINK_2GGC;
else
coex_sta->wl_coex_mode = BTC_WLINK_2GMPORT;
rtw_btc_action_wl_p2p2g(btc);
goto exit;
}
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], WiFi is single-port 2G!!\n");
BTC_TRACE(trace_buf);
coex_sta->wl_coex_mode = BTC_WLINK_2G1PORT;
/*For airpods 2 + HID glitch issue*/
if (coex_sta->bt_a2dp_vendor_id == 0x4c && coex_sta->bt_multi_link)
btc->btc_write_scbd(btc, BTC_SCBD_FIX2M, TRUE);
else
btc->btc_write_scbd(btc, BTC_SCBD_FIX2M, FALSE);
if (coex_sta->bt_disabled) {
if (!link_info_ext->is_connected)
rtw_btc_action_wl_not_connected(btc);
else
rtw_btc_action_wl_only(btc);
goto exit;
}
if (coex_sta->wl_under_lps && !coex_sta->wl_force_lps_ctrl) {
rtw_btc_action_wl_native_lps(btc);
goto exit;
}
if (coex_sta->bt_whck_test) {
rtw_btc_action_bt_whql_test(btc);
goto exit;
}
if (coex_sta->bt_setup_link) {
rtw_btc_action_bt_relink(btc);
goto exit;
}
if (coex_sta->bt_inq_page) {
rtw_btc_action_bt_inquiry(btc);
goto exit;
}
if ((coex_dm->bt_status == BTC_BTSTATUS_NCON_IDLE ||
coex_dm->bt_status == BTC_BTSTATUS_CON_IDLE) &&
link_info_ext->is_connected) {
rtw_btc_action_bt_idle(btc);
goto exit;
}
if (coex_sta->wl_linkscan_proc && !coex_sta->coex_freerun) {
rtw_btc_action_wl_linkscan(btc);
goto exit;
}
if (link_info_ext->is_connected) {
rtw_btc_action_wl_connected(btc);
goto exit;
} else {
rtw_btc_action_wl_not_connected(btc);
goto exit;
}
exit:
#ifdef PLATFORM_WINDOWS
/* 0:original, 1:1R */
if (coex_sta->wl_coex_mode == BTC_WLINK_2GFREE &&
chip_para->rx_path_num >= 2)
rtw_btc_mimo_ps(btc, FC_EXCU, 1);
else
rtw_btc_mimo_ps(btc, FC_EXCU, 0);
#endif
rtw_btc_gnt_workaround(btc, NM_EXCU, coex_sta->wl_coex_mode);
rtw_btc_limited_wl(btc);
}
static void rtw_btc_init_coex_var(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
u8 i;
/* Reset Coex variable */
btc->btc_set(btc, BTC_SET_RESET_COEX_VAR, NULL);
/* Init Coex variables that are not zero */
for (i = 0; i < ARRAY_SIZE(coex_dm->bt_rssi_state); i++)
coex_dm->bt_rssi_state[i] = BTC_RSSI_STATE_LOW;
for (i = 0; i < ARRAY_SIZE(coex_dm->wl_rssi_state); i++)
coex_dm->wl_rssi_state[i] = BTC_RSSI_STATE_LOW;
for (i = 0; i < ARRAY_SIZE(coex_sta->bt_sut_pwr_lvl); i++)
coex_sta->bt_sut_pwr_lvl[i] = 0xff;
coex_sta->bt_reg_vendor_ac = 0xffff;
coex_sta->bt_reg_vendor_ae = 0xffff;
coex_sta->gnt_workaround_state = BTC_WLINK_MAX;
btc->bt_info.bt_get_fw_ver = 0;
}
static void
rtw_btc_init_hw_config(struct btc_coexist *btc, boolean wifi_only)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 table_case = 1, tdma_case = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
/* init coex_dm, coex_sta variable to sync with chip status */
rtw_btc_init_coex_var(btc);
/* 0xf0[15:12] --> chip kt info */
coex_sta->kt_ver = (btc->btc_read_1byte(btc, 0xf1) & 0xf0) >> 4;
rtw_btc_monitor_bt_enable(btc);
/* TBTT enable */
btc->btc_write_1byte_bitmask(btc, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION,
0x1);
/* Setup RF front end type */
btc->chip_para->chip_setup(btc, BTC_CSETUP_RFE_TYPE);
/* Init coex relared register */
btc->chip_para->chip_setup(btc, BTC_CSETUP_INIT_HW);
/* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */
rtw_btc_set_wl_pri_mask(btc, BTC_WLPRI_TX_RSP, 1);
/* set Tx beacon = Hi-Pri */
rtw_btc_set_wl_pri_mask(btc, BTC_WLPRI_TX_BEACON, 1);
/* set Tx beacon queue = Hi-Pri */
rtw_btc_set_wl_pri_mask(btc, BTC_WLPRI_TX_BEACONQ, 1);
/* Antenna config */
if (btc->wl_rf_state_off) {
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_WOFF);
btc->btc_write_scbd(btc, BTC_SCBD_ALL, FALSE);
btc->stop_coex_dm = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): RF Off\n", __func__);
BTC_TRACE(trace_buf);
} else if (wifi_only) {
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_WONLY);
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE | BTC_SCBD_ON, TRUE);
btc->stop_coex_dm = TRUE;
} else {
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_INIT);
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE | BTC_SCBD_ON, TRUE);
btc->stop_coex_dm = FALSE;
coex_sta->coex_freeze = TRUE;
}
/* PTA parameter */
rtw_btc_table(btc, FC_EXCU, table_case);
rtw_btc_tdma(btc, FC_EXCU, tdma_case);
rtw_btc_query_bt_info(btc);
}
void rtw_btc_ex_power_on_setting(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_board_info *board_info = &btc->board_info;
u8 table_case = 1;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
btc->stop_coex_dm = TRUE;
btc->wl_rf_state_off = FALSE;
/* enable BB, REG_SYS_FUNC_EN to write reg correctly. */
btc->btc_write_1byte_bitmask(btc, REG_SYS_FUNC_EN,
BIT_FEN_BB_GLB_RST | BIT_FEN_BB_RSTB, 0x3);
rtw_btc_monitor_bt_enable(btc);
/* Setup RF front end type */
btc->chip_para->chip_setup(btc, BTC_CSETUP_RFE_TYPE);
/* Set Antenna Path to BT side */
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_POWERON);
rtw_btc_table(btc, FC_EXCU, table_case);
/* SD1 Chunchu red x issue */
btc->btc_write_1byte(btc, 0xff1a, 0x0);
rtw_btc_gnt_debug(btc, TRUE);
board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT;
}
void rtw_btc_ex_pre_load_firmware(struct btc_coexist *btc) {}
void rtw_btc_ex_init_hw_config(struct btc_coexist *btc, boolean wifi_only)
{
rtw_btc_init_hw_config(btc, wifi_only);
}
void rtw_btc_ex_init_coex_dm(struct btc_coexist *btc)
{
}
void rtw_btc_ex_display_simple_coex_info(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
struct btc_rfe_type *rfe_type = &btc->rfe_type;
struct btc_board_info *board_info = &btc->board_info;
u8 *cli_buf = btc->cli_buf;
u32 bt_patch_ver = 0, bt_coex_ver = 0, val = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n _____[BT Coexist info]____");
CL_PRINTF(cli_buf);
if (btc->manual_control) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n __[Under Manual Control]_");
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n _________________________");
CL_PRINTF(cli_buf);
}
if (btc->stop_coex_dm) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ____[Coex is STOPPED]____");
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n _________________________");
CL_PRINTF(cli_buf);
}
if (!coex_sta->bt_disabled &&
(coex_sta->bt_supported_version == 0 ||
coex_sta->bt_supported_version == 0xffff) &&
coex_sta->cnt_wl[BTC_CNT_WL_COEXINFO2] % 3 == 0) {
btc->btc_get(btc, BTC_GET_U4_SUPPORTED_FEATURE,
&coex_sta->bt_supported_feature);
btc->btc_get(btc, BTC_GET_U4_SUPPORTED_VERSION,
&coex_sta->bt_supported_version);
val = btc->btc_get_bt_reg(btc, 3, 0xac);
coex_sta->bt_reg_vendor_ac = (u16)(val & 0xffff);
val = btc->btc_get_bt_reg(btc, 3, 0xae);
coex_sta->bt_reg_vendor_ae = (u16)(val & 0xffff);
btc->btc_get(btc, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
btc->bt_info.bt_get_fw_ver = bt_patch_ver;
}
/* BT coex. info. */
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %d/ %d/ %s / %d",
"Ant PG Num/ Mech/ Pos/ RFE", board_info->pg_ant_num,
board_info->btdm_ant_num,
(board_info->btdm_ant_pos ==
BTC_ANTENNA_AT_MAIN_PORT ? "Main" : "Aux"),
rfe_type->rfe_module_type);
CL_PRINTF(cli_buf);
bt_coex_ver = ((coex_sta->bt_supported_version & 0xff00) >> 8);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %d_%02x/ %d_%02x/ 0x%02x/ 0x%02x (%s)",
"Ver Coex/ Para/ BT_Dez/ BT_Rpt",
coex_ver_date, coex_ver, chip_para->para_ver_date,
chip_para->para_ver, chip_para->bt_desired_ver, bt_coex_ver,
(bt_coex_ver == 0xff ? "Unknown" :
(coex_sta->bt_disabled ? "BT-disable" :
(bt_coex_ver >= chip_para->bt_desired_ver ?
"Match" : "Mis-Match"))));
CL_PRINTF(cli_buf);
/* BT Status */
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT status",
((coex_sta->bt_disabled) ? ("disabled") :
((coex_sta->bt_inq_page) ? ("inquiry/page") :
((coex_dm->bt_status == BTC_BTSTATUS_NCON_IDLE) ?
"non-connected idle" :
((coex_dm->bt_status == BTC_BTSTATUS_CON_IDLE) ?
"connected-idle" : "busy")))));
CL_PRINTF(cli_buf);
/* HW Settings */
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
"0x770(Hi-pri rx/tx)", coex_sta->hi_pri_rx,
coex_sta->hi_pri_tx);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d %s",
"0x774(Lo-pri rx/tx)", coex_sta->lo_pri_rx,
coex_sta->lo_pri_tx, (coex_sta->bt_slave ?
"(Slave!!)" : ""));
CL_PRINTF(cli_buf);
coex_sta->cnt_wl[BTC_CNT_WL_COEXINFO2]++;
}
void rtw_btc_ex_display_coex_info(struct btc_coexist *btc)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
const struct btc_chip_para *chip_para = btc->chip_para;
struct btc_rfe_type *rfe_type = &btc->rfe_type;
struct btc_board_info *board_info = &btc->board_info;
u8 *cli_buf = btc->cli_buf, i, ps_tdma_case = 0;
u16 scbd;
u32 phy_ver = 0, fw_ver = 0,
bt_coex_ver = 0, val = 0,
fa_ofdm, fa_cck, cca_ofdm, cca_cck,
ok_11b, ok_11g, ok_11n, ok_11vht,
err_11b, err_11g, err_11n, err_11vht;
boolean is_bt_reply = FALSE;
u8 * const p = &coex_sta->bt_afh_map[0];
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ============[BT Coexist info %s]============",
chip_para->chip_name);
CL_PRINTF(cli_buf);
if (btc->manual_control) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ============[Under Manual Control]============");
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ==========================================");
CL_PRINTF(cli_buf);
} else if (btc->stop_coex_dm) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ============[Coex is STOPPED]============");
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ==========================================");
CL_PRINTF(cli_buf);
} else if (coex_sta->coex_freeze) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ============[coex_freeze]============");
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n ==========================================");
CL_PRINTF(cli_buf);
}
if (!coex_sta->bt_disabled &&
coex_sta->cnt_wl[BTC_CNT_WL_COEXINFO1] % 3 == 0) {
if (coex_sta->bt_supported_version == 0 ||
coex_sta->bt_supported_version == 0xffff) {
btc->btc_get(btc, BTC_GET_U4_SUPPORTED_VERSION,
&coex_sta->bt_supported_version);
if (coex_sta->bt_supported_version > 0 &&
coex_sta->bt_supported_version < 0xffff)
is_bt_reply = TRUE;
} else {
is_bt_reply = TRUE;
}
if (coex_dm->bt_status != BTC_BTSTATUS_NCON_IDLE) {
btc->btc_get_bt_afh_map_from_bt(btc, 0, p);
val = btc->btc_get_bt_reg(btc, 1, 0xa);
coex_sta->bt_reg_modem_a = (u16)((val & 0x1c0) >> 6);
val = btc->btc_get_bt_reg(btc, 0, 0x2);
coex_sta->bt_reg_rf_2 = (u16)val;
}
}
if (is_bt_reply) {
if (coex_sta->bt_supported_feature == 0) {
btc->btc_get(btc, BTC_GET_U4_SUPPORTED_FEATURE,
&coex_sta->bt_supported_feature);
if (coex_sta->bt_supported_feature & BIT(11))
coex_sta->bt_slave_latency = TRUE;
else
coex_sta->bt_slave_latency = FALSE;
}
if (coex_sta->bt_reg_vendor_ac == 0xffff) {
val = btc->btc_get_bt_reg(btc, 3, 0xac);
coex_sta->bt_reg_vendor_ac = (u16)(val & 0xffff);
}
if (coex_sta->bt_reg_vendor_ae == 0xffff) {
val = btc->btc_get_bt_reg(btc, 3, 0xae);
coex_sta->bt_reg_vendor_ae = (u16)(val & 0xffff);
}
if (btc->bt_info.bt_get_fw_ver == 0)
btc->btc_get(btc, BTC_GET_U4_BT_PATCH_VER,
&btc->bt_info.bt_get_fw_ver);
if (coex_sta->bt_a2dp_exist &&
coex_sta->bt_a2dp_vendor_id == 0 &&
coex_sta->bt_a2dp_device_name == 0) {
btc->btc_get(btc, BTC_GET_U4_BT_DEVICE_INFO, &val);
coex_sta->bt_a2dp_vendor_id = (u8)(val & 0xff);
coex_sta->bt_a2dp_device_name = (val & 0xffffff00) >> 8;
}
if (coex_sta->bt_a2dp_exist &&
coex_sta->bt_a2dp_flush_time == 0) {
btc->btc_get(btc, BTC_GET_U4_BT_A2DP_FLUSH_VAL, &val);
coex_sta->bt_a2dp_flush_time = val;
}
}
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %s/ %s / %d/ %d",
"Ant PG Num/ Mech/ Pos/ RFE/ Dist", board_info->pg_ant_num,
(board_info->btdm_ant_num == 1 ? "Shared" : "Non-Shared"),
(board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT ?
"Main" : "Aux"), rfe_type->rfe_module_type,
board_info->ant_distance);
CL_PRINTF(cli_buf);
btc->btc_get(btc, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
btc->btc_get(btc, BTC_GET_U4_WIFI_PHY_VER, &phy_ver);
bt_coex_ver = ((coex_sta->bt_supported_version & 0xff00) >> 8);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %d_%02x/ %d_%02x/ 0x%02x/ 0x%02x (%s)",
"Ver Coex/ Para/ BT_Dez/ BT_Rpt",
coex_ver_date, coex_ver, chip_para->para_ver_date,
chip_para->para_ver, chip_para->bt_desired_ver, bt_coex_ver,
(bt_coex_ver == 0xff ? "Unknown" :
(coex_sta->bt_disabled ? "BT-disable" :
(bt_coex_ver >= chip_para->bt_desired_ver ?
"Match" : "Mis-Match"))));
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = 0x%x(%s)/ 0x%08x/ v%d/ %c",
"W_FW/ B_FW/ Phy/ Kt", fw_ver,
(fw_ver >= wl_fw_desired_ver ? "Match" : "Mis-Match"),
btc->bt_info.bt_get_fw_ver, phy_ver, coex_sta->kt_ver + 65);
CL_PRINTF(cli_buf);
/* wifi status */
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
"============[Wifi Status]============");
CL_PRINTF(cli_buf);
btc->btc_disp_dbg_msg(btc, BTC_DBG_DISP_WIFI_STATUS);
/*EXT CHIP status*/
if (btc->board_info.ext_chip_id != BTC_EXT_CHIP_NONE) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
"============[EXT CHIP Status]============");
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s",
"EXT CHIP ID/EXT CHIP mode",
((btc->board_info.ext_chip_id ==
BTC_EXT_CHIP_RF4CE) ? "RF4CE" : "unknown"),
((coex_sta->ext_chip_mode ==
BTC_EXTMODE_VOICE) ? "VOICE" : "NORMAL"));
CL_PRINTF(cli_buf);
}
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
"============[BT Status]============");
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %ddBm/ %d/ %d",
"BT status/ rssi/ retryCnt/ popCnt",
((coex_sta->bt_disabled) ? ("disabled") :
((coex_sta->bt_inq_page) ? ("inquiry-page") :
((coex_dm->bt_status == BTC_BTSTATUS_NCON_IDLE) ?
"non-connecte-idle" : ((coex_dm->bt_status ==
BTC_BTSTATUS_CON_IDLE) ? "connected-idle" : "busy")))),
coex_sta->bt_rssi - 100, coex_sta->cnt_bt[BTC_CNT_BT_RETRY],
coex_sta->cnt_bt[BTC_CNT_BT_POPEVENT]);
CL_PRINTF(cli_buf);
if (coex_sta->bt_profile_num != 0) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %s%s%s%s%s%s (multilink = %d)",
"Profiles", ((coex_sta->bt_a2dp_exist) ?
((coex_sta->bt_a2dp_sink) ? "A2DP sink," :
"A2DP,") : ""),
((coex_sta->bt_hfp_exist) ? "HFP," : ""),
((coex_sta->bt_hid_exist) ?
((coex_sta->bt_ble_exist) ? "HID(RCU)" :
((coex_sta->bt_hid_slot >= 2) ? "HID(4/18)," :
(coex_sta->bt_ble_hid_exist ? "HID(BLE)" :
"HID(2/18),"))) : ""), ((coex_sta->bt_pan_exist) ?
((coex_sta->bt_opp_exist) ? "OPP," : "PAN,") :
""), ((coex_sta->bt_ble_voice) ? "Voice," : ""),
((coex_sta->bt_msft_mr_exist) ? "MR" : ""),
coex_sta->bt_multi_link);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %d/ %d/ %d/ %d",
"SUT Power[3:0]",
coex_sta->bt_sut_pwr_lvl[3],
coex_sta->bt_sut_pwr_lvl[2],
coex_sta->bt_sut_pwr_lvl[1],
coex_sta->bt_sut_pwr_lvl[0]);
CL_PRINTF(cli_buf);
} else {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s",
"Profiles",
(coex_sta->bt_msft_mr_exist) ? "MR" : "None");
CL_PRINTF(cli_buf);
}
/* for 8822b, Scoreboard[10]: 0: CQDDR off, 1: CQDDR on
* for 8822c, Scoreboard[10]: 0: CQDDR on, 1:CQDDR fix 2M
*/
if (coex_sta->bt_a2dp_exist) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %s/ %d/ 0x%x/ 0x%x/ %d",
"CQDDR/Bitpool/V_ID/D_name/Flush",
(chip_para->new_scbd10_def ?
((coex_sta->bt_fix_2M) ? "fix_2M" : "CQDDR_On") :
((coex_sta->bt_fix_2M) ? "CQDDR_On" : "CQDDR_Off")),
coex_sta->bt_a2dp_bitpool,
coex_sta->bt_a2dp_vendor_id,
coex_sta->bt_a2dp_device_name,
coex_sta->bt_a2dp_flush_time);
CL_PRINTF(cli_buf);
}
if (coex_sta->bt_hid_exist) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d",
"HID PairNum", coex_sta->bt_hid_pair_num);
CL_PRINTF(cli_buf);
}
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s/ 0x%x",
"Role/RoleSwCnt/IgnWla/Feature",
((coex_sta->bt_slave) ? "Slave" : "Master"),
coex_sta->cnt_bt[BTC_CNT_BT_ROLESWITCH],
((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"),
coex_sta->bt_supported_feature);
CL_PRINTF(cli_buf);
if (coex_sta->bt_ble_scan_en) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
"BLEScan Type/TV/Init/Ble",
coex_sta->bt_ble_scan_type,
(coex_sta->bt_ble_scan_type & 0x1 ?
coex_sta->bt_ble_scan_para[0] : 0x0),
(coex_sta->bt_ble_scan_type & 0x2 ?
coex_sta->bt_ble_scan_para[1] : 0x0),
(coex_sta->bt_ble_scan_type & 0x4 ?
coex_sta->bt_ble_scan_para[2] : 0x0));
CL_PRINTF(cli_buf);
}
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %d/ %d/ %d/ %d/ %d/ %d/ %d %s",
"Init/ReLink/IgnWl/Pag/Inq/iqkO/iqkX",
coex_sta->cnt_bt[BTC_CNT_BT_REINIT],
coex_sta->cnt_bt[BTC_CNT_BT_SETUPLINK],
coex_sta->cnt_bt[BTC_CNT_BT_IGNWLANACT],
coex_sta->cnt_bt[BTC_CNT_BT_PAGE],
coex_sta->cnt_bt[BTC_CNT_BT_INQ],
coex_sta->cnt_bt[BTC_CNT_BT_IQK],
coex_sta->cnt_bt[BTC_CNT_BT_IQKFAIL],
(coex_sta->bt_setup_link ? "(Relink!!)" : ""));
CL_PRINTF(cli_buf);
if (coex_sta->bt_reg_vendor_ae == 0xffff ||
coex_sta->bt_reg_vendor_ac == 0xffff)
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = x/ x/ 0x%04x",
"0xae[4]/0xac[1:0]/ScBd(B->W)",
btc->btc_read_scbd(btc, &scbd));
else
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x/ 0x%04x/ %s",
"ae/ac/m_a[8:6]/rf_2/ScBd(B->W)/path",
coex_sta->bt_reg_vendor_ae,
coex_sta->bt_reg_vendor_ac,
coex_sta->bt_reg_modem_a,
coex_sta->bt_reg_rf_2,
btc->btc_read_scbd(btc, &scbd),
((coex_sta->bt_reg_vendor_ae & BIT(4)) ? "S1" : "S0"
));
CL_PRINTF(cli_buf);
if (coex_dm->bt_status != BTC_BTSTATUS_NCON_IDLE) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x",
"AFH MAP", coex_sta->bt_afh_map[0],
coex_sta->bt_afh_map[1], coex_sta->bt_afh_map[2],
coex_sta->bt_afh_map[3], coex_sta->bt_afh_map[4],
coex_sta->bt_afh_map[5], coex_sta->bt_afh_map[6],
coex_sta->bt_afh_map[7], coex_sta->bt_afh_map[8],
coex_sta->bt_afh_map[9]);
CL_PRINTF(cli_buf);
}
for (i = 0; i < BTC_BTINFO_SRC_BT_IQK; i++) {
if (coex_sta->cnt_bt_info_c2h[i]) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x (%d)",
glbt_info_src[i],
coex_sta->bt_info_c2h[i][0],
coex_sta->bt_info_c2h[i][1],
coex_sta->bt_info_c2h[i][2],
coex_sta->bt_info_c2h[i][3],
coex_sta->bt_info_c2h[i][4],
coex_sta->bt_info_c2h[i][5],
coex_sta->bt_info_c2h[i][6],
coex_sta->cnt_bt_info_c2h[i]);
CL_PRINTF(cli_buf);
}
}
if (btc->manual_control) {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
"============[mechanisms] (under Manual)============");
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %02x %02x %02x %02x %02x",
"TDMA_Now",
coex_dm->fw_tdma_para[0], coex_dm->fw_tdma_para[1],
coex_dm->fw_tdma_para[2], coex_dm->fw_tdma_para[3],
coex_dm->fw_tdma_para[4]);
CL_PRINTF(cli_buf);
} else {
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
"============[Mechanisms]============");
CL_PRINTF(cli_buf);
ps_tdma_case = coex_dm->cur_ps_tdma;
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %02x %02x %02x %02x %02x (case-%d, TDMA-%s, Ext-%d, Tog-%d)",
"TDMA",
coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1],
coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3],
coex_dm->ps_tdma_para[4], ps_tdma_case,
(coex_dm->cur_ps_tdma_on ? "On" : "Off"),
coex_sta->bt_ext_autoslot_thres,
coex_sta->wl_toggle_interval);
CL_PRINTF(cli_buf);
}
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d",
"Coex_Mode/Free_Run/Timer_base",
coex_mode_string[coex_sta->wl_coex_mode],
((coex_sta->coex_freerun) ? "Yes" : "No"),
coex_sta->tdma_timer_base);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %d/ 0x%x/ 0x%x/ 0x%x",
"Table/0x6c0/0x6c4/0x6c8", coex_sta->coex_table_type,
btc->btc_read_4byte(btc, REG_BT_COEX_TABLE0),
btc->btc_read_4byte(btc, REG_BT_COEX_TABLE1),
btc->btc_read_4byte(btc, REG_BT_COEX_BRK_TABLE));
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = 0x%x/ 0x%x/ 0x%04x/ %d/ %s",
"0x778/0x6cc/ScBd(W->B)/RunCnt/Rsn",
btc->btc_read_1byte(btc, REG_BT_STAT_CTRL),
btc->btc_read_4byte(btc, REG_BT_COEX_TABLE_H),
coex_sta->score_board_WB,
coex_sta->cnt_wl[BTC_CNT_WL_COEXRUN],
run_reason_string[coex_sta->coex_run_reason]);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %02x %02x %02x (RF-Ch = %d)", "AFH Map to BT",
coex_dm->wl_chnl_info[0], coex_dm->wl_chnl_info[1],
coex_dm->wl_chnl_info[2], coex_sta->wl_center_ch);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s/ %d",
"AntDiv/BtCtrlLPS/LPRA/g_busy",
((board_info->ant_div_cfg) ? "On" : "Off"),
((coex_sta->wl_force_lps_ctrl) ? "On" : "Off"),
((coex_dm->cur_low_penalty_ra) ? "On" : "Off"),
coex_sta->wl_gl_busy);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d",
"Null All/Retry/Ack/BT_Empty/BT_Late",
coex_sta->wl_fw_dbg_info[1], coex_sta->wl_fw_dbg_info[2],
coex_sta->wl_fw_dbg_info[3], coex_sta->wl_fw_dbg_info[4],
coex_sta->wl_fw_dbg_info[5]);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %s/ %d",
"Cnt TDMA_Togg/LkRx/LKAP_On/fw",
coex_sta->wl_fw_dbg_info[6],
coex_sta->wl_fw_dbg_info[7],
((coex_sta->wl_leak_ap) ? "Yes" : "No"),
coex_sta->cnt_wl[BTC_CNT_WL_FW_NOTIFY]);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %s/ %d",
"WL_TxPw/BT_TxPw/WL_Rx/BT_LNA_Lvl",
coex_dm->cur_wl_pwr_lvl, coex_dm->cur_bt_pwr_lvl,
((coex_dm->cur_wl_rx_low_gain_en) ? "On" : "Off"),
coex_dm->cur_bt_lna_lvl);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %s",
"MIMO_PS On/Recover/BlackAP",
coex_sta->cnt_wl[BTC_CNT_WL_2G_FDDSTAY],
coex_sta->cnt_wl[BTC_CNT_WL_2G_TDDTRY],
((coex_sta->wl_blacklist_ap) ? "Yes": "No"));
CL_PRINTF(cli_buf);
/* Hw setting */
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
"============[Hw setting]============");
CL_PRINTF(cli_buf);
btc->chip_para->chip_setup(btc, BTC_CSETUP_COEXINFO_HW);
fa_ofdm = btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_FA_OFDM);
fa_cck = btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_FA_CCK);
cca_ofdm = btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CCA_OFDM);
cca_cck = btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CCA_CCK);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %d/ %d/ %d/ %d",
"CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", cca_cck, fa_cck, cca_ofdm,
fa_ofdm);
CL_PRINTF(cli_buf);
ok_11b =
btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CRC32_OK_CCK);
ok_11g =
btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CRC32_OK_LEGACY);
ok_11n =
btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CRC32_OK_HT);
ok_11vht =
btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CRC32_OK_VHT);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d",
"CRC_OK CCK/11g/11n/11ac", ok_11b, ok_11g, ok_11n, ok_11vht);
CL_PRINTF(cli_buf);
err_11b =
btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CRC32_ERROR_CCK);
err_11g =
btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CRC32_ERROR_LEGACY);
err_11n =
btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CRC32_ERROR_HT);
err_11vht =
btc->btc_phydm_query_PHY_counter(btc, PHYDM_INFO_CRC32_ERROR_VHT);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d",
"CRC_Err CCK/11g/11n/11ac",
err_11b, err_11g, err_11n, err_11vht);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
"\r\n %-35s = %d/ %d/ %s-%d/ %d (Tx macid: %d)",
"Rate RxD/RxRTS/TxD/TxRetry_ratio",
coex_sta->wl_rx_rate, coex_sta->wl_rts_rx_rate,
(coex_sta->wl_tx_rate & 0x80 ? "SGI" : "LGI"),
coex_sta->wl_tx_rate & 0x7f,
coex_sta->wl_tx_retry_ratio,
coex_sta->wl_tx_macid);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s/ %d",
"HiPr/ Locking/ Locked/ Noisy",
(coex_sta->wl_hi_pri_task1 ? "Yes" : "No"),
(coex_sta->wl_cck_lock ? "Yes" : "No"),
(coex_sta->wl_cck_lock_ever ? "Yes" : "No"),
coex_sta->wl_noisy_level);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
"0x770(Hi-pri rx/tx)", coex_sta->hi_pri_rx,
coex_sta->hi_pri_tx);
CL_PRINTF(cli_buf);
CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d %s",
"0x774(Lo-pri rx/tx)", coex_sta->lo_pri_rx,
coex_sta->lo_pri_tx, (coex_sta->bt_slave ?
"(Slave!!)" : ""));
CL_PRINTF(cli_buf);
btc->btc_disp_dbg_msg(btc, BTC_DBG_DISP_COEX_STATISTICS);
coex_sta->cnt_wl[BTC_CNT_WL_COEXINFO1]++;
if (coex_sta->cnt_wl[BTC_CNT_WL_COEXINFO1] % 5 == 0)
coex_sta->cnt_bt[BTC_CNT_BT_POPEVENT] = 0;
}
void rtw_btc_ex_ips_notify(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (btc->manual_control || btc->stop_coex_dm)
return;
if (type == BTC_IPS_ENTER) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], IPS ENTER notify\n");
BTC_TRACE(trace_buf);
coex_sta->wl_under_ips = TRUE;
/* Write WL "Active" in Score-board for LPS off */
btc->btc_write_scbd(btc, BTC_SCBD_ALL, FALSE);
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_WOFF);
rtw_btc_action_coex_all_off(btc);
} else if (type == BTC_IPS_LEAVE) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], IPS LEAVE notify\n");
BTC_TRACE(trace_buf);
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE | BTC_SCBD_ON, TRUE);
/*leave IPS : run ini hw config (exclude wifi only)*/
rtw_btc_init_hw_config(btc, FALSE);
coex_sta->wl_under_ips = FALSE;
}
}
void rtw_btc_ex_lps_notify(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (btc->manual_control || btc->stop_coex_dm)
return;
if (type == BTC_LPS_ENABLE) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], LPS ENABLE notify\n");
BTC_TRACE(trace_buf);
coex_sta->wl_under_lps = TRUE;
if (coex_sta->wl_force_lps_ctrl) { /* LPS No-32K */
/* Write WL "Active" in Score-board for PS-TDMA */
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE, TRUE);
} else {
/* Write WL "Non-Active" in Score-board for Native-PS */
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE, FALSE);
btc->btc_write_scbd(btc, BTC_SCBD_WLBUSY, FALSE);
rtw_btc_run_coex(btc, BTC_RSN_LPS);
}
} else if (type == BTC_LPS_DISABLE) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], LPS DISABLE notify\n");
BTC_TRACE(trace_buf);
coex_sta->wl_under_lps = FALSE;
/* Write WL "Active" in Score-board for LPS off */
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE, TRUE);
if (!coex_sta->wl_force_lps_ctrl)
rtw_btc_query_bt_info(btc);
rtw_btc_run_coex(btc, BTC_RSN_LPS);
}
}
void rtw_btc_ex_scan_notify(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (btc->manual_control || btc->stop_coex_dm)
return;
coex_sta->coex_freeze = FALSE;
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE | BTC_SCBD_ON, TRUE);
if (type == BTC_SCAN_START_5G) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], SCAN START notify (5G)\n");
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_5G);
rtw_btc_run_coex(btc, BTC_RSN_5GSCANSTART);
} else if (type == BTC_SCAN_START_2G || type == BTC_SCAN_START) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], SCAN START notify (2G)\n");
BTC_TRACE(trace_buf);
coex_sta->wl_hi_pri_task2 = TRUE;
/* Force antenna setup for no scan result issue */
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_2G);
rtw_btc_run_coex(btc, BTC_RSN_2GSCANSTART);
} else {
btc->btc_get(btc, BTC_GET_U1_AP_NUM,
&coex_sta->cnt_wl[BTC_CNT_WL_SCANAP]);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n",
coex_sta->cnt_wl[BTC_CNT_WL_SCANAP]);
BTC_TRACE(trace_buf);
coex_sta->wl_hi_pri_task2 = FALSE;
rtw_btc_run_coex(btc, BTC_RSN_SCANFINISH);
}
}
void rtw_btc_ex_scan_notify_without_bt(struct btc_coexist *btc, u8 type)
{
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
struct btc_rfe_type *rfe_type = &btc->rfe_type;
u8 ctrl_type = BTC_SWITCH_CTRL_BY_BBSW, pos_type = BTC_SWITCH_TO_WLG;
if (!rfe_type->ant_switch_exist)
return;
if (type == BTC_SCAN_START && link_info_ext->is_all_under_5g)
pos_type = BTC_SWITCH_TO_WLA;
rtw_btc_set_ant_switch(btc, FC_EXCU, ctrl_type, pos_type);
}
void rtw_btc_ex_switchband_notify(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (btc->manual_control || btc->stop_coex_dm)
return;
if (type == BTC_SWITCH_TO_5G) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): TO_5G\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_run_coex(btc, BTC_RSN_5GSWITCHBAND);
} else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): TO_24G_NOFORSCAN\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_run_coex(btc, BTC_RSN_2GSWITCHBAND);
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): TO_2G\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_ex_scan_notify(btc, BTC_SCAN_START_2G);
}
}
void rtw_btc_ex_switchband_notify_without_bt(struct btc_coexist *btc, u8 type)
{
struct btc_rfe_type *rfe_type = &btc->rfe_type;
u8 ctrl_type = BTC_SWITCH_CTRL_BY_BBSW, pos_type = BTC_SWITCH_TO_WLG;
if (!rfe_type->ant_switch_exist)
return;
if (type == BTC_SWITCH_TO_5G) {
pos_type = BTC_SWITCH_TO_WLA;
} else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) {
pos_type = BTC_SWITCH_TO_WLG;
} else {
rtw_btc_ex_scan_notify_without_bt(btc, BTC_SCAN_START_2G);
return;
}
rtw_btc_set_ant_switch(btc, FC_EXCU, ctrl_type, pos_type);
}
void rtw_btc_ex_connect_notify(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (btc->manual_control || btc->stop_coex_dm)
return;
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE | BTC_SCBD_ON, TRUE);
if (type == BTC_ASSOCIATE_5G_START) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): 5G start\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_5G);
rtw_btc_run_coex(btc, BTC_RSN_5GCONSTART);
} else if (type == BTC_ASSOCIATE_5G_FINISH) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): 5G finish\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_5G);
rtw_btc_run_coex(btc, BTC_RSN_5GCONFINISH);
} else if (type == BTC_ASSOCIATE_START) {
coex_sta->wl_hi_pri_task1 = TRUE;
coex_sta->cnt_wl[BTC_CNT_WL_ARP] = 0;
coex_sta->wl_connecting = TRUE;
btc->btc_set_timer(btc, BTC_TIMER_WL_CONNPKT, 2);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): 2G start\n", __func__);
BTC_TRACE(trace_buf);
/* Force antenna setup for no scan result issue */
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_2G);
rtw_btc_run_coex(btc, BTC_RSN_2GCONSTART);
/* To keep TDMA case during connect process,
* to avoid changed by Btinfo and run_coex
*/
coex_sta->coex_freeze = TRUE;
btc->btc_set_timer(btc, BTC_TIMER_WL_COEXFREEZE, 5);
} else {
coex_sta->wl_hi_pri_task1 = FALSE;
coex_sta->coex_freeze = FALSE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): 2G finish\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_run_coex(btc, BTC_RSN_2GCONFINISH);
}
}
void rtw_btc_ex_media_status_notify(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
boolean wl_b_mode = FALSE;
u8 i;
if (btc->manual_control || btc->stop_coex_dm)
return;
btc->btc_get(btc, BTC_GET_BL_WIFI_BSSID, btc->wifi_bssid);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BSSID = %02x %02X %02X %02x %02X %02X\n",
__func__, btc->wifi_bssid[0],
btc->wifi_bssid[1], btc->wifi_bssid[2],
btc->wifi_bssid[3], btc->wifi_bssid[4],
btc->wifi_bssid[5]);
BTC_TRACE(trace_buf);
/* check if black-list ap */
for (i = 0; i <= 5; i++) {
if (btc->wifi_bssid[i] != btc->wifi_black_bssid[i])
break;
}
if (i <= 5)
coex_sta->wl_blacklist_ap = FALSE;
else
coex_sta->wl_blacklist_ap = TRUE;
if (type == BTC_MEDIA_CONNECT_5G) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): 5G\n", __func__);
BTC_TRACE(trace_buf);
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE, TRUE);
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_5G);
rtw_btc_run_coex(btc, BTC_RSN_5GMEDIA);
} else if (type == BTC_MEDIA_CONNECT) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): 2G\n", __func__);
BTC_TRACE(trace_buf);
btc->btc_write_scbd(btc, BTC_SCBD_ACTIVE, TRUE);
/* Force antenna setup for no scan result issue */
rtw_btc_set_ant_path(btc, FC_EXCU, BTC_ANT_2G);
btc->btc_get(btc, BTC_GET_BL_WIFI_UNDER_B_MODE, &wl_b_mode);
/* Set CCK Tx/Rx high Pri except 11b mode */
if (wl_b_mode)/* CCK Rx */
rtw_btc_set_wl_pri_mask(btc, BTC_WLPRI_RX_CCK, 0);
else /* CCK Rx */
rtw_btc_set_wl_pri_mask(btc, BTC_WLPRI_RX_CCK, 1);
rtw_btc_run_coex(btc, BTC_RSN_2GMEDIA);
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): disconnect!!\n", __func__);
BTC_TRACE(trace_buf);
coex_sta->cnt_wl[BTC_CNT_WL_ARP] = 0;
rtw_btc_run_coex(btc, BTC_RSN_MEDIADISCON);
}
btc->btc_get(btc, BTC_GET_U1_IOT_PEER, &coex_sta->wl_iot_peer);
rtw_btc_update_wl_ch_info(btc, type);
}
void rtw_btc_ex_specific_packet_notify(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
boolean under_4way = FALSE;
if (btc->manual_control || btc->stop_coex_dm)
return;
if (type & BTC_5G_BAND) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): 5G\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_run_coex(btc, BTC_RSN_5GSPECIALPKT);
return;
}
btc->btc_get(btc, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &under_4way);
if (under_4way) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): under_4way!!\n", __func__);
BTC_TRACE(trace_buf);
coex_sta->wl_hi_pri_task1 = TRUE;
btc->btc_set_timer(btc, BTC_TIMER_WL_SPECPKT, 2);
} else if (type == BTC_PACKET_ARP) {
coex_sta->cnt_wl[BTC_CNT_WL_ARP]++;
if (coex_sta->wl_hi_pri_task1) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): ARP cnt = %d\n",
__func__, coex_sta->cnt_wl[BTC_CNT_WL_ARP]);
BTC_TRACE(trace_buf);
}
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): DHCP or EAPOL Type = %d\n",
__func__, type);
BTC_TRACE(trace_buf);
coex_sta->wl_hi_pri_task1 = TRUE;
btc->btc_set_timer(btc, BTC_TIMER_WL_SPECPKT, 2);
}
if (coex_sta->wl_hi_pri_task1)
rtw_btc_run_coex(btc, BTC_RSN_2GSPECIALPKT);
}
void rtw_btc_ex_bt_info_notify(struct btc_coexist *btc, u8 *tmp_buf, u8 length)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_coex_dm *coex_dm = &btc->coex_dm;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
u8 i, rsp_source = 0, type;
rsp_source = tmp_buf[0] & 0xf;
if (rsp_source >= BTC_BTINFO_SRC_MAX)
return;
coex_sta->cnt_bt_info_c2h[rsp_source]++;
/* bt_iqk_state-> 1: start, 0: ok, 2:fail */
if (rsp_source == BTC_BTINFO_SRC_BT_IQK) {
coex_sta->bt_iqk_state = tmp_buf[1];
if (coex_sta->bt_iqk_state == 0x0)
coex_sta->cnt_bt[BTC_CNT_BT_IQK]++;
else if (coex_sta->bt_iqk_state == 0x2)
coex_sta->cnt_bt[BTC_CNT_BT_IQKFAIL]++;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], BT IQK by bt_info, data0 = 0x%02x\n",
tmp_buf[1]);
BTC_TRACE(trace_buf);
return;
}
if (rsp_source == BTC_BTINFO_SRC_BT_SCBD) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], BT Scoreboard change notify by WL FW c2h, 0xaa = 0x%02x, 0xab = 0x%02x\n",
tmp_buf[1], tmp_buf[2]);
BTC_TRACE(trace_buf);
rtw_btc_monitor_bt_enable(btc);
if (coex_sta->bt_disabled != coex_sta->bt_disabled_pre) {
coex_sta->bt_disabled_pre = coex_sta->bt_disabled;
rtw_btc_run_coex(btc, BTC_RSN_BTINFO);
}
return;
}
if (rsp_source == BTC_BTINFO_SRC_H2C60) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], H2C 0x60 content replied by WL FW: H2C_0x60 = [%02x %02x %02x %02x %02x]\n",
tmp_buf[1], tmp_buf[2], tmp_buf[3], tmp_buf[4],
tmp_buf[5]);
BTC_TRACE(trace_buf);
for (i = 1; i <= 5; i++)
coex_dm->fw_tdma_para[i - 1] = tmp_buf[i];
return;
}
if (rsp_source == BTC_BTINFO_SRC_WL_FW) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], bt_info reply by WL FW\n");
BTC_TRACE(trace_buf);
rtw_btc_update_bt_link_info(btc);
/* rtw_btc_run_coex(btc, BTC_RSN_BTINFO); */
return;
}
if (rsp_source == BTC_BTINFO_SRC_BT_RSP ||
rsp_source == BTC_BTINFO_SRC_BT_ACT) {
if (coex_sta->bt_disabled) {
coex_sta->bt_disabled = FALSE;
coex_sta->bt_reenable = TRUE;
btc->btc_set_timer(btc, BTC_TIMER_BT_REENABLE, 15);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], BT enable detected by bt_info\n");
BTC_TRACE(trace_buf);
}
}
if (length != 7) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], Bt_info length = %d invalid!!\n",
length);
BTC_TRACE(trace_buf);
return;
}
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], Bt_info[%d], len=%d, data=[%02x %02x %02x %02x %02x %02x]\n",
tmp_buf[0], length, tmp_buf[1], tmp_buf[2], tmp_buf[3],
tmp_buf[4], tmp_buf[5], tmp_buf[6]);
BTC_TRACE(trace_buf);
for (i = 0; i < 7; i++)
coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
if (coex_sta->bt_info_c2h[rsp_source][1] == coex_sta->bt_info_lb2 &&
coex_sta->bt_info_c2h[rsp_source][2] == coex_sta->bt_info_lb3 &&
coex_sta->bt_info_c2h[rsp_source][3] == coex_sta->bt_info_hb0 &&
coex_sta->bt_info_c2h[rsp_source][4] == coex_sta->bt_info_hb1 &&
coex_sta->bt_info_c2h[rsp_source][5] == coex_sta->bt_info_hb2 &&
coex_sta->bt_info_c2h[rsp_source][6] == coex_sta->bt_info_hb3) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], Return because Btinfo duplicate!!\n");
BTC_TRACE(trace_buf);
return;
}
coex_sta->bt_info_lb2 = coex_sta->bt_info_c2h[rsp_source][1];
coex_sta->bt_info_lb3 = coex_sta->bt_info_c2h[rsp_source][2];
coex_sta->bt_info_hb0 = coex_sta->bt_info_c2h[rsp_source][3];
coex_sta->bt_info_hb1 = coex_sta->bt_info_c2h[rsp_source][4];
coex_sta->bt_info_hb2 = coex_sta->bt_info_c2h[rsp_source][5];
coex_sta->bt_info_hb3 = coex_sta->bt_info_c2h[rsp_source][6];
/* ========== BT info Low-Byte2 ========== */
/* if 0xff, it means BT is under WHCK test */
coex_sta->bt_whck_test = (coex_sta->bt_info_lb2 == 0xff);
coex_sta->bt_inq_page = ((coex_sta->bt_info_lb2 & BIT(2)) == BIT(2));
if (coex_sta->bt_inq_page_pre != coex_sta->bt_inq_page) {
coex_sta->bt_inq_page_pre = coex_sta->bt_inq_page;
coex_sta->bt_inq_page_remain = TRUE;
if (!coex_sta->bt_inq_page)
btc->btc_set_timer(btc, BTC_TIMER_BT_INQPAGE, 2);
}
coex_sta->bt_acl_busy = ((coex_sta->bt_info_lb2 & BIT(3)) == BIT(3));
/* ========== BT info Low-Byte3 ========== */
coex_sta->cnt_bt[BTC_CNT_BT_RETRY] = coex_sta->bt_info_lb3 & 0xf;
if (coex_sta->cnt_bt[BTC_CNT_BT_RETRY] >= 1)
coex_sta->cnt_bt[BTC_CNT_BT_POPEVENT]++;
coex_sta->bt_fix_2M = ((coex_sta->bt_info_lb3 & BIT(4)) == BIT(4));
coex_sta->bt_inq = ((coex_sta->bt_info_lb3 & BIT(5)) == BIT(5));
coex_sta->bt_mesh = ((coex_sta->bt_info_lb3 & BIT(6)) == BIT(6));
if (coex_sta->bt_inq)
coex_sta->cnt_bt[BTC_CNT_BT_INQ]++;
coex_sta->bt_page = ((coex_sta->bt_info_lb3 & BIT(7)) == BIT(7));
if (coex_sta->bt_page)
coex_sta->cnt_bt[BTC_CNT_BT_PAGE]++;
/* ========== BT info High-Byte0 ========== */
/* unit: %, value-100 to translate to unit: dBm */
if (btc->chip_para->bt_rssi_type == BTC_BTRSSI_RATIO) {
coex_sta->bt_rssi = coex_sta->bt_info_hb0 * 2 + 10;
} else { /* coex_sta->bt_info_hb0 is just dbm */
if (coex_sta->bt_info_hb0 <= 127)
coex_sta->bt_rssi = 100;
else if (256 - coex_sta->bt_info_hb0 <= 100)
coex_sta->bt_rssi = 100 - (256 - coex_sta->bt_info_hb0);
else
coex_sta->bt_rssi = 0;
}
/* ========== BT info High-Byte1 ========== */
coex_sta->bt_ble_exist = ((coex_sta->bt_info_hb1 & BIT(0)) == BIT(0));
if (coex_sta->bt_info_hb1 & BIT(1))
coex_sta->cnt_bt[BTC_CNT_BT_REINIT]++;
if ((coex_sta->bt_info_hb1 & BIT(2)) ||
(coex_sta->bt_page && coex_sta->wl_pnp_wakeup)) {
coex_sta->cnt_bt[BTC_CNT_BT_SETUPLINK]++;
coex_sta->bt_setup_link = TRUE;
if (coex_sta->bt_reenable)
btc->btc_set_timer(btc, BTC_TIMER_BT_RELINK, 6);
else
btc->btc_set_timer(btc, BTC_TIMER_BT_RELINK, 1);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], Re-Link start in BT info!!\n");
BTC_TRACE(trace_buf);
}
if (coex_sta->bt_info_hb1 & BIT(3))
coex_sta->cnt_bt[BTC_CNT_BT_IGNWLANACT]++;
coex_sta->bt_ble_voice = ((coex_sta->bt_info_hb1 & BIT(4)) == BIT(4));
coex_sta->bt_ble_scan_en = ((coex_sta->bt_info_hb1 & BIT(5)) == BIT(5));
if (coex_sta->bt_info_hb1 & BIT(6))
coex_sta->cnt_bt[BTC_CNT_BT_ROLESWITCH]++;
coex_sta->bt_multi_link = ((coex_sta->bt_info_hb1 & BIT(7)) == BIT(7));
/* for multi_link = 0 but bt pkt remain exist ->
* Use PS-TDMA to protect WL RX
*/
if (!coex_sta->bt_multi_link && coex_sta->bt_multi_link_pre) {
coex_sta->bt_multi_link_remain = TRUE;
btc->btc_set_timer(btc, BTC_TIMER_BT_MULTILINK, 3);
}
coex_sta->bt_multi_link_pre = coex_sta->bt_multi_link;
/* Here we need to resend some wifi info to BT */
/* because bt is reset and loss of the info. */
/* Re-Init */
if ((coex_sta->bt_info_hb1 & BIT(1))) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], BT Re-init, send wifi BW & Chnl to BT!!\n");
BTC_TRACE(trace_buf);
if (link_info_ext->is_connected)
type = BTC_MEDIA_CONNECT;
else
type = BTC_MEDIA_DISCONNECT;
rtw_btc_update_wl_ch_info(btc, type);
}
/* If Ignore_WLanAct && not SetUp_Link */
if ((coex_sta->bt_info_hb1 & BIT(3)) &&
(!(coex_sta->bt_info_hb1 & BIT(2)))) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n");
BTC_TRACE(trace_buf);
rtw_btc_ignore_wlan_act(btc, FC_EXCU, FALSE);
}
/* ========== BT info High-Byte2 ========== */
coex_sta->bt_opp_exist = ((coex_sta->bt_info_hb2 & BIT(0)) == BIT(0));
if (coex_sta->bt_info_hb2 & BIT(1))
coex_sta->cnt_bt[BTC_CNT_BT_AFHUPDATE]++;
coex_sta->bt_a2dp_active = ((coex_sta->bt_info_hb2 & BIT(2)) == BIT(2));
coex_sta->bt_slave = ((coex_sta->bt_info_hb2 & BIT(3)) == BIT(3));
coex_sta->bt_hid_slot = (coex_sta->bt_info_hb2 & 0x30) >> 4;
coex_sta->bt_hid_pair_num = (coex_sta->bt_info_hb2 & 0xc0) >> 6;
if (coex_sta->bt_hid_pair_num > 0 && coex_sta->bt_hid_slot >= 2) {
coex_sta->bt_418_hid_exist = TRUE;
} else if (coex_sta->bt_hid_slot == 1 && coex_sta->bt_ctr_ok &&
(coex_sta->hi_pri_rx + 100 < coex_sta->hi_pri_tx) &&
coex_sta->hi_pri_rx < 100) {
coex_sta->bt_ble_hid_exist = TRUE;
} else if (coex_sta->bt_hid_pair_num == 0 ||
coex_sta->bt_hid_slot == 1) {
coex_sta->bt_418_hid_exist = FALSE;
coex_sta->bt_ble_hid_exist = FALSE;
}
/* ========== BT info High-Byte3 ========== */
if ((coex_sta->bt_info_lb2 & 0x49) == 0x49)
coex_sta->bt_a2dp_bitpool = (coex_sta->bt_info_hb3 & 0x7f);
else
coex_sta->bt_a2dp_bitpool = 0;
coex_sta->bt_a2dp_sink = ((coex_sta->bt_info_hb3 & BIT(7)) == BIT(7));
rtw_btc_update_bt_link_info(btc);
rtw_btc_run_coex(btc, BTC_RSN_BTINFO);
}
void rtw_btc_ex_wl_fwdbginfo_notify(struct btc_coexist *btc, u8 *tmp_buf,
u8 length)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
u8 i = 0, val = 0;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], WiFi Fw Dbg info = %d %d %d %d %d %d %d %d (len = %d)\n",
tmp_buf[0], tmp_buf[1], tmp_buf[2], tmp_buf[3], tmp_buf[4],
tmp_buf[5], tmp_buf[6], tmp_buf[7], length);
BTC_TRACE(trace_buf);
if (tmp_buf[0] != 0x8)
return;
for (i = 1; i <= 7; i++) {
val = coex_sta->wl_fw_dbg_info_pre[i];
if (tmp_buf[i] >= val)
coex_sta->wl_fw_dbg_info[i] = tmp_buf[i] - val;
else
coex_sta->wl_fw_dbg_info[i] = 255 - val + tmp_buf[i];
coex_sta->wl_fw_dbg_info_pre[i] = tmp_buf[i];
}
/* wl_fwdbginfo_notify is auto send by WL FW if TDMA slot toggle = 20
* coex_sta->wl_fw_dbg_info[6] = TDMA slot toggle
* For debug, TDMA slot toggle should be calculated by 2-second
*/
coex_sta->cnt_wl[BTC_CNT_WL_FW_NOTIFY]++;
rtw_btc_wl_ccklock_action(btc);
}
void rtw_btc_ex_rx_rate_change_notify(struct btc_coexist *btc,
BOOLEAN is_data_frame, u8 btc_rate_id)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (is_data_frame)
coex_sta->wl_rx_rate = btc_rate_id;
else
coex_sta->wl_rts_rx_rate = btc_rate_id;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): rate id = %d, RTS_Rate = %d\n", __func__,
coex_sta->wl_rx_rate, coex_sta->wl_rts_rx_rate);
BTC_TRACE(trace_buf);
rtw_btc_wl_ccklock_detect(btc);
}
void rtw_btc_ex_tx_rate_change_notify(struct btc_coexist *btc, u8 tx_rate,
u8 tx_retry_ratio, u8 macid)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): Tx_Rate = %d, Tx_Retry_Ratio = %d, macid =%d\n",
__func__, tx_rate, tx_retry_ratio, macid);
BTC_TRACE(trace_buf);
coex_sta->wl_tx_rate = tx_rate;
coex_sta->wl_tx_retry_ratio = tx_retry_ratio;
coex_sta->wl_tx_macid = macid;
}
void rtw_btc_ex_rf_status_notify(struct btc_coexist *btc, u8 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
if (type == BTC_RF_ON) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): RF is turned ON!!\n", __func__);
BTC_TRACE(trace_buf);
btc->stop_coex_dm = FALSE;
btc->wl_rf_state_off = FALSE;
} else if (type == BTC_RF_OFF) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): RF is turned Off!!\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_action_wl_off(btc);
}
}
void rtw_btc_ex_halt_notify(struct btc_coexist *btc)
{
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_action_wl_off(btc);
}
void rtw_btc_ex_pnp_notify(struct btc_coexist *btc, u8 pnp_state)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
struct btc_wifi_link_info_ext *link_info_ext = &btc->wifi_link_info_ext;
u8 phase;
if (pnp_state == BTC_WIFI_PNP_SLEEP ||
pnp_state == BTC_WIFI_PNP_SLEEP_KEEP_ANT) {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): Sleep\n", __func__);
BTC_TRACE(trace_buf);
btc->btc_write_scbd(btc, BTC_SCBD_ALL, FALSE);
if (pnp_state == BTC_WIFI_PNP_SLEEP_KEEP_ANT) {
if (link_info_ext->is_all_under_5g)
phase = BTC_ANT_5G;
else
phase = BTC_ANT_2G;
} else {
phase = BTC_ANT_WOFF;
}
rtw_btc_set_ant_path(btc, FC_EXCU, phase);
btc->stop_coex_dm = TRUE;
} else {
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): Wake up\n", __func__);
BTC_TRACE(trace_buf);
coex_sta->wl_pnp_wakeup = TRUE;
btc->btc_set_timer(btc, BTC_TIMER_WL_PNPWAKEUP, 3);
/*WoWLAN*/
if (coex_sta->wl_pnp_state_pre == BTC_WIFI_PNP_SLEEP_KEEP_ANT ||
pnp_state == BTC_WIFI_PNP_WOWLAN) {
btc->stop_coex_dm = FALSE;
rtw_btc_run_coex(btc, BTC_RSN_PNP);
}
}
coex_sta->wl_pnp_state_pre = pnp_state;
}
void rtw_btc_ex_coex_dm_reset(struct btc_coexist *btc)
{
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s()\n", __func__);
BTC_TRACE(trace_buf);
rtw_btc_init_hw_config(btc, FALSE);
}
void rtw_btc_ex_periodical(struct btc_coexist *btc)
{
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], ============== Periodical ==============\n");
BTC_TRACE(trace_buf);
}
void rtw_btc_ex_timerup_notify(struct btc_coexist *btc, u32 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
boolean is_change = FALSE;
if (type & BIT(BTC_TIMER_WL_STAYBUSY)) {
if (!coex_sta->wl_busy_pre) {
coex_sta->wl_gl_busy = FALSE;
is_change = TRUE;
rtw_btc_update_wl_ch_info(btc, BTC_MEDIA_DISCONNECT);
btc->btc_write_scbd(btc, BTC_SCBD_WLBUSY, FALSE);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL busy -> idle!!\n", __func__);
BTC_TRACE(trace_buf);
}
}
/*avoid no connect finish notify */
if (type & BIT(BTC_TIMER_WL_COEXFREEZE)) {
coex_sta->coex_freeze = FALSE;
coex_sta->wl_hi_pri_task1 = FALSE;
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): Coex is de-freeze!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_TIMER_WL_SPECPKT)) {
if (!coex_sta->coex_freeze) {
coex_sta->wl_hi_pri_task1 = FALSE;
is_change = TRUE;
}
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL SPECPKT finish!\n", __func__);
BTC_TRACE(trace_buf);
}
/*for A2DP glitch during connecting AP*/
if (type & BIT(BTC_TIMER_WL_CONNPKT)) {
coex_sta->wl_connecting = FALSE;
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL connecting stop!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_TIMER_WL_PNPWAKEUP)) {
coex_sta->wl_pnp_wakeup = FALSE;
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL pnp wakeup stop!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_TIMER_WL_CCKLOCK)) {
if (coex_sta->wl_cck_lock_pre) {
coex_sta->wl_cck_lock_ever = TRUE;
is_change = TRUE;
}
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL CCK Lock Detect!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_TIMER_BT_RELINK)) {
coex_sta->bt_setup_link = FALSE;
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): Re-Link stop!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_TIMER_BT_REENABLE)) {
coex_sta->bt_reenable = FALSE;
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT renable finish!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_TIMER_BT_MULTILINK)) {
coex_sta->bt_multi_link_remain = FALSE;
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT multilink disappear !!\n",
__func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_TIMER_BT_INQPAGE)) {
coex_sta->bt_inq_page_remain = FALSE;
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): BT inq_page disappear !!\n",
__func__);
BTC_TRACE(trace_buf);
}
if (is_change)
rtw_btc_run_coex(btc, BTC_RSN_TIMERUP);
}
void rtw_btc_ex_wl_status_change_notify(struct btc_coexist *btc, u32 type)
{
struct btc_coex_sta *coex_sta = &btc->coex_sta;
boolean is_change = FALSE;
if (type & BIT(BTC_WLSTATUS_CHANGE_TOIDLE)) { /* if busy->idle */
coex_sta->wl_busy_pre = FALSE;
btc->btc_set_timer(btc, BTC_TIMER_WL_STAYBUSY, 6);
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL busy -> idle!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_WLSTATUS_CHANGE_TOBUSY)) { /* if idle->busy */
coex_sta->wl_gl_busy = TRUE;
coex_sta->wl_busy_pre = TRUE;
is_change = TRUE;
rtw_btc_update_wl_ch_info(btc, BTC_MEDIA_CONNECT);
#if 0
btc->btc_write_scbd(btc, BTC_SCBD_WLBUSY, TRUE);
#endif
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL idle -> busy!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_WLSTATUS_CHANGE_RSSI)) { /* if RSSI change */
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL RSSI change!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_WLSTATUS_CHANGE_LINKINFO)) { /* if linkinfo change */
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL LinkInfo change!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_WLSTATUS_CHANGE_DIR)) { /*if WL UL-DL change*/
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s(): WL UL-DL change!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_WLSTATUS_CHANGE_NOISY)) { /*if noisy level change*/
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s():Noisy Level change!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_WLSTATUS_CHANGE_BTCNT)) { /*if BT counter change*/
is_change = TRUE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s():BT counter change!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (type & BIT(BTC_WLSTATUS_CHANGE_LOCKTRY)) { /*if WL CCK lock try*/
is_change = TRUE;
coex_sta->wl_cck_lock_ever = FALSE;
coex_sta->wl_cck_lock = FALSE;
BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE,
"[BTCoex], %s():WL CCK lock try!!\n", __func__);
BTC_TRACE(trace_buf);
}
if (is_change)
rtw_btc_run_coex(btc, BTC_RSN_WLSTATUS);
}
#endif
/* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */