Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / ath / ath9k / hw.c
index e1dc084eac5bbb567372db35aa716ca62180e5a3..caf572cf270fa7cb0395521279c1907b7eeafe96 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <asm/unaligned.h>
 
 #include "hw.h"
@@ -1349,6 +1350,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 {
+       bool ret = false;
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                REG_WRITE(ah, AR_WA, ah->WARegVal);
@@ -1360,13 +1362,20 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 
        switch (type) {
        case ATH9K_RESET_POWER_ON:
-               return ath9k_hw_set_reset_power_on(ah);
+               ret = ath9k_hw_set_reset_power_on(ah);
+               break;
        case ATH9K_RESET_WARM:
        case ATH9K_RESET_COLD:
-               return ath9k_hw_set_reset(ah, type);
+               ret = ath9k_hw_set_reset(ah, type);
+               break;
        default:
-               return false;
+               break;
        }
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+               REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
+       return ret;
 }
 
 static bool ath9k_hw_chip_reset(struct ath_hw *ah,
@@ -1505,6 +1514,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                   struct ath9k_hw_cal_data *caldata, bool bChannelChange)
 {
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        u32 saveLedState;
        struct ath9k_channel *curchan = ah->curchan;
        u32 saveDefAntenna;
@@ -1512,6 +1522,53 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        u64 tsf = 0;
        int i, r;
        bool allow_fbs = false;
+       bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
+       bool save_fullsleep = ah->chip_fullsleep;
+
+       if (mci) {
+
+               ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
+
+               if (mci_hw->bt_state == MCI_BT_CAL_START) {
+                       u32 payload[4] = {0, 0, 0, 0};
+
+                       ath_dbg(common, ATH_DBG_MCI, "MCI stop rx for BT CAL");
+
+                       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);
+
+                       ath_dbg(common, ATH_DBG_MCI, "send WLAN_CAL_GRANT");
+                       MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
+                       ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
+                                               16, true, false);
+
+                       ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is calibrating");
+
+                       /* 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, ATH_DBG_MCI,
+                                       "MCI got BT_CAL_DONE\n");
+                       else
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI ### BT cal takes to long, force"
+                                       "bt_state to be bt_awake\n");
+                       mci_hw->bt_state = MCI_BT_AWAKE;
+                       /* MCI FIX: enable mci interrupt here */
+                       ar9003_mci_enable_interrupt(ah);
+
+                       return true;
+               }
+       }
+
 
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
@@ -1549,12 +1606,29 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                if (ath9k_hw_channel_change(ah, chan)) {
                        ath9k_hw_loadnf(ah, ah->curchan);
                        ath9k_hw_start_nfcal(ah, true);
+                       if (mci && mci_hw->ready)
+                               ar9003_mci_2g5g_switch(ah, true);
+
                        if (AR_SREV_9271(ah))
                                ar9002_hw_load_ani_reg(ah, chan);
                        return 0;
                }
        }
 
+       if (mci) {
+               ar9003_mci_disable_interrupt(ah);
+
+               if (mci_hw->ready && !save_fullsleep) {
+                       ar9003_mci_mute_bt(ah);
+                       udelay(20);
+                       REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
+               }
+
+               mci_hw->bt_state = MCI_BT_SLEEP;
+               mci_hw->ready = false;
+       }
+
+
        saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
        if (saveDefAntenna == 0)
                saveDefAntenna = 1;
@@ -1610,6 +1684,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (r)
                return r;
 
+       if (mci)
+               ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
+
        /*
         * Some AR91xx SoC devices frequently fail to accept TSF writes
         * right after the chip reset. When that happens, write a new
@@ -1724,6 +1801,58 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (!ath9k_hw_init_cal(ah, chan))
                return -EIO;
 
+       ath9k_hw_loadnf(ah, chan);
+       ath9k_hw_start_nfcal(ah, true);
+
+       if (mci && mci_hw->ready) {
+
+               if (IS_CHAN_2GHZ(chan) &&
+                   (mci_hw->bt_state == MCI_BT_SLEEP)) {
+
+                       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)) {
+
+                               /*
+                                * 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.
+                                */
+
+                               ath_dbg(common, ATH_DBG_MCI, "MCI BT wakes up"
+                                       "during WLAN calibration\n");
+
+                               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                                         AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
+                                         AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
+                               ath_dbg(common, ATH_DBG_MCI, "MCI send"
+                                       "REMOTE_RESET\n");
+                               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;
+
+                               ath_dbg(common, ATH_DBG_MCI, "MCI re-cal\n");
+
+                               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;
+
+                       }
+               }
+               ar9003_mci_enable_interrupt(ah);
+       }
+
        ENABLE_REGWRITE_BUFFER(ah);
 
        ath9k_hw_restore_chainmask(ah);
@@ -1766,6 +1895,21 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ah->btcoex_hw.enabled)
                ath9k_hw_btcoex_enable(ah);
 
+       if (mci && mci_hw->ready) {
+               /*
+                * check BT state again to make
+                * sure it's not changed.
+                */
+
+               ar9003_mci_sync_bt_state(ah);
+               ar9003_mci_2g5g_switch(ah, true);
+
+               if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
+                               (mci_hw->query_bt == true)) {
+                       mci_hw->need_flush_btinfo = true;
+               }
+       }
+
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ar9003_hw_bb_watchdog_config(ah);
 
@@ -1823,7 +1967,8 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
        }
 
        /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
-       REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
 }
 
 /*
@@ -1929,6 +2074,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 {
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        int status = true, setChip = true;
        static const char *modes[] = {
                "AWAKE",
@@ -1946,12 +2092,35 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
        switch (mode) {
        case ATH9K_PM_AWAKE:
                status = ath9k_hw_set_power_awake(ah, setChip);
+
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
                break;
        case ATH9K_PM_FULL_SLEEP:
+
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
+                       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
+                               (mci->bt_state != MCI_BT_SLEEP) &&
+                               !mci->halted_bt_gpm) {
+                               ath_dbg(common, ATH_DBG_MCI, "MCI halt BT GPM"
+                                               "(full_sleep)");
+                               ar9003_mci_send_coex_halt_bt_gpm(ah,
+                                                                true, true);
+                       }
+
+                       mci->ready = false;
+                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+               }
+
                ath9k_set_power_sleep(ah, setChip);
                ah->chip_fullsleep = true;
                break;
        case ATH9K_PM_NETWORK_SLEEP:
+
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
                ath9k_set_power_network_sleep(ah, setChip);
                break;
        default:
@@ -2144,6 +2313,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 
        if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah))
                chip_chainmask = 1;
+       else if (AR_SREV_9462(ah))
+               chip_chainmask = 3;
        else if (!AR_SREV_9280_20_OR_LATER(ah))
                chip_chainmask = 7;
        else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah))
@@ -2229,7 +2400,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
        if (common->btcoex_enabled) {
-               if (AR_SREV_9300_20_OR_LATER(ah)) {
+               if (AR_SREV_9462(ah))
+                       btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
+               else if (AR_SREV_9300_20_OR_LATER(ah)) {
                        btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
                        btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
                        btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
@@ -2327,11 +2500,11 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ah->enabled_cals |= TX_IQ_CAL;
-               if (!AR_SREV_9330(ah))
+               if (AR_SREV_9485_OR_LATER(ah))
                        ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
        }
        if (AR_SREV_9462(ah))
-               pCap->hw_caps |= ATH9K_HW_CAP_RTT;
+               pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI;
 
        return 0;
 }