void ar9003_mci_send_wlan_channels(struct ath_hw *ah) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; mci->wlan_channels_update = true; ar9003_mci_send_coex_wlan_channels(ah, true); }
static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type, u8 gpm_opcode, u32 *p_gpm) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u8 *p_data = (u8 *) p_gpm; if (gpm_type != MCI_GPM_COEX_AGENT) return; switch (gpm_opcode) { case MCI_GPM_COEX_VERSION_QUERY: ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n"); ar9003_mci_send_coex_version_response(ah, true); break; case MCI_GPM_COEX_VERSION_RESPONSE: ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n"); mci->bt_ver_major = *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION); mci->bt_ver_minor = *(p_data + MCI_GPM_COEX_B_MINOR_VERSION); mci->bt_version_known = true; ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n", mci->bt_ver_major, mci->bt_ver_minor); break; case MCI_GPM_COEX_STATUS_QUERY: ath_dbg(common, MCI, "MCI Recv GPM COEX Status Query = 0x%02X\n", *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP)); mci->wlan_channels_update = true; ar9003_mci_send_coex_wlan_channels(ah, true); break; case MCI_GPM_COEX_BT_PROFILE_INFO: mci->query_bt = true; ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n"); break; case MCI_GPM_COEX_BT_STATUS_UPDATE: mci->query_bt = true; ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n", *(p_gpm + 3)); break; default: break; } }
static void ar9003_mci_sync_bt_state(struct ath_hw *ah) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 cur_bt_state; cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP); if (mci->bt_state != cur_bt_state) mci->bt_state = cur_bt_state; if (mci->bt_state != MCI_BT_SLEEP) { ar9003_mci_send_coex_version_query(ah, true); ar9003_mci_send_coex_wlan_channels(ah, true); if (mci->unhalt_bt_gpm == true) ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); } }
u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 value = 0; u8 query_type; switch (state_type) { case MCI_STATE_ENABLE: if (mci->ready) { value = REG_READ(ah, AR_BTCOEX_CTRL); if ((value == 0xdeadbeef) || (value == 0xffffffff)) value = 0; } value &= AR_BTCOEX_CTRL_MCI_MODE_EN; break; case MCI_STATE_LAST_SCHD_MSG_OFFSET: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_LAST_SCHD_MSG_INDEX); /* Make it in bytes */ value <<= 4; break; case MCI_STATE_REMOTE_SLEEP: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP) ? MCI_BT_SLEEP : MCI_BT_AWAKE; break; case MCI_STATE_SET_BT_AWAKE: mci->bt_state = MCI_BT_AWAKE; ar9003_mci_send_coex_version_query(ah, true); ar9003_mci_send_coex_wlan_channels(ah, true); if (mci->unhalt_bt_gpm) ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); ar9003_mci_2g5g_switch(ah, false); break; case MCI_STATE_RESET_REQ_WAKE: ar9003_mci_reset_req_wakeup(ah); mci->update_2g5g = true; if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) { /* Check if we still have control of the GPIOs */ if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & ATH_MCI_CONFIG_MCI_OBS_GPIO) != ATH_MCI_CONFIG_MCI_OBS_GPIO) { ar9003_mci_observation_set_up(ah); } } break; case MCI_STATE_SEND_WLAN_COEX_VERSION: ar9003_mci_send_coex_version_response(ah, true); break; case MCI_STATE_SEND_VERSION_QUERY: ar9003_mci_send_coex_version_query(ah, true); break; case MCI_STATE_SEND_STATUS_QUERY: query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY; ar9003_mci_send_coex_bt_status_query(ah, true, query_type); break; case MCI_STATE_RECOVER_RX: ar9003_mci_prep_interface(ah); mci->query_bt = true; mci->need_flush_btinfo = true; ar9003_mci_send_coex_wlan_channels(ah, true); ar9003_mci_2g5g_switch(ah, false); break; case MCI_STATE_NEED_FTP_STOMP: value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); break; default: break; } return value; }
u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 value = 0, tsf; u8 query_type; switch (state_type) { case MCI_STATE_ENABLE: if (mci->ready) { value = REG_READ(ah, AR_BTCOEX_CTRL); if ((value == 0xdeadbeef) || (value == 0xffffffff)) value = 0; } value &= AR_BTCOEX_CTRL_MCI_MODE_EN; break; case MCI_STATE_INIT_GPM_OFFSET: value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); if (value < mci->gpm_len) mci->gpm_idx = value; else mci->gpm_idx = 0; break; case MCI_STATE_LAST_SCHD_MSG_OFFSET: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_LAST_SCHD_MSG_INDEX); /* Make it in bytes */ value <<= 4; break; case MCI_STATE_REMOTE_SLEEP: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP) ? MCI_BT_SLEEP : MCI_BT_AWAKE; break; case MCI_STATE_SET_BT_AWAKE: mci->bt_state = MCI_BT_AWAKE; ar9003_mci_send_coex_version_query(ah, true); ar9003_mci_send_coex_wlan_channels(ah, true); if (mci->unhalt_bt_gpm) ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); ar9003_mci_2g5g_switch(ah, false); break; case MCI_STATE_RESET_REQ_WAKE: ar9003_mci_reset_req_wakeup(ah); mci->update_2g5g = true; if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) { /* Check if we still have control of the GPIOs */ if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & ATH_MCI_CONFIG_MCI_OBS_GPIO) != ATH_MCI_CONFIG_MCI_OBS_GPIO) { ar9003_mci_observation_set_up(ah); } } break; case MCI_STATE_SEND_WLAN_COEX_VERSION: ar9003_mci_send_coex_version_response(ah, true); break; case MCI_STATE_SEND_VERSION_QUERY: ar9003_mci_send_coex_version_query(ah, true); break; case MCI_STATE_SEND_STATUS_QUERY: query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY; ar9003_mci_send_coex_bt_status_query(ah, true, query_type); break; case MCI_STATE_RECOVER_RX: tsf = ath9k_hw_gettsf32(ah); if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) { ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) ignore Rx recovery\n"); break; } ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) RECOVER RX\n"); mci->last_recovery = tsf; ar9003_mci_prep_interface(ah); mci->query_bt = true; mci->need_flush_btinfo = true; ar9003_mci_send_coex_wlan_channels(ah, true); ar9003_mci_2g5g_switch(ah, false); break; case MCI_STATE_NEED_FTP_STOMP: value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); break; case MCI_STATE_NEED_FLUSH_BT_INFO: value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; mci->need_flush_btinfo = false; break; case MCI_STATE_AIC_CAL: if (ath9k_hw_is_aic_enabled(ah)) value = ar9003_aic_calibration(ah); break; case MCI_STATE_AIC_START: if (ath9k_hw_is_aic_enabled(ah)) ar9003_aic_start_normal(ah); break; case MCI_STATE_AIC_CAL_RESET: if (ath9k_hw_is_aic_enabled(ah)) value = ar9003_aic_cal_reset(ah); break; case MCI_STATE_AIC_CAL_SINGLE: if (ath9k_hw_is_aic_enabled(ah)) value = ar9003_aic_calibration_single(ah); break; default: break; } return value; }
u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 value = 0, more_gpm = 0, gpm_ptr; u8 query_type; switch (state_type) { case MCI_STATE_ENABLE: if (mci->ready) { value = REG_READ(ah, AR_BTCOEX_CTRL); if ((value == 0xdeadbeef) || (value == 0xffffffff)) value = 0; } value &= AR_BTCOEX_CTRL_MCI_MODE_EN; break; case MCI_STATE_INIT_GPM_OFFSET: value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); mci->gpm_idx = value; break; case MCI_STATE_NEXT_GPM_OFFSET: case MCI_STATE_LAST_GPM_OFFSET: REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_GPM); gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); value = gpm_ptr; if (value == 0) value = mci->gpm_len - 1; else if (value >= mci->gpm_len) { if (value != 0xFFFF) value = 0; } else { value--; } if (value == 0xFFFF) { value = MCI_GPM_INVALID; more_gpm = MCI_GPM_NOMORE; } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) { if (gpm_ptr == mci->gpm_idx) { value = MCI_GPM_INVALID; more_gpm = MCI_GPM_NOMORE; } else { for (;;) { u32 temp_index; if (value != mci->gpm_idx) more_gpm = MCI_GPM_MORE; else more_gpm = MCI_GPM_NOMORE; temp_index = mci->gpm_idx; mci->gpm_idx++; if (mci->gpm_idx >= mci->gpm_len) mci->gpm_idx = 0; if (ar9003_mci_is_gpm_valid(ah, temp_index)) { value = temp_index; break; } if (more_gpm == MCI_GPM_NOMORE) { value = MCI_GPM_INVALID; break; } } } if (p_data) *p_data = more_gpm; } if (value != MCI_GPM_INVALID) value <<= 4; break; case MCI_STATE_LAST_SCHD_MSG_OFFSET: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_LAST_SCHD_MSG_INDEX); value <<= 4; break; case MCI_STATE_REMOTE_SLEEP: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP) ? MCI_BT_SLEEP : MCI_BT_AWAKE; break; case MCI_STATE_CONT_RSSI_POWER: value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER); break; case MCI_STATE_CONT_PRIORITY: value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY); break; case MCI_STATE_CONT_TXRX: value = MS(mci->cont_status, AR_MCI_CONT_TXRX); break; case MCI_STATE_BT: value = mci->bt_state; break; case MCI_STATE_SET_BT_SLEEP: mci->bt_state = MCI_BT_SLEEP; break; case MCI_STATE_SET_BT_AWAKE: mci->bt_state = MCI_BT_AWAKE; ar9003_mci_send_coex_version_query(ah, true); ar9003_mci_send_coex_wlan_channels(ah, true); if (mci->unhalt_bt_gpm) ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); ar9003_mci_2g5g_switch(ah, true); break; case MCI_STATE_SET_BT_CAL_START: mci->bt_state = MCI_BT_CAL_START; break; case MCI_STATE_SET_BT_CAL: mci->bt_state = MCI_BT_CAL; break; case MCI_STATE_RESET_REQ_WAKE: ar9003_mci_reset_req_wakeup(ah); mci->update_2g5g = true; if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) { if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & ATH_MCI_CONFIG_MCI_OBS_GPIO) != ATH_MCI_CONFIG_MCI_OBS_GPIO) { ar9003_mci_observation_set_up(ah); } } break; case MCI_STATE_SEND_WLAN_COEX_VERSION: ar9003_mci_send_coex_version_response(ah, true); break; case MCI_STATE_SET_BT_COEX_VERSION: if (!p_data) ath_dbg(common, MCI, "MCI Set BT Coex version with NULL data!!\n"); else { mci->bt_ver_major = (*p_data >> 8) & 0xff; mci->bt_ver_minor = (*p_data) & 0xff; mci->bt_version_known = true; ath_dbg(common, MCI, "MCI BT version set: %d.%d\n", mci->bt_ver_major, mci->bt_ver_minor); } break; case MCI_STATE_SEND_WLAN_CHANNELS: if (p_data) { if (((mci->wlan_channels[1] & 0xffff0000) == (*(p_data + 1) & 0xffff0000)) && (mci->wlan_channels[2] == *(p_data + 2)) && (mci->wlan_channels[3] == *(p_data + 3))) break; mci->wlan_channels[0] = *p_data++; mci->wlan_channels[1] = *p_data++; mci->wlan_channels[2] = *p_data++; mci->wlan_channels[3] = *p_data++; } mci->wlan_channels_update = true; ar9003_mci_send_coex_wlan_channels(ah, true); break; case MCI_STATE_SEND_VERSION_QUERY: ar9003_mci_send_coex_version_query(ah, true); break; case MCI_STATE_SEND_STATUS_QUERY: query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY; ar9003_mci_send_coex_bt_status_query(ah, true, query_type); break; case MCI_STATE_NEED_FLUSH_BT_INFO: value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; if (p_data) mci->need_flush_btinfo = (*p_data != 0) ? true : false; break; case MCI_STATE_RECOVER_RX: ar9003_mci_prep_interface(ah); mci->query_bt = true; mci->need_flush_btinfo = true; ar9003_mci_send_coex_wlan_channels(ah, true); ar9003_mci_2g5g_switch(ah, true); break; case MCI_STATE_NEED_FTP_STOMP: value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); break; case MCI_STATE_NEED_TUNING: value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING); break; default: break; } return value; }