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;
}
Example #2
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))
		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);
}
Example #6
0
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;
}