]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/wireless/ath/ath9k/ar9003_paprd.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / net / wireless / ath / ath9k / ar9003_paprd.c
index 716db414c258f254263a47238f45aa9fd6c2d813..356d2fd78822279245b0d4a2669a5d6aa6dd731d 100644 (file)
 
 void ar9003_paprd_enable(struct ath_hw *ah, bool val)
 {
+       struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+       struct ath9k_channel *chan = ah->curchan;
+
+       if (val) {
+               ah->paprd_table_write_done = true;
+
+               ah->eep_ops->set_txpower(ah, chan,
+                               ath9k_regd_get_ctl(regulatory, chan),
+                               chan->chan->max_antenna_gain * 2,
+                               chan->chan->max_power * 2,
+                               min((u32) MAX_RATE_POWER,
+                               (u32) regulatory->power_limit), false);
+       }
+
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
                      AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
-       REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,
-                     AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
-       REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,
-                     AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+       if (ah->caps.tx_chainmask & BIT(1))
+               REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,
+                             AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+       if (ah->caps.tx_chainmask & BIT(2))
+               REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,
+                             AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
 }
 EXPORT_SYMBOL(ar9003_paprd_enable);
 
-static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
+static int ar9003_get_training_power_2g(struct ath_hw *ah)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G;
+       unsigned int power, scale, delta;
+
+       scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), AR9300_PAPRD_SCALE_1);
+       power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
+                              AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+
+       delta = abs((int) ah->paprd_target_power - (int) power);
+       if (delta > scale)
+               return -1;
+
+       if (delta < 4)
+               power -= 4 - delta;
+
+       return power;
+}
+
+static int ar9003_get_training_power_5g(struct ath_hw *ah)
 {
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
-       struct ar9300_modal_eep_header *hdr;
-       const u32 ctrl0[3] = {
+       struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
+       struct ath9k_channel *chan = ah->curchan;
+       unsigned int power, scale, delta;
+
+       if (chan->channel >= 5700)
+               scale = MS(le32_to_cpu(hdr->papdRateMaskHt20),
+                          AR9300_PAPRD_SCALE_1);
+       else if (chan->channel >= 5400)
+               scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
+                          AR9300_PAPRD_SCALE_2);
+       else
+               scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
+                          AR9300_PAPRD_SCALE_1);
+
+       if (IS_CHAN_HT40(chan))
+               power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
+                       AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
+       else
+               power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,
+                       AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
+
+       power += scale;
+       delta = abs((int) ah->paprd_target_power - (int) power);
+       if (delta > scale)
+               return -1;
+
+       power += 2 * get_streams(common->tx_chainmask);
+       return power;
+}
+
+static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       static const u32 ctrl0[3] = {
                AR_PHY_PAPRD_CTRL0_B0,
                AR_PHY_PAPRD_CTRL0_B1,
                AR_PHY_PAPRD_CTRL0_B2
        };
-       const u32 ctrl1[3] = {
+       static const u32 ctrl1[3] = {
                AR_PHY_PAPRD_CTRL1_B0,
                AR_PHY_PAPRD_CTRL1_B1,
                AR_PHY_PAPRD_CTRL1_B2
        };
-       u32 am_mask, ht40_mask;
+       int training_power;
        int i;
 
-       if (ah->curchan && IS_CHAN_5GHZ(ah->curchan))
-               hdr = &eep->modalHeader5G;
+       if (IS_CHAN_2GHZ(ah->curchan))
+               training_power = ar9003_get_training_power_2g(ah);
        else
-               hdr = &eep->modalHeader2G;
-
-       am_mask = le32_to_cpu(hdr->papdRateMaskHt20);
-       ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40);
+               training_power = ar9003_get_training_power_5g(ah);
 
-       REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
-       REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
-       REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask);
-
-       for (i = 0; i < 3; i++) {
+       if (training_power < 0) {
+               ath_dbg(common, ATH_DBG_CALIBRATE,
+                       "PAPRD target power delta out of range");
+               return -ERANGE;
+       }
+       ah->paprd_training_power = training_power;
+       ath_dbg(common, ATH_DBG_CALIBRATE,
+               "Training power: %d, Target power: %d\n",
+               ah->paprd_training_power, ah->paprd_target_power);
+
+       REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
+                     ah->paprd_ratemask);
+       REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,
+                     ah->paprd_ratemask);
+       REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,
+                     ah->paprd_ratemask_ht40);
+
+       for (i = 0; i < ah->caps.max_txchains; i++) {
                REG_RMW_FIELD(ah, ctrl0[i],
                              AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
                REG_RMW_FIELD(ah, ctrl1[i],
@@ -102,8 +181,14 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
                      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
                      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
-       REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
-                     AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6);
+       if (AR_SREV_9485(ah))
+               REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+                             AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+                             -3);
+       else
+               REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+                             AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+                             -6);
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
                      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE,
                      -15);
@@ -132,6 +217,7 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
                      AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
                      AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
+       return 0;
 }
 
 static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
@@ -586,15 +672,10 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah,
 {
        u32 *paprd_table_val = caldata->pa_table[chain];
        u32 small_signal_gain = caldata->small_signal_gain[chain];
-       u32 training_power;
+       u32 training_power = ah->paprd_training_power;
        u32 reg = 0;
        int i;
 
-       training_power =
-           REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
-                          AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
-       training_power -= 4;
-
        if (chain == 0)
                reg = AR_PHY_PAPRD_MEM_TAB_B0;
        else if (chain == 1)
@@ -620,26 +701,22 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah,
                      AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
                      training_power);
 
-       REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,
-                     AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
-                     training_power);
+       if (ah->caps.tx_chainmask & BIT(1))
+               REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,
+                             AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+                             training_power);
 
-       REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
-                     AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
-                     training_power);
+       if (ah->caps.tx_chainmask & BIT(2))
+               REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
+                             AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+                             training_power);
 }
 EXPORT_SYMBOL(ar9003_paprd_populate_single_table);
 
 int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
 {
-
        unsigned int i, desired_gain, gain_index;
-       unsigned int train_power;
-
-       train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
-                                    AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
-
-       train_power = train_power - 4;
+       unsigned int train_power = ah->paprd_training_power;
 
        desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
 
@@ -705,7 +782,12 @@ EXPORT_SYMBOL(ar9003_paprd_create_curve);
 
 int ar9003_paprd_init_table(struct ath_hw *ah)
 {
-       ar9003_paprd_setup_single_table(ah);
+       int ret;
+
+       ret = ar9003_paprd_setup_single_table(ah);
+       if (ret < 0)
+           return ret;
+
        ar9003_paprd_get_gain_table(ah);
        return 0;
 }