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;
}
Exemple #5
0
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;
}