bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); if (mci_hw->bt_state != MCI_BT_CAL_START) return false; mci_hw->bt_state = MCI_BT_CAL; ar9003_mci_disable_interrupt(ah); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, true, false); if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n"); else ath_dbg(common, MCI, "MCI BT_CAL_DONE not received\n"); mci_hw->bt_state = MCI_BT_AWAKE; ar9003_mci_enable_interrupt(ah); return true; }
int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata) { struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; if (!mci_hw->ready) return 0; if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP)) goto exit; if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) && !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) goto exit; /* * BT is sleeping. Check if BT wakes up during * WLAN calibration. If BT wakes up during * WLAN calibration, need to go through all * message exchanges again and recal. */ REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)); ar9003_mci_remote_reset(ah, true); ar9003_mci_send_sys_waking(ah, true); udelay(1); if (IS_CHAN_2GHZ(chan)) ar9003_mci_send_lna_transfer(ah, true); mci_hw->bt_state = MCI_BT_AWAKE; REG_CLR_BIT(ah, AR_PHY_TIMING4, 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); if (caldata) { caldata->done_txiqcal_once = false; caldata->done_txclcal_once = false; caldata->rtt_done = false; } if (!ath9k_hw_init_cal(ah, chan)) return -EIO; REG_SET_BIT(ah, AR_PHY_TIMING4, 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); exit: ar9003_mci_enable_interrupt(ah); return 0; }
int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata) { struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; if (!mci_hw->ready) return 0; if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP)) goto exit; if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) { REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); ar9003_mci_remote_reset(ah, true); ar9003_mci_send_sys_waking(ah, true); udelay(1); if (IS_CHAN_2GHZ(chan)) ar9003_mci_send_lna_transfer(ah, true); mci_hw->bt_state = MCI_BT_AWAKE; if (caldata) { caldata->done_txiqcal_once = false; caldata->done_txclcal_once = false; caldata->rtt_hist.num_readings = 0; } if (!ath9k_hw_init_cal(ah, chan)) return -EIO; } exit: ar9003_mci_enable_interrupt(ah); return 0; }
bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); if (mci_hw->bt_state != MCI_BT_CAL_START) return false; mci_hw->bt_state = MCI_BT_CAL; /* * MCI FIX: disable mci interrupt here. This is to avoid * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and * lead to mci_intr reentry. */ ar9003_mci_disable_interrupt(ah); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, true, false); /* Wait BT calibration to be completed for 25ms */ if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n"); else ath_dbg(common, MCI, "MCI BT_CAL_DONE not received\n"); mci_hw->bt_state = MCI_BT_AWAKE; /* MCI FIX: enable mci interrupt here */ ar9003_mci_enable_interrupt(ah); return true; }
void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, bool is_full_sleep) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 regval; ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n", is_full_sleep, is_2g); if (!mci->gpm_addr && !mci->sched_addr) { ath_dbg(common, MCI, "MCI GPM and schedule buffers are not allocated\n"); return; } if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { ath_dbg(common, MCI, "BTCOEX control register is dead\n"); return; } /* Program MCI DMA related registers */ REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr); REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len); REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr); /* * To avoid MCI state machine be affected by incoming remote MCI msgs, * MCI mode will be enabled later, right before reset the MCI TX and RX. */ regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | SM(1, AR_BTCOEX_CTRL_PA_SHARED) | SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); REG_WRITE(ah, AR_BTCOEX_CTRL, regval); if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) ar9003_mci_osla_setup(ah, true); else ar9003_mci_osla_setup(ah, false); REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_SPDT_ENABLE); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval); REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); /* Resetting the Rx and Tx paths of MCI */ regval = REG_READ(ah, AR_MCI_COMMAND2); regval |= SM(1, AR_MCI_COMMAND2_RESET_TX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); udelay(1); regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); if (is_full_sleep) { ar9003_mci_mute_bt(ah); udelay(100); } /* Check pending GPM msg before MCI Reset Rx */ ar9003_mci_check_gpm_offset(ah); regval |= SM(1, AR_MCI_COMMAND2_RESET_RX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); udelay(1); regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); ar9003_mci_get_next_gpm_offset(ah, true, NULL); REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); REG_CLR_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); ar9003_mci_observation_set_up(ah); mci->ready = true; ar9003_mci_prep_interface(ah); if (en_int) ar9003_mci_enable_interrupt(ah); }
int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, bool is_full_sleep) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 regval, i; ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n", is_full_sleep, is_2g); if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { ath_err(common, "BTCOEX control register is dead\n"); return -EINVAL; } /* Program MCI DMA related registers */ REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr); REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len); REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr); /* * To avoid MCI state machine be affected by incoming remote MCI msgs, * MCI mode will be enabled later, right before reset the MCI TX and RX. */ if (AR_SREV_9565(ah)) { u8 ant = MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH); if (ant == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED) ar9003_mci_set_btcoex_ctrl_9565_1ANT(ah); else ar9003_mci_set_btcoex_ctrl_9565_2ANT(ah); } else { ar9003_mci_set_btcoex_ctrl_9462(ah); } if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) ar9003_mci_osla_setup(ah, true); else ar9003_mci_osla_setup(ah, false); REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_SPDT_ENABLE); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 0); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); /* Set the time out to 3.125ms (5 BT slots) */ REG_RMW_FIELD(ah, AR_BTCOEX_WL_LNA, AR_BTCOEX_WL_LNA_TIMEOUT, 0x3D090); /* concurrent tx priority */ if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) { REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE, 0); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_TXPWR_THRESH, 0x7f); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_REDUCE_TXPWR, 0); for (i = 0; i < 8; i++) REG_WRITE(ah, AR_BTCOEX_MAX_TXPWR(i), 0x7f7f7f7f); } regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval); REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); /* Resetting the Rx and Tx paths of MCI */ regval = REG_READ(ah, AR_MCI_COMMAND2); regval |= SM(1, AR_MCI_COMMAND2_RESET_TX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); udelay(1); regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); if (is_full_sleep) { ar9003_mci_mute_bt(ah); udelay(100); } /* Check pending GPM msg before MCI Reset Rx */ ar9003_mci_check_gpm_offset(ah); regval |= SM(1, AR_MCI_COMMAND2_RESET_RX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); udelay(1); regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); /* Init GPM offset after MCI Reset Rx */ ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET); REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) REG_CLR_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); else REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); ar9003_mci_observation_set_up(ah); mci->ready = true; ar9003_mci_prep_interface(ah); ar9003_mci_stat_setup(ah); if (en_int) ar9003_mci_enable_interrupt(ah); if (ath9k_hw_is_aic_enabled(ah)) ar9003_aic_start_normal(ah); return 0; }