ath9k: Fix PeakDetect calibration for AR9462
authorSujith Manoharan <c_manoha@qca.qualcomm.com>
Wed, 11 Sep 2013 11:06:32 +0000 (16:36 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 26 Sep 2013 19:13:47 +0000 (15:13 -0400)
Since HW PeakDetect calibration is turned on for AR9462,
various conditions have to be handled in the driver:

* Enable agc_cal when loading RTT fails.
* Disable SW PeakDetect calibration when RTT calibration is not enabled.
* Keep SW PeakDetect calibration result in driver.
* Update RTT table according to the saved value.
* Write RTT back after modifying SW RTT table.
* Enable local mode for PeakDetect calibration and restore values.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_rtt.c
drivers/net/wireless/ath/ath9k/hw.h

index 687173c8d280ea86147024219d3b7c8ea1082595..22934d3ca54413fa9558a928fdccbc4ab108131a 100644 (file)
@@ -965,18 +965,44 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
 }
 
 static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
-                                        struct ath9k_channel *chan)
+                                        struct ath9k_channel *chan,
+                                        bool run_rtt_cal)
 {
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
        int i;
 
        if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah))
                return;
 
+       if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && !run_rtt_cal)
+               return;
+
        for (i = 0; i < AR9300_MAX_CHAINS; i++) {
                if (!(ah->rxchainmask & (1 << i)))
                        continue;
                ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
        }
+
+       if (caldata)
+               set_bit(SW_PKDET_DONE, &caldata->cal_flags);
+
+       if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && caldata) {
+               if (IS_CHAN_2GHZ(chan)){
+                       caldata->caldac[0] = REG_READ_FIELD(ah,
+                                                   AR_PHY_65NM_RXRF_AGC(0),
+                                                   AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
+                       caldata->caldac[1] = REG_READ_FIELD(ah,
+                                                   AR_PHY_65NM_RXRF_AGC(1),
+                                                   AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
+               } else {
+                       caldata->caldac[0] = REG_READ_FIELD(ah,
+                                                   AR_PHY_65NM_RXRF_AGC(0),
+                                                   AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);
+                       caldata->caldac[1] = REG_READ_FIELD(ah,
+                                                   AR_PHY_65NM_RXRF_AGC(1),
+                                                   AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);
+               }
+       }
 }
 
 static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
@@ -1047,13 +1073,18 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
                ar9003_hw_rtt_clear_hist(ah);
        }
 
-       if (rtt && !run_rtt_cal) {
-               agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL);
-               agc_supp_cals &= agc_ctrl;
-               agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |
-                            AR_PHY_AGC_CONTROL_FLTR_CAL |
-                            AR_PHY_AGC_CONTROL_PKDET_CAL);
-               REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
+       if (rtt) {
+               if (!run_rtt_cal) {
+                       agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL);
+                       agc_supp_cals &= agc_ctrl;
+                       agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |
+                                     AR_PHY_AGC_CONTROL_FLTR_CAL |
+                                     AR_PHY_AGC_CONTROL_PKDET_CAL);
+                       REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
+               } else {
+                       if (ah->ah_flags & AH_FASTCC)
+                               run_agc_cal = true;
+               }
        }
 
        if (ah->enabled_cals & TX_CL_CAL) {
@@ -1124,7 +1155,7 @@ skip_tx_iqcal:
                                       AR_PHY_AGC_CONTROL_CAL,
                                       0, AH_WAIT_TIMEOUT);
 
-               ar9003_hw_do_manual_peak_cal(ah, chan);
+               ar9003_hw_do_manual_peak_cal(ah, chan, run_rtt_cal);
        }
 
        if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
@@ -1159,12 +1190,16 @@ skip_tx_iqcal:
 
        if (run_rtt_cal && caldata) {
                if (is_reusable) {
-                       if (!ath9k_hw_rfbus_req(ah))
+                       if (!ath9k_hw_rfbus_req(ah)) {
                                ath_err(ath9k_hw_common(ah),
                                        "Could not stop baseband\n");
-                       else
+                       } else {
                                ar9003_hw_rtt_fill_hist(ah);
 
+                               if (test_bit(SW_PKDET_DONE, &caldata->cal_flags))
+                                       ar9003_hw_rtt_load_hist(ah);
+                       }
+
                        ath9k_hw_rfbus_done(ah);
                }
 
index e398c181297764bdc811b2034571632b8fc32185..934418872e8e156a641145a512280f3bee6f86bd 100644 (file)
@@ -118,6 +118,27 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
        }
 }
 
+static void ar9003_hw_patch_rtt(struct ath_hw *ah, int index, int chain)
+{
+       int agc, caldac;
+
+       if (!test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags))
+               return;
+
+       if ((index != 5) || (chain >= 2))
+               return;
+
+       agc = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                            AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE);
+       if (!agc)
+               return;
+
+       caldac = ah->caldata->caldac[chain];
+       ah->caldata->rtt_table[chain][index] &= 0xFFFF05FF;
+       caldac = (caldac & 0x20) | ((caldac & 0x1F) << 7);
+       ah->caldata->rtt_table[chain][index] |= (caldac << 4);
+}
+
 static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
 {
        u32 val;
@@ -155,6 +176,9 @@ void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
                for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
                        ah->caldata->rtt_table[chain][i] =
                                ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
+
+                       ar9003_hw_patch_rtt(ah, i, chain);
+
                        ath_dbg(ath9k_hw_common(ah), CALIBRATE,
                                "RTT value at idx %d, chain %d is: 0x%x\n",
                                i, chain, ah->caldata->rtt_table[chain][i]);
@@ -186,11 +210,37 @@ bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
        if (!ah->caldata)
                return false;
 
+       if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) {
+               if (IS_CHAN_2GHZ(chan)){
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
+                                     AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
+                                     ah->caldata->caldac[0]);
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
+                                     AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
+                                     ah->caldata->caldac[1]);
+               } else {
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
+                                     AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
+                                     ah->caldata->caldac[0]);
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
+                                     AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
+                                     ah->caldata->caldac[1]);
+               }
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
+                             AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
+                             AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
+       }
+
        if (!test_bit(RTT_DONE, &ah->caldata->cal_flags))
                return false;
 
        ar9003_hw_rtt_enable(ah);
-       ar9003_hw_rtt_set_mask(ah, 0x10);
+
+       if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags))
+               ar9003_hw_rtt_set_mask(ah, 0x30);
+       else
+               ar9003_hw_rtt_set_mask(ah, 0x10);
 
        if (!ath9k_hw_rfbus_req(ah)) {
                ath_err(ath9k_hw_common(ah), "Could not stop baseband\n");
index e5e927020945b4c9f535d2ff3b2ce24d891626da..2babf931b4598b3c0cf2a2e77a2d0976c8eebf09 100644 (file)
@@ -412,6 +412,7 @@ enum ath9k_cal_flags {
        NFCAL_INTF,
        TXIQCAL_DONE,
        TXCLCAL_DONE,
+       SW_PKDET_DONE,
 };
 
 struct ath9k_hw_cal_data {
@@ -422,6 +423,7 @@ struct ath9k_hw_cal_data {
        int32_t CalValid;
        int8_t iCoff;
        int8_t qCoff;
+       u8 caldac[2];
        u16 small_signal_gain[AR9300_MAX_CHAINS];
        u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
        u32 num_measures[AR9300_MAX_CHAINS];