ath5k: Update gain_F calibration code and add documentation
authorNick Kossifidis <mick@madwifi-project.org>
Mon, 9 Feb 2009 04:03:41 +0000 (06:03 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 13 Feb 2009 18:44:43 +0000 (13:44 -0500)
 * Update and cleanup rf gain optimization code

 * Add comments and refferences to docs and use sane function names

 * Use only step index on ath5k_gain, no need to have a pointer to
   the current step since we can determine te step from it's index,
   this also allows us to put all other structs on rfgain.h and cleanup
   ath5k.h a little

 * No need for ah_rfgain variable, we use ah_gain.g_state for everything

 * Tested on RF2112B chip but gain_F calibration is not yet done
   (we will finish this on the next patch where we'll rewrite rf-buffer
   handling)

 * Use initial rf gain settings for 2316 and 2317 SoCs introduced on a previous patch

 It seems big but it's mostly cleanup, very few functional changes have been made on phy.c

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath5k/ath5k.h
drivers/net/wireless/ath5k/attach.c
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/phy.c
drivers/net/wireless/ath5k/reset.c
drivers/net/wireless/ath5k/rfbuffer.h
drivers/net/wireless/ath5k/rfgain.h

index 0eda785..c870e2a 100644 (file)
@@ -649,49 +649,21 @@ struct ath5k_beacon_state {
 
 enum ath5k_rfgain {
        AR5K_RFGAIN_INACTIVE = 0,
+       AR5K_RFGAIN_ACTIVE,
        AR5K_RFGAIN_READ_REQUESTED,
        AR5K_RFGAIN_NEED_CHANGE,
 };
 
-#define AR5K_GAIN_CRN_FIX_BITS_5111            4
-#define AR5K_GAIN_CRN_FIX_BITS_5112            7
-#define AR5K_GAIN_CRN_MAX_FIX_BITS             AR5K_GAIN_CRN_FIX_BITS_5112
-#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN         15
-#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN         20
-#define AR5K_GAIN_CCK_PROBE_CORR               5
-#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA          15
-#define AR5K_GAIN_STEP_COUNT                   10
-#define AR5K_GAIN_PARAM_TX_CLIP                        0
-#define AR5K_GAIN_PARAM_PD_90                  1
-#define AR5K_GAIN_PARAM_PD_84                  2
-#define AR5K_GAIN_PARAM_GAIN_SEL               3
-#define AR5K_GAIN_PARAM_MIX_ORN                        0
-#define AR5K_GAIN_PARAM_PD_138                 1
-#define AR5K_GAIN_PARAM_PD_137                 2
-#define AR5K_GAIN_PARAM_PD_136                 3
-#define AR5K_GAIN_PARAM_PD_132                 4
-#define AR5K_GAIN_PARAM_PD_131                 5
-#define AR5K_GAIN_PARAM_PD_130                 6
-#define AR5K_GAIN_CHECK_ADJUST(_g)             \
-       ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
-
-struct ath5k_gain_opt_step {
-       s16                             gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
-       s32                             gos_gain;
-};
-
 struct ath5k_gain {
-       u32                     g_step_idx;
-       u32                     g_current;
-       u32                     g_target;
-       u32                     g_low;
-       u32                     g_high;
-       u32                     g_f_corr;
-       u32                     g_active;
-       const struct ath5k_gain_opt_step        *g_step;
+       u8                      g_step_idx;
+       u8                      g_current;
+       u8                      g_target;
+       u8                      g_low;
+       u8                      g_high;
+       u8                      g_f_corr;
+       u8                      g_state;
 };
 
-
 /********************\
   COMMON DEFINITIONS
 \********************/
@@ -1053,7 +1025,6 @@ struct ath5k_hw {
        bool                    ah_running;
        bool                    ah_single_chip;
        bool                    ah_combined_mic;
-       enum ath5k_rfgain       ah_rf_gain;
 
        u32                     ah_mac_srev;
        u16                     ah_mac_version;
@@ -1262,9 +1233,9 @@ extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_cha
 
 /* Initialize RF */
 extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
-extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq);
-extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah);
-extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah);
+extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
+extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
+extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
 /* PHY/RF channel functions */
 extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
 extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
index dea378f..a3f07a4 100644 (file)
@@ -331,7 +331,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
        ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
        ath5k_hw_set_opmode(ah);
 
-       ath5k_hw_set_rfgain_opt(ah);
+       ath5k_hw_rfgain_opt_init(ah);
 
        return ah;
 err_free:
index f9d486f..4b968a5 100644 (file)
@@ -2518,7 +2518,7 @@ ath5k_calibrate(unsigned long data)
                ieee80211_frequency_to_channel(sc->curchan->center_freq),
                sc->curchan->hw_value);
 
-       if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) {
+       if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
                /*
                 * Rfgain is out of bounds, reset the chip
                 * to load new gain values.
index 5021749..2543a71 100644 (file)
@@ -78,10 +78,104 @@ static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits,
        return data;
 }
 
-static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
+/**********************\
+* RF Gain optimization *
+\**********************/
+
+/*
+ * This code is used to optimize rf gain on different environments
+ * (temprature mostly) based on feedback from a power detector.
+ *
+ * It's only used on RF5111 and RF5112, later RF chips seem to have
+ * auto adjustment on hw -notice they have a much smaller BANK 7 and
+ * no gain optimization ladder-.
+ *
+ * For more infos check out this patent doc
+ * http://www.freepatentsonline.com/7400691.html
+ *
+ * This paper describes power drops as seen on the receiver due to
+ * probe packets
+ * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
+ * %20of%20Power%20Control.pdf
+ *
+ * And this is the MadWiFi bug entry related to the above
+ * http://madwifi-project.org/ticket/1659
+ * with various measurements and diagrams
+ *
+ * TODO: Deal with power drops due to probes by setting an apropriate
+ * tx power on the probe packets ! Make this part of the calibration process.
+ */
+
+/* Initialize ah_gain durring attach */
+int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
+{
+       /* Initialize the gain optimization values */
+       switch (ah->ah_radio) {
+       case AR5K_RF5111:
+               ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
+               ah->ah_gain.g_low = 20;
+               ah->ah_gain.g_high = 35;
+               ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+               break;
+       case AR5K_RF5112:
+               ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
+               ah->ah_gain.g_low = 20;
+               ah->ah_gain.g_high = 85;
+               ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Schedule a gain probe check on the next transmited packet.
+ * That means our next packet is going to be sent with lower
+ * tx power and a Peak to Average Power Detector (PAPD) will try
+ * to measure the gain.
+ *
+ * TODO: Use propper tx power setting for the probe packet so
+ * that we don't observe a serious power drop on the receiver
+ *
+ * XXX:  How about forcing a tx packet (bypassing PCU arbitrator etc)
+ * just after we enable the probe so that we don't mess with
+ * standard traffic ? Maybe it's time to use sw interrupts and
+ * a probe tasklet !!!
+ */
+static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
+{
+
+       /* Skip if gain calibration is inactive or
+        * we already handle a probe request */
+       if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
+               return;
+
+       ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
+                       AR5K_PHY_PAPD_PROBE_TXPOWER) |
+                       AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
+
+       ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
+
+}
+
+/* Calculate gain_F measurement correction
+ * based on the current step for RF5112 rev. 2 */
+static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
 {
        u32 mix, step;
        u32 *rf;
+       const struct ath5k_gain_opt *go;
+       const struct ath5k_gain_opt_step *g_step;
+
+       /* Only RF5112 Rev. 2 supports it */
+       if ((ah->ah_radio != AR5K_RF5112) ||
+       (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
+               return 0;
+
+       go = &rfgain_opt_5112;
+
+       g_step = &go->go_step[ah->ah_gain.g_step_idx];
 
        if (ah->ah_rf_banks == NULL)
                return 0;
@@ -89,11 +183,15 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
        rf = ah->ah_rf_banks;
        ah->ah_gain.g_f_corr = 0;
 
+       /* No VGA (Variable Gain Amplifier) override, skip */
        if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1)
                return 0;
 
+       /* Mix gain stepping */
        step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false);
-       mix = ah->ah_gain.g_step->gos_param[0];
+
+       /* Mix gain override */
+       mix = g_step->gos_param[0];
 
        switch (mix) {
        case 3:
@@ -113,9 +211,13 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
        return ah->ah_gain.g_f_corr;
 }
 
-static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
+/* Check if current gain_F measurement is in the range of our
+ * power detector windows. If we get a measurement outside range
+ * we know it's not accurate (detectors can't measure anything outside
+ * their detection window) so we must ignore it */
+static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
 {
-       u32 step, mix, level[4];
+       u32 step, mix_ovr, level[4];
        u32 *rf;
 
        if (ah->ah_rf_banks == NULL)
@@ -127,20 +229,20 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
                step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0,
                                false);
                level[0] = 0;
-               level[1] = (step == 0x3f) ? 0x32 : step + 4;
-               level[2] = (step != 0x3f) ? 0x40 : level[0];
-               level[3] = level[2] + 0x32;
+               level[1] = (step == 63) ? 50 : step + 4;
+               level[2] = (step != 63) ? 64 : level[0];
+               level[3] = level[2] + 50 ;
 
                ah->ah_gain.g_high = level[3] -
-                       (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
+                       (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
                ah->ah_gain.g_low = level[0] +
-                       (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
+                       (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
        } else {
-               mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0,
+               mix_ovr = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0,
                                false);
                level[0] = level[2] = 0;
 
-               if (mix == 1) {
+               if (mix_ovr == 1) {
                        level[1] = level[3] = 83;
                } else {
                        level[1] = level[3] = 107;
@@ -154,9 +256,12 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
                        ah->ah_gain.g_current <= level[3]);
 }
 
-static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah)
+/* Perform gain_F adjustment by choosing the right set
+ * of parameters from rf gain optimization ladder */
+static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
 {
        const struct ath5k_gain_opt *go;
+       const struct ath5k_gain_opt_step *g_step;
        int ret = 0;
 
        switch (ah->ah_radio) {
@@ -170,35 +275,39 @@ static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah)
                return 0;
        }
 
-       ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx];
+       g_step = &go->go_step[ah->ah_gain.g_step_idx];
 
        if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
+
+               /* Reached maximum */
                if (ah->ah_gain.g_step_idx == 0)
                        return -1;
+
                for (ah->ah_gain.g_target = ah->ah_gain.g_current;
                                ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
                                ah->ah_gain.g_step_idx > 0;
-                               ah->ah_gain.g_step =
-                                       &go->go_step[ah->ah_gain.g_step_idx])
+                               g_step = &go->go_step[ah->ah_gain.g_step_idx])
                        ah->ah_gain.g_target -= 2 *
                            (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
-                           ah->ah_gain.g_step->gos_gain);
+                           g_step->gos_gain);
 
                ret = 1;
                goto done;
        }
 
        if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
+
+               /* Reached minimum */
                if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
                        return -2;
+
                for (ah->ah_gain.g_target = ah->ah_gain.g_current;
                                ah->ah_gain.g_target <= ah->ah_gain.g_low &&
                                ah->ah_gain.g_step_idx < go->go_steps_count-1;
-                               ah->ah_gain.g_step =
-                                       &go->go_step[ah->ah_gain.g_step_idx])
+                               g_step = &go->go_step[ah->ah_gain.g_step_idx])
                        ah->ah_gain.g_target -= 2 *
                            (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
-                           ah->ah_gain.g_step->gos_gain);
+                           g_step->gos_gain);
 
                ret = 2;
                goto done;
@@ -213,6 +322,135 @@ done:
        return ret;
 }
 
+/* Main callback for thermal rf gain calibration engine
+ * Check for a new gain reading and schedule an adjustment
+ * if needed.
+ *
+ * TODO: Use sw interrupt to schedule reset if gain_F needs
+ * adjustment */
+enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
+{
+       u32 data, type;
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+
+       ATH5K_TRACE(ah->ah_sc);
+
+       if (ah->ah_rf_banks == NULL ||
+       ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
+               return AR5K_RFGAIN_INACTIVE;
+
+       /* No check requested, either engine is inactive
+        * or an adjustment is already requested */
+       if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
+               goto done;
+
+       /* Read the PAPD (Peak to Average Power Detector)
+        * register */
+       data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
+
+       /* No probe is scheduled, read gain_F measurement */
+       if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
+               ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
+               type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
+
+               /* If tx packet is CCK correct the gain_F measurement
+                * by cck ofdm gain delta */
+               if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
+                       if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
+                               ah->ah_gain.g_current +=
+                                       ee->ee_cck_ofdm_gain_delta;
+                       else
+                               ah->ah_gain.g_current +=
+                                       AR5K_GAIN_CCK_PROBE_CORR;
+               }
+
+               /* Further correct gain_F measurement for
+                * RF5112A radios */
+               if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+                       ath5k_hw_rf_gainf_corr(ah);
+                       ah->ah_gain.g_current =
+                               ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
+                               (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
+                               0;
+               }
+
+               /* Check if measurement is ok and if we need
+                * to adjust gain, schedule a gain adjustment,
+                * else switch back to the acive state */
+               if (ath5k_hw_rf_check_gainf_readback(ah) &&
+               AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
+               ath5k_hw_rf_gainf_adjust(ah)) {
+                       ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
+               } else {
+                       ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+               }
+       }
+
+done:
+       return ah->ah_gain.g_state;
+}
+
+/* Write initial rf gain table to set the RF sensitivity
+ * this one works on all RF chips and has nothing to do
+ * with gain_F calibration */
+int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
+{
+       const struct ath5k_ini_rfgain *ath5k_rfg;
+       unsigned int i, size;
+
+       switch (ah->ah_radio) {
+       case AR5K_RF5111:
+               ath5k_rfg = rfgain_5111;
+               size = ARRAY_SIZE(rfgain_5111);
+               break;
+       case AR5K_RF5112:
+               ath5k_rfg = rfgain_5112;
+               size = ARRAY_SIZE(rfgain_5112);
+               break;
+       case AR5K_RF2413:
+               ath5k_rfg = rfgain_2413;
+               size = ARRAY_SIZE(rfgain_2413);
+               break;
+       case AR5K_RF2316:
+               ath5k_rfg = rfgain_2316;
+               size = ARRAY_SIZE(rfgain_2316);
+               break;
+       case AR5K_RF5413:
+               ath5k_rfg = rfgain_5413;
+               size = ARRAY_SIZE(rfgain_5413);
+               break;
+       case AR5K_RF2317:
+       case AR5K_RF2425:
+               ath5k_rfg = rfgain_2425;
+               size = ARRAY_SIZE(rfgain_2425);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (freq) {
+       case AR5K_INI_RFGAIN_2GHZ:
+       case AR5K_INI_RFGAIN_5GHZ:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < size; i++) {
+               AR5K_REG_WAIT(i);
+               ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
+                       (u32)ath5k_rfg[i].rfg_register);
+       }
+
+       return 0;
+}
+
+
+
+/********************\
+* RF Registers setup *
+\********************/
+
 /*
  * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111
  */
@@ -311,6 +549,8 @@ static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah,
                ath5k_hw_reg_write(ah, rf[i], rfb_5111[i].rfb_ctrl_register);
        }
 
+       ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+
        return 0;
 }
 
@@ -407,6 +647,9 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah,
        for (i = 0; i < rf_size; i++)
                ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register);
 
+
+       ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+
        return 0;
 }
 
@@ -536,125 +779,12 @@ int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel,
        }
 
        ret = func(ah, channel, mode);
-       if (!ret)
-               ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE;
 
        return ret;
 }
 
-int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
-{
-       const struct ath5k_ini_rfgain *ath5k_rfg;
-       unsigned int i, size;
 
-       switch (ah->ah_radio) {
-       case AR5K_RF5111:
-               ath5k_rfg = rfgain_5111;
-               size = ARRAY_SIZE(rfgain_5111);
-               break;
-       case AR5K_RF5112:
-               ath5k_rfg = rfgain_5112;
-               size = ARRAY_SIZE(rfgain_5112);
-               break;
-       case AR5K_RF5413:
-               ath5k_rfg = rfgain_5413;
-               size = ARRAY_SIZE(rfgain_5413);
-               break;
-       case AR5K_RF2413:
-               ath5k_rfg = rfgain_2413;
-               size = ARRAY_SIZE(rfgain_2413);
-               break;
-       case AR5K_RF2425:
-               ath5k_rfg = rfgain_2425;
-               size = ARRAY_SIZE(rfgain_2425);
-               break;
-       default:
-               return -EINVAL;
-       }
 
-       switch (freq) {
-       case AR5K_INI_RFGAIN_2GHZ:
-       case AR5K_INI_RFGAIN_5GHZ:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       for (i = 0; i < size; i++) {
-               AR5K_REG_WAIT(i);
-               ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
-                       (u32)ath5k_rfg[i].rfg_register);
-       }
-
-       return 0;
-}
-
-enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah)
-{
-       u32 data, type;
-
-       ATH5K_TRACE(ah->ah_sc);
-
-       if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active ||
-                       ah->ah_version <= AR5K_AR5211)
-               return AR5K_RFGAIN_INACTIVE;
-
-       if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED)
-               goto done;
-
-       data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
-
-       if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
-               ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
-               type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
-
-               if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK)
-                       ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR;
-
-               if (ah->ah_radio >= AR5K_RF5112) {
-                       ath5k_hw_rfregs_gainf_corr(ah);
-                       ah->ah_gain.g_current =
-                               ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
-                               (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
-                               0;
-               }
-
-               if (ath5k_hw_rfregs_gain_readback(ah) &&
-                               AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
-                               ath5k_hw_rfregs_gain_adjust(ah))
-                       ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE;
-       }
-
-done:
-       return ah->ah_rf_gain;
-}
-
-int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah)
-{
-       /* Initialize the gain optimization values */
-       switch (ah->ah_radio) {
-       case AR5K_RF5111:
-               ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
-               ah->ah_gain.g_step =
-                   &rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx];
-               ah->ah_gain.g_low = 20;
-               ah->ah_gain.g_high = 35;
-               ah->ah_gain.g_active = 1;
-               break;
-       case AR5K_RF5112:
-               ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
-               ah->ah_gain.g_step =
-                   &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx];
-               ah->ah_gain.g_low = 20;
-               ah->ah_gain.g_high = 85;
-               ah->ah_gain.g_active = 1;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
 
 /**************************\
   PHY/RF channel functions
@@ -1176,13 +1306,8 @@ done:
         * as often as I/Q calibration.*/
        ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 
-       /* Request RF gain */
-       if (channel->hw_value & CHANNEL_5GHZ) {
-               ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
-                       AR5K_PHY_PAPD_PROBE_TXPOWER) |
-                       AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
-               ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED;
-       }
+       /* Initiate a gain_F calibration */
+       ath5k_hw_request_rfgain_probe(ah);
 
        return 0;
 }
index dc2d7d8..f7ce80e 100644 (file)
@@ -441,9 +441,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
        s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
 
-       if (change_channel && ah->ah_rf_banks != NULL)
-               ath5k_hw_get_rf_gain(ah);
-
 
        /*Wakeup the device*/
        ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
@@ -530,7 +527,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                 * Write initial RF gain settings
                 * This should work for both 5111/5112
                 */
-               ret = ath5k_hw_rfgain(ah, freq);
+               ret = ath5k_hw_rfgain_init(ah, freq);
                if (ret)
                        return ret;
 
index 526cf6c..28b3016 100644 (file)
@@ -111,6 +111,7 @@ enum ath5k_rf_regs_idx {
 #define        AR5K_RF5111_GAIN_I              { 6, 29,  0 }
 #define        AR5K_RF5111_PLO_SEL             { 1, 4,   0 }
 #define        AR5K_RF5111_RFGAIN_SEL          { 1, 36,  0 }
+#define AR5K_RF5111_RFGAIN_STEP                { 6, 37,  0 }
 /* Only on AR5212 BaseBand and up */
 #define        AR5K_RF5111_WAIT_S              { 5, 19,  0 }
 #define        AR5K_RF5111_WAIT_I              { 5, 24,  0 }
@@ -235,7 +236,9 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = {
 
 /* BANK 7 (Common)                     len  pos col */
 #define        AR5K_RF5112X_GAIN_I             { 6, 14,  0 }
+#define        AR5K_RF5112X_MIXVGA_OVR         { 1, 36,  0 }
 #define        AR5K_RF5112X_MIXGAIN_OVR        { 2, 37,  0 }
+#define AR5K_RF5112X_MIXGAIN_STEP      { 4, 32,  0 }
 #define        AR5K_RF5112X_PD_DELAY_A         { 4, 58,  0 }
 #define        AR5K_RF5112X_PD_DELAY_B         { 4, 62,  0 }
 #define        AR5K_RF5112X_PD_DELAY_XR        { 4, 66,  0 }
index 6dd2ea1..1354d8c 100644 (file)
@@ -441,12 +441,38 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = {
        { AR5K_RF_GAIN(63),     { 0x00000000, 0x000000f9 } },
 };
 
+#define AR5K_GAIN_CRN_FIX_BITS_5111            4
+#define AR5K_GAIN_CRN_FIX_BITS_5112            7
+#define AR5K_GAIN_CRN_MAX_FIX_BITS             AR5K_GAIN_CRN_FIX_BITS_5112
+#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN         15
+#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN         20
+#define AR5K_GAIN_CCK_PROBE_CORR               5
+#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA          15
+#define AR5K_GAIN_STEP_COUNT                   10
+
+/* Check if our current measurement is inside our
+ * current variable attenuation window */
+#define AR5K_GAIN_CHECK_ADJUST(_g)             \
+       ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
+
+struct ath5k_gain_opt_step {
+       s8                              gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
+       s8                              gos_gain;
+};
+
 struct ath5k_gain_opt {
-       u32                     go_default;
-       u32                     go_steps_count;
+       u8                              go_default;
+       u8                              go_steps_count;
        const struct ath5k_gain_opt_step        go_step[AR5K_GAIN_STEP_COUNT];
 };
 
+/*
+ * Parameters on gos_param:
+ * 1) Tx clip PHY register
+ * 2) PWD 90 RF register
+ * 3) PWD 84 RF register
+ * 4) RFGainSel RF register
+ */
 static const struct ath5k_gain_opt rfgain_opt_5111 = {
        4,
        9,
@@ -463,6 +489,16 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = {
        }
 };
 
+/*
+ * Parameters on gos_param:
+ * 1) Mixgain ovr RF register
+ * 2) PWD 138 RF register
+ * 3) PWD 137 RF register
+ * 4) PWD 136 RF register
+ * 5) PWD 132 RF register
+ * 6) PWD 131 RF register
+ * 7) PWD 130 RF register
+ */
 static const struct ath5k_gain_opt rfgain_opt_5112 = {
        1,
        8,