summaryrefslogtreecommitdiffstats
path: root/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_paprd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/dev/ath/ath_hal/ar9300/ar9300_paprd.c')
-rw-r--r--sys/contrib/dev/ath/ath_hal/ar9300/ar9300_paprd.c2443
1 files changed, 2443 insertions, 0 deletions
diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_paprd.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_paprd.c
new file mode 100644
index 0000000..36ab31a
--- /dev/null
+++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_paprd.c
@@ -0,0 +1,2443 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "opt_ah.h"
+#include "ah.h"
+#include "ar9300.h"
+#include "ah_internal.h"
+#include "ar9300paprd.h"
+#include "ar9300reg.h"
+
+
+#if ATH_SUPPORT_PAPRD
+
+static struct ar9300_paprd_pwr_adjust ar9300_paprd_pwr_adj_array[] = {
+/* rate index , register offset , mask of register , */
+ {ALL_TARGET_HT20_5, AR_PHY_POWERTX_RATE5, AR_PHY_POWERTX_RATE5_POWERTXHT20_3,
+/* mask offset of register , offset dB*/
+ AR_PHY_POWERTX_RATE5_POWERTXHT20_3_S, 1},
+ {ALL_TARGET_HT20_6, AR_PHY_POWERTX_RATE6, AR_PHY_POWERTX_RATE6_POWERTXHT20_4,
+ AR_PHY_POWERTX_RATE6_POWERTXHT20_4_S, 2},
+ {ALL_TARGET_HT20_7, AR_PHY_POWERTX_RATE6, AR_PHY_POWERTX_RATE6_POWERTXHT20_5,
+ AR_PHY_POWERTX_RATE6_POWERTXHT20_5_S, 2},
+ {ALL_TARGET_HT40_5, AR_PHY_POWERTX_RATE7, AR_PHY_POWERTX_RATE7_POWERTXHT40_3,
+ AR_PHY_POWERTX_RATE7_POWERTXHT40_3_S, 1},
+ {ALL_TARGET_HT40_6, AR_PHY_POWERTX_RATE8, AR_PHY_POWERTX_RATE8_POWERTXHT40_4,
+ AR_PHY_POWERTX_RATE8_POWERTXHT40_4_S, 2},
+ {ALL_TARGET_HT40_7, AR_PHY_POWERTX_RATE8, AR_PHY_POWERTX_RATE8_POWERTXHT40_5,
+ AR_PHY_POWERTX_RATE8_POWERTXHT40_5_S, 2},
+ {ALL_TARGET_LEGACY_54, AR_PHY_POWERTX_RATE2, AR_PHY_POWERTX_RATE2_POWERTX54M_7,
+ AR_PHY_POWERTX_RATE2_POWERTX54M_7_S, 2},
+};
+
+HAL_BOOL create_pa_curve(u_int32_t * paprd_train_data_l,
+ u_int32_t *paprd_train_data_u, u_int32_t *pa_table, u_int32_t *g_fxp_ext,
+ int * pa_in);
+
+#define AR9300_IS_CHAN(_c, _f) (((_c)->channel_flags & _f) || 0)
+
+static int
+ar9300_paprd_setup_single_table(struct ath_hal *ah, HAL_CHANNEL * chan)
+{
+ int is_2g = AR9300_IS_CHAN(chan, CHANNEL_2GHZ);
+ struct ath_hal_9300 *ahp = AH9300(ah);
+ int is_ht40 = 0;
+ u_int32_t am_mask = 0;
+ u_int32_t val = OS_REG_READ(ah, AR_2040_MODE);
+ u_int8_t target_power_val_t2[ar9300_rate_size];
+ int power_tblindex = 0, power_delta = 0;
+ int paprd_scale_factor = 5;
+
+ const u_int8_t mask2num[8] = {
+ 0 /* 000 */,
+ 1 /* 001 */,
+ 1 /* 010 */,
+ 2 /* 011 */,
+ 1 /* 100 */,
+ 2 /* 101 */,
+ 2 /* 110 */,
+ 3 /* 111 */
+ };
+
+ ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
+
+#define ABS(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : (int)_y - (int)_x)
+
+ ar9300_set_target_power_from_eeprom(ah, chan->channel, target_power_val_t2);
+ if (val & HAL_HT_MACMODE_2040) {
+ is_ht40 = 1;
+ }
+
+ /*
+ * Note on paprd_scale_factor
+ * This factor is saved in eeprom as 3 bit fields in following fashion.
+ * In 5G there are 3 scale factors -- upper, mid and lower band.
+ * Upper band scale factor is coded in bits 25-27 of
+ * modal_header_5g.paprd_rate_mask_ht20.
+ * Mid band scale factor is coded in bits 28-30 of
+ * modal_header_5g.paprd_rate_mask_ht40.
+ * Lower band scale factor is coded in bits 25-27 of
+ * modal_header_5g.paprd_rate_mask_ht40.
+ * For 2G there is only one scale factor. It is saved in bits 25-27 of
+ * modal_header_2g.paprd_rate_mask_ht20.
+ */
+ AH_PAPRD_GET_SCALE_FACTOR(paprd_scale_factor, eep, is_2g, chan->channel);
+ if (is_2g) {
+ if (is_ht40) {
+ am_mask = ahp->ah_2g_paprd_rate_mask_ht40 & AH_PAPRD_AM_PM_MASK;
+ power_tblindex = ALL_TARGET_HT40_0_8_16;
+ } else {
+ am_mask = ahp->ah_2g_paprd_rate_mask_ht20 & AH_PAPRD_AM_PM_MASK;
+ power_tblindex = ALL_TARGET_HT20_0_8_16;
+ }
+ if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
+ if (is_ht40) {
+ ahp->paprd_training_power =
+ target_power_val_t2[ALL_TARGET_HT40_7] + 2;
+ } else {
+ ahp->paprd_training_power =
+ target_power_val_t2[ALL_TARGET_HT20_7] + 2;
+ }
+ } else if (AR_SREV_POSEIDON(ah)) {
+ ahp->paprd_training_power = 25;
+ } else {
+ ahp->paprd_training_power =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_POWERTX_RATE5,
+ AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+ if (ABS(target_power_val_t2[power_tblindex],
+ ahp->paprd_training_power) > paprd_scale_factor)
+ {
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "%s[%d]: Chan %d paprd failing EEP PWR 0x%08x"
+ "TGT PWR 0x%08x\n", __func__, __LINE__, chan->channel,
+ target_power_val_t2[power_tblindex],
+ ahp->paprd_training_power);
+ goto FAILED;
+ }
+
+ power_delta =
+ ABS(ahp->paprd_training_power,
+ target_power_val_t2[power_tblindex]);
+
+ power_delta = power_delta > 4 ? 0 : 4 - power_delta;
+ ahp->paprd_training_power =
+ ahp->paprd_training_power - power_delta;
+ }
+
+
+ } else {
+ if (is_ht40) {
+ ahp->paprd_training_power =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_POWERTX_RATE8,
+ AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
+ am_mask = ahp->ah_5g_paprd_rate_mask_ht40 & AH_PAPRD_AM_PM_MASK;
+ switch (mask2num[ahp->ah_tx_chainmask])
+ {
+ case 1:
+ power_delta = 6;
+ break;
+ case 2:
+ power_delta = 4;
+ break;
+ case 3:
+ power_delta = 2;
+ break;
+ default:
+ goto FAILED;
+ break;
+ }
+ power_tblindex = ALL_TARGET_HT40_7;
+ } else {
+ ahp->paprd_training_power =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_POWERTX_RATE6,
+ AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
+ am_mask = ahp->ah_5g_paprd_rate_mask_ht20 & AH_PAPRD_AM_PM_MASK;
+ switch (mask2num[ahp->ah_tx_chainmask])
+ {
+ case 1:
+ power_delta = 6;
+ break;
+ case 2:
+ power_delta = 4;
+ break;
+ case 3:
+ power_delta = 2;
+ break;
+ default:
+ goto FAILED;
+ break;
+ }
+ power_tblindex = ALL_TARGET_HT20_7;
+ }
+ /* Adjust for scale factor */
+ ahp->paprd_training_power += paprd_scale_factor;
+ /*
+ ath_hal_printf(ah, "%s[%d] paprd_scale_factor %d power_delta %d\n",
+ __func__, __LINE__, paprd_scale_factor, power_delta);
+ */
+ if (ABS(target_power_val_t2[power_tblindex], ahp->paprd_training_power)
+ > paprd_scale_factor)
+ {
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "%s[%d]: Chan %d paprd failing EEP PWR 0x%08x TGT PWR 0x%08x\n",
+ __func__, __LINE__, chan->channel,
+ target_power_val_t2[power_tblindex], ahp->paprd_training_power);
+ goto FAILED;
+ }
+ ahp->paprd_training_power = ahp->paprd_training_power + power_delta;
+ }
+
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s 2G %d HT40 %d am_mask 0x%08x\n",
+ __func__, is_2g, is_ht40, am_mask);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
+ am_mask);
+ if (AR_SREV_HORNET(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,
+ 0);
+ }
+ else {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,
+ am_mask);
+ }
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,
+ AR_PHY_PAPRD_HT40_MASK);
+ /* chain0 */
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN0_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B0_USE_SINGLE_TABLE_MASK, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_ADAPTIVE_AM2PM_ENABLE_0, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_ADAPTIVE_AM2AM_ENABLE_0, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_PA_GAIN_SCALE_FACT_0_MASK, 181);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_PAPRD_MAG_SCALE_FACT_0, 361);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B0_PAPRD_MAG_THRSH_0, 3);
+ }
+
+ /* chain1 */
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN1_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B1_PAPRD_ADAPTIVE_USE_SINGLE_TABLE_1, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_ADAPTIVE_AM2PM_ENABLE_1, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_ADAPTIVE_AM2AM_ENABLE_1, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_PA_GAIN_SCALE_FACT_1_MASK, 181);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_PAPRD_MAG_SCALE_FACT_1, 361);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B1_PAPRD_MAG_THRSH_1, 3);
+ }
+
+ /* chain2 */
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN2_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_B2_PAPRD_ADAPTIVE_USE_SINGLE_TABLE_2, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_ADAPTIVE_AM2PM_ENABLE_2, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_ADAPTIVE_AM2AM_ENABLE_2, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_PA_GAIN_SCALE_FACT_2_MASK, 181);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_PAPRD_MAG_SCALE_FACT_2, 361);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_B2_PAPRD_MAG_THRSH_2, 3);
+ }
+
+ ar9300_enable_paprd(ah, AH_FALSE, chan);
+ if (AR_SREV_POSEIDON(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL2_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 148);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, -15);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES, 100);
+ } else {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1);
+ if (is_2g) {
+ if(AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)){
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 0x91);
+ }else{
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147);
+ }
+ }
+ else if (AR_SREV_WASP(ah) && !is_2g) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 137);
+ } else {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147);
+ }
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
+ if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3);
+ } else {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6);
+ }
+ if (is_2g) {
+ if(AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)){
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, -10);
+ }else{
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, -15);
+ }
+ }
+ else {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, -10);
+ }
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES, 100);
+ }
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALE_0_B0_PAPRD_PRE_POST_SCALING_0_0, 261376);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALE_1_B0_PAPRD_PRE_POST_SCALING_1_0, 248079);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALE_2_B0_PAPRD_PRE_POST_SCALING_2_0, 233759);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALE_3_B0_PAPRD_PRE_POST_SCALING_3_0, 220464);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALE_4_B0_PAPRD_PRE_POST_SCALING_4_0, 208194);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALE_5_B0_PAPRD_PRE_POST_SCALING_5_0, 196949);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALE_6_B0_PAPRD_PRE_POST_SCALING_6_0, 185706);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALE_7_B0_PAPRD_PRE_POST_SCALING_7_0, 175487);
+ return 0;
+
+FAILED:
+ return -1;
+#undef ABS
+}
+
+static inline HAL_CHANNEL_INTERNAL*
+ar9300_check_chan(struct ath_hal *ah, HAL_CHANNEL *chan)
+{
+ if ((AR9300_IS_CHAN(chan, CHANNEL_2GHZ) ^
+ AR9300_IS_CHAN(chan, CHANNEL_5GHZ)) == 0)
+ {
+ HALDEBUG(ah, HAL_DEBUG_CHANNEL,
+ "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n",
+ __func__, chan->channel, chan->channel_flags);
+ return AH_NULL;
+ }
+
+ if ((AR9300_IS_CHAN(chan, CHANNEL_OFDM) ^
+ AR9300_IS_CHAN(chan, CHANNEL_CCK) ^
+ AR9300_IS_CHAN(chan, CHANNEL_HT20) ^
+ AR9300_IS_CHAN(chan, CHANNEL_HT40PLUS) ^
+ AR9300_IS_CHAN(chan, CHANNEL_HT40MINUS)) == 0)
+ {
+ HALDEBUG(ah, HAL_DEBUG_CHANNEL,
+ "%s: invalid channel %u/0x%x; not marked as "
+ "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", __func__,
+ chan->channel, chan->channel_flags);
+ return AH_NULL;
+ }
+
+ return (ath_hal_checkchannel(ah, chan));
+}
+
+void ar9300_enable_paprd(struct ath_hal *ah, HAL_BOOL enable_flag,
+ HAL_CHANNEL * chan)
+{
+ HAL_BOOL enable = enable_flag;
+ u_int32_t am_mask = 0;
+ u_int32_t val = OS_REG_READ(ah, AR_2040_MODE);
+ int is_2g = AR9300_IS_CHAN(chan, CHANNEL_2GHZ);
+ int is_ht40 = 0;
+ struct ath_hal_9300 *ahp = AH9300(ah);
+
+ if (val & HAL_HT_MACMODE_2040) {
+ is_ht40 = 1;
+ }
+ if (enable_flag == AH_TRUE) {
+ ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom;
+
+ if (!is_2g) {
+ /*
+ * 3 bits for modal_header_5g.paprd_rate_mask_ht20
+ * is used for sub band disabling of paprd.
+ * 5G band is divided into 3 sub bands -- upper, mid, lower.
+ * If bit 30 of modal_header_5g.paprd_rate_mask_ht20 is set
+ * to one -- disable paprd for upper 5G
+ * If bit 29 of modal_header_5g.paprd_rate_mask_ht20 is set
+ * to one -- disable paprd for mid 5G
+ * If bit 28 of modal_header_5g.paprd_rate_mask_ht20 is set
+ * to one -- disable paprd for lower 5G
+ * u_int32_t am_mask = eep->modal_header_5g.paprd_rate_mask_ht20;
+ */
+ if (chan->channel >= UPPER_5G_SUB_BANDSTART) {
+ if (eep->modal_header_5g.paprd_rate_mask_ht20 & (1 << 30)) {
+ enable = AH_FALSE;
+ }
+ } else if (chan->channel >= MID_5G_SUB_BANDSTART) {
+ if (eep->modal_header_5g.paprd_rate_mask_ht20 & (1 << 29)) {
+ enable = AH_FALSE;
+ }
+ } else { /* must be in the lower 5G subband */
+ if (eep->modal_header_5g.paprd_rate_mask_ht20 & (1 << 28)) {
+ enable = AH_FALSE;
+ }
+ }
+ }
+
+ if (ahp->ah_paprd_broken) {
+ ahp->ah_paprd_broken = AH_FALSE;
+ enable = AH_FALSE;
+
+ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
+ "%s: PAPRD is in bad state. Don't enable PAPRD\n",
+ __func__);
+ }
+ }
+ if (enable) {
+ HAL_CHANNEL_INTERNAL *ichan;
+ if (is_2g) {
+ if (is_ht40) {
+ am_mask = ahp->ah_2g_paprd_rate_mask_ht40 & AH_PAPRD_AM_PM_MASK;
+ } else {
+ am_mask = ahp->ah_2g_paprd_rate_mask_ht20 & AH_PAPRD_AM_PM_MASK;
+ }
+ } else {
+ if (is_ht40) {
+ am_mask = ahp->ah_5g_paprd_rate_mask_ht40 & AH_PAPRD_AM_PM_MASK;
+ } else {
+ am_mask = ahp->ah_5g_paprd_rate_mask_ht20 & AH_PAPRD_AM_PM_MASK;
+ }
+ }
+ /* Earlier we promgrammed TGT Power with Scaled down value, since
+ * PAPRD CAL was not done.
+ * Now we finish PAPRD CAL, so bump up the TGT PWR to original
+ * EEPROM Power. CTLs calc and Maverickd in
+ * "ar9300_eeprom_set_transmit_power"
+ */
+ ichan = ar9300_check_chan(ah, chan);
+ ichan->paprd_table_write_done = 1;
+ chan->paprd_table_write_done = 1;
+ /*
+ ath_hal_printf(ah, "%s[%d] eeprom_set_transmit_power PAPRD\n",
+ __func__, __LINE__);
+ */
+ if (ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, ichan,
+ ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan),
+ ath_hal_get_twice_max_regpower(AH_PRIVATE(ah), ichan, chan),
+ AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_power_limit)) != HAL_OK) {
+ ichan->paprd_table_write_done = 0;
+ chan->paprd_table_write_done = 0;
+ /* Intentional print */
+ ath_hal_printf(ah,
+ "%s[%d] eeprom_set_transmit_power failed ABORT PAPRD\n",
+ __func__, __LINE__);
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B0_PAPRD_ENABLE_0, 0);
+ if (!AR_SREV_POSEIDON(ah) && !AR_SREV_HORNET(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B1_PAPRD_ENABLE_1, 0);
+ if (!AR_SREV_JUPITER(ah) || (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN2_MASK)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_B2_PAPRD_ENABLE_2, 0);
+
+ }
+ }
+ return;
+ }
+
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s 2G %d HT40 %d am_mask 0x%08x\n",
+ __func__, is_2g, is_ht40, am_mask);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
+ am_mask);
+ if (AR_SREV_HORNET(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah,
+ AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, 0);
+ } else {
+ OS_REG_RMW_FIELD_ALT(ah,
+ AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
+ }
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,
+ AR_PHY_PAPRD_HT40_MASK);
+ /* chain0 */
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN0_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B0_USE_SINGLE_TABLE_MASK, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_ADAPTIVE_AM2PM_ENABLE_0, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_ADAPTIVE_AM2AM_ENABLE_0, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_PA_GAIN_SCALE_FACT_0_MASK, 181);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_PAPRD_MAG_SCALE_FACT_0, 361);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B0_PAPRD_MAG_THRSH_0, 3);
+ }
+ /* chain1 */
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN1_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B1_PAPRD_ADAPTIVE_USE_SINGLE_TABLE_1, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_ADAPTIVE_AM2PM_ENABLE_1, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_ADAPTIVE_AM2AM_ENABLE_1, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_PA_GAIN_SCALE_FACT_1_MASK, 181);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_PAPRD_MAG_SCALE_FACT_1, 361);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B1_PAPRD_MAG_THRSH_1, 3);
+ }
+ /* chain2 */
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN2_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_B2_PAPRD_ADAPTIVE_USE_SINGLE_TABLE_2, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_ADAPTIVE_AM2PM_ENABLE_2, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_ADAPTIVE_AM2AM_ENABLE_2, 1);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_PA_GAIN_SCALE_FACT_2_MASK, 181);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_PAPRD_MAG_SCALE_FACT_2, 361);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_ADAPTIVE_SCALING_ENA, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_B2_PAPRD_MAG_THRSH_2, 3);
+ }
+
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN0_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B0_PAPRD_ENABLE_0, 1);
+ }
+
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN1_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B1_PAPRD_ENABLE_1, 1);
+ }
+
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN2_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_B2_PAPRD_ENABLE_2, 1);
+ }
+
+ } else {
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN0_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B0_PAPRD_ENABLE_0, 0);
+ }
+
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN1_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B1_PAPRD_ENABLE_1, 0);
+ }
+
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN2_MASK) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_B2_PAPRD_ENABLE_2, 0);
+ }
+ }
+}
+
+static void ar9300_gain_table_entries(struct ath_hal *ah)
+{
+ int i;
+ u_int32_t reg;
+ u_int32_t *gain_table_entries = AH9300(ah)->paprd_gain_table_entries;
+ u_int32_t *gain_vs_table_index = AH9300(ah)->paprd_gain_table_index;
+
+ reg = AR_PHY_TXGAIN_TAB(1);
+
+ for (i = 0; i < 32; i++) {
+ gain_table_entries[i] = OS_REG_READ(ah, reg);
+ gain_vs_table_index[i] = (gain_table_entries[i] >> 24) & 0xff;
+ /*
+ * ath_hal_printf(
+ * ah, "+++reg 0x%08x gain_table_entries[%d] = 0x%08x \n",
+ * reg, i, gain_table_entries[i]);
+ */
+ reg = reg + 4;
+ }
+}
+
+/* Get gain index for Target power */
+static unsigned int ar9300_get_desired_gain_for_chain(struct ath_hal *ah,
+ int chain_num, int target_power)
+{
+ int olpc_gain_delta = 0;
+ int alpha_therm = 0, alpha_volt = 0;
+ int therm_cal_value = 0, volt_cal_value = 0;
+ int latest_therm_value = 0, latest_volt_value = 0, olpc_gain_delta_tmp = 0;
+ int thermal_gain_corr = 0, voltage_gain_corr = 0, desired_scale = 0;
+ int desired_gain = 0;
+ int cl_gain_mod = 0;
+
+ /* Clear the training done bit */
+ if (AR_SREV_POSEIDON(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE, 0);
+ } else {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE, 0);
+ }
+ /*field_read("BB_tpc_12.desired_scale_ht40_5", &desired_scale);*/
+ desired_scale =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_12,
+ AR_PHY_TPC_12_DESIRED_SCALE_HT40_5);
+ /*field_read("BB_tpc_19.alpha_therm", &alpha_therm);*/
+ alpha_therm =
+ OS_REG_READ_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM);
+ /*field_read("BB_tpc_19.alpha_volt", &alpha_volt);*/
+ alpha_volt =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALT_ALPHA_VOLT);
+
+ /*field_read("BB_tpc_18.therm_cal_value", &therm_cal_value);*/
+ therm_cal_value =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_18,
+ AR_PHY_TPC_18_ALT_THERM_CAL_VALUE);
+ /*field_read("BB_tpc_18.volt_cal_value", &volt_cal_value);*/
+ volt_cal_value =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_18,
+ AR_PHY_TPC_18_ALT_VOLT_CAL_VALUE);
+
+ /*field_read("BB_therm_adc_4.latest_therm_value", &latest_therm_value);*/
+ latest_therm_value =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_THERM_ADC_4,
+ AR_PHY_THERM_ADC_4_LATEST_THERM_VALUE);
+ /*field_read("BB_therm_adc_4.latest_volt_value", &latest_volt_value);*/
+ latest_volt_value =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_THERM_ADC_4,
+ AR_PHY_THERM_ADC_4_LATEST_VOLT_VALUE);
+
+ /*
+ * sprintf(
+ * field_name, "%s%d%s%d\0", "BB_tpc_11_b",
+ * chain_num, ".olpc_gain_delta_", chain_num);
+ */
+ /*field_read(field_name, &olpc_gain_delta_tmp);*/
+
+
+ if (chain_num == 0) {
+ olpc_gain_delta_tmp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_11_B0,
+ AR_PHY_TPC_11_B0_OLPC_GAIN_DELTA_0);
+ cl_gain_mod = OS_REG_READ_FIELD_ALT(ah, AR_PHY_CL_TAB_0,
+ AR_PHY_CL_TAB_0_CL_GAIN_MOD);
+ } else if (chain_num == 1) {
+ if (!AR_SREV_POSEIDON(ah)) {
+ olpc_gain_delta_tmp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_11_B1,
+ AR_PHY_TPC_11_B1_OLPC_GAIN_DELTA_1);
+ cl_gain_mod = OS_REG_READ_FIELD_ALT(ah, AR_PHY_CL_TAB_1,
+ AR_PHY_CL_TAB_1_CL_GAIN_MOD);
+ }
+ } else if (chain_num == 2) {
+ if (!AR_SREV_POSEIDON(ah)) {
+ olpc_gain_delta_tmp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_11_B2,
+ AR_PHY_TPC_11_B2_OLPC_GAIN_DELTA_2);
+ cl_gain_mod = OS_REG_READ_FIELD_ALT(ah, AR_PHY_CL_TAB_2,
+ AR_PHY_CL_TAB_2_CL_GAIN_MOD);
+ }
+ } else {
+ /* invalid chain_num */
+ }
+
+ if (olpc_gain_delta_tmp < 128) {
+ olpc_gain_delta = olpc_gain_delta_tmp;
+ } else {
+ olpc_gain_delta = olpc_gain_delta_tmp - 256;
+ }
+
+ thermal_gain_corr =
+ (int) (alpha_therm * (latest_therm_value - therm_cal_value) +
+ 128) >> 8;
+ voltage_gain_corr =
+ (int) (alpha_volt * (latest_volt_value - volt_cal_value) + 64) >> 7;
+ desired_gain =
+ target_power - olpc_gain_delta - thermal_gain_corr -
+ voltage_gain_corr + desired_scale + cl_gain_mod;
+ /*
+ * printf(
+ * "olpc_gain_delta %d, desired_gain %d\n",
+ * olpc_gain_delta, desired_gain);
+ */
+#if 0
+ ath_hal_printf(ah,
+ "+++ target_power %d olpc_gain_delta %d, cl_gain_mod %d,"
+ "thermal_gain_corr %d voltage_gain_corr %d desired_scale %d"
+ "desired_gain %d\n",
+ target_power, olpc_gain_delta, cl_gain_mod, thermal_gain_corr,
+ voltage_gain_corr,
+ desired_scale, desired_gain);
+#endif
+ return (unsigned int) desired_gain;
+}
+
+static void ar9300_tx_force_gain(struct ath_hal *ah, unsigned int gain_index)
+{
+ int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain;
+ int padrvgn_a, padrvgn_b, padrvgn_c, padrvgn_d;
+ u_int32_t *gain_table_entries = AH9300(ah)->paprd_gain_table_entries;
+
+ /*u_int32_t *gain_vs_table_index = ah->paprd_gain_table_index;*/
+ selected_gain_entry = gain_table_entries[gain_index];
+ txbb1dbgain = selected_gain_entry & 0x7;
+ txbb6dbgain = (selected_gain_entry >> 3) & 0x3;
+ txmxrgain = (selected_gain_entry >> 5) & 0xf;
+ padrvgn_a = (selected_gain_entry >> 9) & 0xf;
+ padrvgn_b = (selected_gain_entry >> 13) & 0xf;
+ padrvgn_c = (selected_gain_entry >> 17) & 0xf;
+ padrvgn_d = (selected_gain_entry >> 21) & 0x3;
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgn_a);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgn_b);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgn_c);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgn_d);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0);
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0);
+}
+
+#define HAL_DEBUG_PAPRD HAL_DEBUG_CALIBRATE /* driver: conditionally print */
+
+#if defined(ART_PAPRD_DEBUG) || defined(AH_DEBUG)
+static void ar9300_paprd_debug_print(struct ath_hal *ah)
+{
+ int temp;
+ int txbb1dbgain, txbb6dbgain, txmxrgain;
+ int padrvgn_a, padrvgn_b, padrvgn_c, padrvgn_d;
+
+ if (AR_SREV_POSEIDON(ah)) {
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_lb_skip", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_lb_skip=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_lb_enable", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_lb_enable=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_tx_gain_force", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_tx_gain_force=0x%x\n", temp);
+ /*
+ * field_read(
+ * "BB_paprd_trainer_cntl1.cf_paprd_rx_bb_gain_force", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_rx_bb_gain_force=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_iqcorr_enable", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_iqcorr_enable=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_agc2_settling", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_agc2_settling=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_train_enable", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_train_enable=0x%x\n", temp);
+ /*
+ * field_read("BB_paprd_trainer_cntl2.cf_paprd_init_rx_bb_gain", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL2_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl2.cf_paprd_init_rx_bb_gain=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl3.cf_paprd_fine_corr_len", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_fine_corr_len=0x%x\n", temp);
+ /*
+ * field_read("BB_paprd_trainer_cntl3.cf_paprd_coarse_corr_len", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_coarse_corr_len=0x%x\n", temp);
+ /*
+ * field_read("BB_paprd_trainer_cntl3.cf_paprd_num_corr_stages", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_num_corr_stages=0x%x\n", temp);
+ /*
+ * field_read(
+ * "BB_paprd_trainer_cntl3.cf_paprd_min_loopback_del", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_min_loopback_del=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl3.cf_paprd_quick_drop", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_quick_drop=0x%x\n", temp);
+ /*
+ * field_read(
+ * "BB_paprd_trainer_cntl3.cf_paprd_adc_desired_size", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_adc_desired_size=0x%x\n", temp);
+ /*
+ * field_read("BB_paprd_trainer_cntl3.cf_paprd_bbtxmix_disable", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_bbtxmix_disable=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl4.cf_paprd_safety_delta", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl4.cf_paprd_safety_delta=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl4.cf_paprd_min_corr", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl4.cf_paprd_min_corr=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_agc2_pwr", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_agc2_pwr = 0x%02x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_rx_gain_idx", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_RX_GAIN_IDX);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_rx_gain_idx = 0x%02x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_train_active", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_ACTIVE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_train_active = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_corr_err", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_CORR_ERR);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_corr_err = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_train_incomplete", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_train_incomplete = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_train_done", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_train_done = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat2.paprd_fine_idx", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT2_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_fine_idx = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat2.paprd_coarse_idx", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT2_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_coarse_idx = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat2.paprd_fine_val", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT2_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_fine_val = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat3.paprd_train_samples_cnt", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_train_samples_cnt = 0x%08x\n", temp);
+ } else {
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_lb_skip", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_lb_skip=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_lb_enable", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_lb_enable=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_tx_gain_force", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_tx_gain_force=0x%x\n", temp);
+ /*
+ * field_read(
+ * "BB_paprd_trainer_cntl1.cf_paprd_rx_bb_gain_force", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_rx_bb_gain_force=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_iqcorr_enable", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_iqcorr_enable=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_agc2_settling", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_agc2_settling=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl1.cf_paprd_train_enable", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl1.cf_paprd_train_enable=0x%x\n", temp);
+ /*
+ * field_read("BB_paprd_trainer_cntl2.cf_paprd_init_rx_bb_gain", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl2.cf_paprd_init_rx_bb_gain=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl3.cf_paprd_fine_corr_len", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_fine_corr_len=0x%x\n", temp);
+ /*
+ * field_read("BB_paprd_trainer_cntl3.cf_paprd_coarse_corr_len", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_coarse_corr_len=0x%x\n", temp);
+ /*
+ * field_read("BB_paprd_trainer_cntl3.cf_paprd_num_corr_stages", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_num_corr_stages=0x%x\n", temp);
+ /*
+ * field_read(
+ * "BB_paprd_trainer_cntl3.cf_paprd_min_loopback_del", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_min_loopback_del=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl3.cf_paprd_quick_drop", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_quick_drop=0x%x\n", temp);
+ /*
+ * field_read(
+ * "BB_paprd_trainer_cntl3.cf_paprd_adc_desired_size", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_adc_desired_size=0x%x\n", temp);
+ /*
+ * field_read(
+ * "BB_paprd_trainer_cntl3.cf_paprd_bbtxmix_disable", &temp);
+ */
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl3.cf_paprd_bbtxmix_disable=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl4.cf_paprd_safety_delta", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl4.cf_paprd_safety_delta=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_cntl4.cf_paprd_min_corr", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "BB_paprd_trainer_cntl4.cf_paprd_min_corr=0x%x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_agc2_pwr", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_agc2_pwr = 0x%02x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_rx_gain_idx", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_RX_GAIN_IDX);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_rx_gain_idx = 0x%02x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_train_active", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_ACTIVE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_train_active = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_corr_err", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_CORR_ERR);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_corr_err = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_train_incomplete", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_train_incomplete = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat1.paprd_train_done", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_train_done = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat2.paprd_fine_idx", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT2,
+ AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_fine_idx = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat2.paprd_coarse_idx", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT2,
+ AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_coarse_idx = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat2.paprd_fine_val", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT2,
+ AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_fine_val = 0x%08x\n", temp);
+ /*field_read("BB_paprd_trainer_stat3.paprd_train_samples_cnt", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT3,
+ AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " paprd_train_samples_cnt = 0x%08x\n", temp);
+ }
+
+ /*field_read("BB_tpc_1.force_dac_gain", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD, " dac_gain_forced = 0x%08x\n",
+ temp);
+ /*field_read("BB_tpc_1.forced_dac_gain", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD, " forced_dac_gain = 0x%08x\n",
+ temp);
+
+ /*field_read("BB_paprd_ctrl0_b0.paprd_enable_0", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B0_PAPRD_ENABLE_0);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " BB_paprd_ctrl0_b0.paprd_enable_0 = 0x%08x\n", temp);
+ if (!AR_SREV_POSEIDON(ah)) {
+ /*field_read("BB_paprd_ctrl0_b1.paprd_enable_1", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B1_PAPRD_ENABLE_1);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " BB_paprd_ctrl0_b1.paprd_enable_1 = 0x%08x\n", temp);
+ if (AH9300(ah)->ah_tx_chainmask & AR9300_CHAIN2_MASK) {
+ /*field_read("BB_paprd_ctrl0_b2.paprd_enable_2", &temp);*/
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_B2_PAPRD_ENABLE_2);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ " BB_paprd_ctrl0_b2.paprd_enable_2 = 0x%08x\n", temp);
+ }
+ }
+
+ /*field_read("BB_tx_forced_gain.forced_txbb1dbgain", &txbb1dbgain);*/
+ txbb1dbgain =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN);
+ /*field_read("BB_tx_forced_gain.forced_txbb6dbgain", &txbb6dbgain);*/
+ txbb6dbgain =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN);
+ /*field_read("BB_tx_forced_gain.forced_txmxrgain", &txmxrgain);*/
+ txmxrgain =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN);
+ /*field_read("BB_tx_forced_gain.forced_padrvgn_a", &padrvgn_a);*/
+ padrvgn_a =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA);
+ /*field_read("BB_tx_forced_gain.forced_padrvgn_b", &padrvgn_b);*/
+ padrvgn_b =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB);
+ /*field_read("BB_tx_forced_gain.forced_padrvgn_c", &padrvgn_c);*/
+ padrvgn_c =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC);
+ /*field_read("BB_tx_forced_gain.forced_padrvgn_d", &padrvgn_d);*/
+ padrvgn_d =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND);
+
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "txbb1dbgain=0x%x, txbb6dbgain=0x%x, txmxrgain=0x%x\n",
+ txbb1dbgain, txbb6dbgain, txmxrgain);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "padrvgn_a=0x%x, padrvgn_b=0x%x\n", padrvgn_a, padrvgn_b);
+ HALDEBUG(ah, HAL_DEBUG_PAPRD,
+ "padrvgn_c=0x%x, padrvgn_d=0x%x\n", padrvgn_c, padrvgn_d);
+}
+#else
+#define ar9300_paprd_debug_print(ah) /* dummy macro */
+#endif /* defined(ART_PAPRD_DEBUG) || defined(AH_DEBUG) */
+
+static int ar9300_create_pa_curve(struct ath_hal *ah, u_int32_t * pa_table,
+ u_int32_t * small_signal_gain, int * pa_in)
+{
+ int i;
+ int status;
+ /*char field_name[100];*/
+ u_int32_t paprd_train_data_l[48], paprd_train_data_u[48];
+ u_int32_t reg;
+
+ ar9300_paprd_debug_print(ah);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_CHAN_INFO_MEMORY,
+ AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ, 0);
+ reg = AR_PHY_CHAN_INFO_TAB_0;
+
+ for (i = 0; i < 48; i++) {
+ /*
+ * sprintf(
+ * field_name, "%s%d%s\0", "BB_chan_info_chan_tab_b0[",
+ * i, "].chaninfo_word");
+ */
+ /*field_read(field_name, &paprd_train_data_l[i]);*/
+ paprd_train_data_l[i] = OS_REG_READ(ah, reg);
+ reg = reg + 4;
+ }
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_CHAN_INFO_MEMORY,
+ AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ, 1);
+ reg = AR_PHY_CHAN_INFO_TAB_0;
+
+ for (i = 0; i < 48; i++) {
+ /*
+ * sprintf(
+ * field_name, "%s%d%s\0", "BB_chan_info_chan_tab_b0[",
+ * i, "].chaninfo_word");
+ */
+ /*field_read(field_name, &paprd_train_data_u[i]);*/
+ paprd_train_data_u[i] = OS_REG_READ(ah, reg);
+ reg = reg + 4;
+ }
+
+ /*
+ * for(i=0; i<48; i++)
+ * ath_hal_printf(
+ * ah, "%08x%08x\n", paprd_train_data_u[i], paprd_train_data_l[i]);
+ */
+ status = 0;
+ if (create_pa_curve(
+ paprd_train_data_l, paprd_train_data_u,
+ pa_table, small_signal_gain, pa_in) ==
+ AH_FALSE)
+ {
+ status = -2;
+ }
+ /* Clear the training done bit */
+ if (AR_SREV_POSEIDON(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE, 0);
+ } else {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE, 0);
+ }
+ return status;
+}
+
+static int find_expn(int num)
+{
+ int tmp, exp;
+
+ exp = 0;
+ tmp = num >> 1;
+
+ while (tmp != 0) {
+ tmp = tmp >> 1;
+ exp++;
+ }
+
+ return exp;
+}
+
+static int find_proper_scale(int expn, int n)
+{
+ int q_pw;
+
+ q_pw = (expn > n) ? expn - 10 : 0;
+ return q_pw;
+}
+
+static int find_max(int *array, int length)
+{
+ int i, loc_max;
+
+ loc_max = 0;
+
+ for (i = 0; i < length; i++) {
+ if (array[i] > loc_max) {
+ loc_max = array[i];
+ }
+ }
+
+ return loc_max;
+}
+
+static int paprd_abs(int num)
+{
+ if (num < 0) {
+ return -num;
+ }
+ return num;
+}
+
+#define NUM_BIN 23
+
+HAL_BOOL create_pa_curve(u_int32_t * paprd_train_data_l,
+ u_int32_t * paprd_train_data_u, u_int32_t * pa_table,
+ u_int32_t * g_fxp_ext, int *pa_in)
+{
+ unsigned int accum_cnt[NUM_BIN + 1];
+ unsigned int accum_tx[NUM_BIN + 1];
+ unsigned int accum_rx[NUM_BIN + 1];
+ unsigned int accum_ang[NUM_BIN + 1];
+ unsigned int thresh_accum_cnt;
+
+ int max_index;
+ int scale_factor;
+
+ int x_est[NUM_BIN + 1];
+ int y[NUM_BIN + 1];
+ int theta[NUM_BIN + 1];
+ int y_sqr[NUM_BIN + 1];
+ int y_quad[NUM_BIN + 1];
+ int theta_tilde[NUM_BIN + 1];
+ int pa_angle[NUM_BIN + 1];
+
+ int b1_tmp[NUM_BIN + 1];
+ int b2_tmp[NUM_BIN + 1];
+ int b1_abs[NUM_BIN + 1];
+ int b2_abs[NUM_BIN + 1];
+
+ int y_lin[NUM_BIN + 1];
+ int y_est[NUM_BIN + 1];
+ int x_est_fxp1_nonlin[NUM_BIN + 1];
+ int x_tilde[NUM_BIN + 1];
+ int x_tilde_abs[NUM_BIN + 1];
+
+ int g_fxp;
+ int y_intercept;
+ int order_x_by_y;
+ int m, half_lo, half_hi;
+ int sum_y_sqr;
+ int sum_y_quad;
+ int q_x, q_b1, q_b2;
+ int beta_raw, alpha_raw, scale_b;
+ int q_scale_b, q_beta, q_alpha;
+ int alpha, beta;
+ int order_1, order_2;
+ int order1_5x, order2_3x;
+ int order1_5x_rem, order2_3x_rem;
+ int y5, y3, tmp;
+ int bin, idx;
+ int theta_low_bin = 0;
+
+ /*
+ * [15:00] u16, accum_cnt[15:00]: number of samples in the bin
+ * [42:16] u27, accum_tx[26:00]: sum(tx amplitude) of the bin
+ * [63:43] u21, accum_rx[20:00]:
+ * sum(rx amplitude distance to lower bin edge) of the bin
+ * [90:64] s27, accum_ang[26:00]: sum(angles) of the bin
+ */
+ max_index = 0;
+ /*
+ * Disregard any bin that contains less than
+ * or equal to 16 counts of samples
+ */
+ thresh_accum_cnt = 16;
+ scale_factor = 5;
+
+ for (bin = 0; bin < NUM_BIN; bin++) {
+ accum_cnt[bin] = paprd_train_data_l[bin] & 0xffff;
+ /* lower 16 bit OR-ed upper 11 bits */
+ accum_tx[bin] =
+ ((paprd_train_data_l[bin] >> 16) & 0xffff) |
+ ((paprd_train_data_u[bin] & 0x7ff) << 16);
+ accum_rx[bin] =
+ ((paprd_train_data_u[bin] >> 11) & 0x1f) |
+ ((paprd_train_data_l[bin + 23] & 0xffff) << 5);
+ accum_ang[bin] =
+ ((paprd_train_data_l[bin + 23] >> 16) & 0xffff) |
+ ((paprd_train_data_u[bin + 23] & 0x7ff) << 16);
+ /*
+ * printf(
+ * "%d\t%d\t%d\t%d\n", accum_cnt[bin], accum_tx[bin],
+ * accum_rx[bin], accum_ang[bin]);
+ */
+ if (accum_cnt[bin] > thresh_accum_cnt) {
+ /* accum_cnt[i] will be non-zero at this point */
+ x_est[bin + 1] =
+ ((((accum_tx[bin] << scale_factor) +
+ accum_cnt[bin]) / accum_cnt[bin]) + 32) >> scale_factor;
+ y[bin + 1] =
+ (((((accum_rx[bin] << scale_factor) +
+ accum_cnt[bin]) / accum_cnt[bin]) + 32) >> scale_factor) +
+ (1 << scale_factor) * max_index + 16;
+ if (accum_ang[bin] >= (1 << 26)) {
+ theta[bin + 1] =
+ ((accum_ang[bin] - (1 << 27)) * (1 << scale_factor) +
+ accum_cnt[bin]);
+ theta[bin + 1] = theta[bin + 1] / (int) accum_cnt[bin];
+ /*
+ * theta[i+1] =
+ * ((accum_ang[i] - (1 << 27)) *
+ * (1 << scale_factor) + zz) / zz;
+ */
+ } else {
+ theta[bin + 1] =
+ ((accum_ang[bin] * (1 << scale_factor)) +
+ accum_cnt[bin]) / accum_cnt[bin];
+ }
+ max_index++;
+ }
+ /*
+ * printf(
+ * "i=%d, theta[i+1]=%d\t%d\t%d\t%d\t%d\n",
+ * i, theta[i+1], accum_cnt[i],
+ * accum_tx[i], accum_rx[i], accum_ang[i]);
+ */
+ }
+
+ /*
+ * Find average theta of first 5 bin and all of those to same value.
+ * Curve is linear at that range.
+ */
+ for (bin = 1; bin < 6; bin++) {
+ theta_low_bin += theta[bin];
+ }
+ theta_low_bin = theta_low_bin / 5;
+ for (bin = 1; bin < 6; bin++) {
+ theta[bin] = theta_low_bin;
+ }
+
+ /* Set values at origin */
+ theta[0] = theta_low_bin;
+
+ for (bin = 0; bin <= max_index; bin++) {
+ theta[bin] = theta[bin] - theta_low_bin;
+ /*printf("bin=%d, theta[bin] = %d\n", bin, theta[bin]);*/
+ }
+
+ x_est[0] = 0;
+ y[0] = 0;
+ scale_factor = 8;
+ /* low signal gain */
+ if (x_est[6] == x_est[3]) {
+ return AH_FALSE;
+ }
+ g_fxp =
+ (((y[6] - y[3]) * 1 << scale_factor) + (x_est[6] - x_est[3])) /
+ (x_est[6] - x_est[3]);
+ if (g_fxp == 0) {
+ /*
+ * ath_hal_printf(
+ * NULL, "%s[%d] Potential divide by zero error\n",
+ * __func__, __LINE__);
+ */
+ return AH_FALSE;
+ }
+
+ for (bin = 0; bin <= max_index; bin++) {
+ y_lin[bin] =
+ (g_fxp * (x_est[bin] - x_est[3]) + (1 << scale_factor)) /
+ (1 << scale_factor) + y[3];
+ }
+ y_intercept = y_lin[0];
+
+ for (bin = 0; bin <= max_index; bin++) {
+ y_est[bin] = y[bin] - y_intercept;
+ y_lin[bin] = y_lin[bin] - y_intercept;
+ }
+
+ for (bin = 0; bin <= 3; bin++) {
+ y_est[bin] = bin * 32;
+ /* g_fxp was checked for zero already */
+ x_est[bin] = ((y_est[bin] * 1 << scale_factor) + g_fxp) / g_fxp;
+ }
+
+ /*
+ * for (bin = 0; bin <= max_index; bin++) {
+ * printf("y_est[%d] = %d, x_est[%d]=%d\n",
+ * bin, y_est[bin], bin, x_est[bin]);
+ * }
+ */
+ for (bin = 0; bin <= max_index; bin++) {
+ x_est_fxp1_nonlin[bin] =
+ x_est[bin] - ((1 << scale_factor) * y_est[bin] + g_fxp) / g_fxp;
+ /*printf("x_est_fxp1_nonlin[%d] = %d\n", bin, x_est_fxp1_nonlin[bin]);*/
+ }
+
+ /* Check for divide by 0 */
+ if (y_est[max_index] == 0) {
+ return AH_FALSE;
+ }
+ order_x_by_y =
+ (x_est_fxp1_nonlin[max_index] + y_est[max_index]) / y_est[max_index];
+ if (order_x_by_y == 0) {
+ m = 10;
+ } else if (order_x_by_y == 1) {
+ m = 9;
+ } else {
+ m = 8;
+ }
+
+ half_lo = (max_index > 15) ? 7 : max_index >> 1;
+ half_hi = max_index - half_lo;
+ scale_factor = 8;
+ sum_y_sqr = 0;
+ sum_y_quad = 0;
+
+ for (bin = 0; bin <= half_hi; bin++) {
+ if (y_est[bin + half_lo] == 0) {
+ /*
+ * ath_hal_printf(
+ * NULL, "%s Potential divide by zero error\n", __func__);
+ */
+ return AH_FALSE;
+ }
+
+ x_tilde[bin] =
+ (x_est_fxp1_nonlin[bin + half_lo] * (1 << m) +
+ y_est[bin + half_lo]) / y_est[bin + half_lo];
+ x_tilde[bin] = (x_tilde[bin] * (1 << m) + y_est[bin + half_lo]) /
+ y_est[bin + half_lo];
+ x_tilde[bin] = (x_tilde[bin] * (1 << m) + y_est[bin + half_lo]) /
+ y_est[bin + half_lo];
+
+ y_sqr[bin] =
+ (y_est[bin + half_lo] * y_est[bin + half_lo] +
+ (scale_factor * scale_factor)) / (scale_factor * scale_factor);
+ x_tilde_abs[bin] = paprd_abs(x_tilde[bin]);
+ y_quad[bin] = y_sqr[bin] * y_sqr[bin];
+ sum_y_sqr = sum_y_sqr + y_sqr[bin];
+ sum_y_quad = sum_y_quad + y_quad[bin];
+ }
+
+ /*printf("sum_y_sqr = %d, sum_y_quad=%d\n", sum_y_sqr, sum_y_quad);*/
+
+ for (bin = 0; bin <= half_hi; bin++) {
+ b1_tmp[bin] = y_sqr[bin] * (half_hi + 1) - sum_y_sqr;
+ b2_tmp[bin] = sum_y_quad - sum_y_sqr * y_sqr[bin];
+ b1_abs[bin] = paprd_abs(b1_tmp[bin]);
+ b2_abs[bin] = paprd_abs(b2_tmp[bin]);
+
+ /*
+ * printf(
+ * "bin=%d, b1_tmp[bin] = %d, b2_tmp[bin] = %d\n",
+ * bin, b1_tmp[bin], b2_tmp[bin]);
+ */
+ }
+
+ q_x = find_proper_scale(find_expn(find_max(x_tilde_abs, half_hi + 1)), 10);
+ q_b1 = find_proper_scale(find_expn(find_max(b1_abs, half_hi + 1)), 10);
+ q_b2 = find_proper_scale(find_expn(find_max(b2_abs, half_hi + 1)), 10);
+
+ beta_raw = 0;
+ alpha_raw = 0;
+
+ for (bin = 0; bin <= half_hi; bin++) {
+ x_tilde[bin] = x_tilde[bin] / (1 << q_x);
+ b1_tmp[bin] = b1_tmp[bin] / (1 << q_b1);
+ b2_tmp[bin] = b2_tmp[bin] / (1 << q_b2);
+
+ /*
+ * printf(
+ * "bin=%d, b1_tmp[bin]=%d b2_tmp[bin]=%d x_tilde[bin] = %d\n",
+ * bin, b1_tmp[bin], b2_tmp[bin], x_tilde[bin]);
+ */
+ beta_raw = beta_raw + b1_tmp[bin] * x_tilde[bin];
+ alpha_raw = alpha_raw + b2_tmp[bin] * x_tilde[bin];
+ }
+
+ scale_b =
+ ((sum_y_quad / scale_factor) * (half_hi + 1) -
+ (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor;
+ q_scale_b = find_proper_scale(find_expn(paprd_abs(scale_b)), 10);
+ scale_b = scale_b / (1 << q_scale_b);
+ /* Check for divide by 0 */
+ if (scale_b == 0) {
+ return AH_FALSE;
+ }
+ q_beta = find_proper_scale(find_expn(paprd_abs(beta_raw)), 10);
+ q_alpha = find_proper_scale(find_expn(paprd_abs(alpha_raw)), 10);
+
+ beta_raw = beta_raw / (1 << q_beta);
+ alpha_raw = alpha_raw / (1 << q_alpha);
+ alpha = (alpha_raw << 10) / scale_b;
+ beta = (beta_raw << 10) / scale_b;
+ order_1 = 3 * m - q_x - q_b1 - q_beta + 10 + q_scale_b;
+ order_2 = 3 * m - q_x - q_b2 - q_alpha + 10 + q_scale_b;
+
+ order1_5x = order_1 / 5;
+ order2_3x = order_2 / 3;
+
+ order1_5x_rem = order_1 - 5 * order1_5x;
+ order2_3x_rem = order_2 - 3 * order2_3x;
+
+ for (idx = 0; idx < AR9300_PAPRD_TABLE_SZ; idx++) {
+ tmp = idx * 32;
+ y5 = ((beta * tmp) >> 6) >> order1_5x;
+ y5 = (y5 * tmp) >> order1_5x;
+ y5 = (y5 * tmp) >> order1_5x;
+ y5 = (y5 * tmp) >> order1_5x;
+ y5 = (y5 * tmp) >> order1_5x;
+
+ y5 = y5 >> order1_5x_rem;
+ y3 = (alpha * tmp) >> order2_3x;
+ y3 = (y3 * tmp) >> order2_3x;
+ y3 = (y3 * tmp) >> order2_3x;
+
+ y3 = y3 >> order2_3x_rem;
+ /* g_fxp was checked for zero already */
+ pa_in[idx] = y5 + y3 + (256 * tmp) / g_fxp;
+ }
+
+ for (idx = 1; idx < 23; idx++) {
+ tmp = pa_in[idx + 1] - pa_in[idx];
+ if (tmp < 0) {
+ pa_in[idx + 1] = pa_in[idx] + (pa_in[idx] - pa_in[idx - 1]);
+ }
+ }
+
+ for (idx = 0; idx < AR9300_PAPRD_TABLE_SZ; idx++) {
+ pa_in[idx] = (pa_in[idx] < 1400) ? pa_in[idx] : 1400;
+ /*printf("idx=%d, pa_in[idx]=%d\n", i, pa_in[idx]);*/
+ }
+
+ beta_raw = 0;
+ alpha_raw = 0;
+
+ for (bin = 0; bin <= half_hi; bin++) {
+ /*
+ * printf(
+ * "bin=%d half_lo=%d m=%d theta[bin+half_lo]=%d "
+ * "y_est[bin+half_lo]=%d\n",
+ * bin, half_lo, m, theta[bin+half_lo], y_est[bin+half_lo]);
+ */
+ /* y_est[] was already checked for zero */
+ theta_tilde[bin] =
+ ((theta[bin + half_lo] << m) + y_est[bin + half_lo]) /
+ y_est[bin + half_lo];
+ theta_tilde[bin] = ((theta_tilde[bin] << m) + y_est[bin + half_lo]) /
+ y_est[bin + half_lo];
+ theta_tilde[bin] = ((theta_tilde[bin] << m) + y_est[bin + half_lo]) /
+ y_est[bin + half_lo];
+
+ /*printf("bin=%d theta_tilde[bin]=%d\n", bin, theta_tilde[bin]);*/
+ beta_raw = beta_raw + b1_tmp[bin] * theta_tilde[bin];
+ alpha_raw = alpha_raw + b2_tmp[bin] * theta_tilde[bin];
+
+ /*
+ printf("bin=%d, alpha_raw=%d, beta_raw=%d\n", bin, alpha_raw, beta_raw);
+ */
+ }
+
+ q_beta = find_proper_scale(find_expn(paprd_abs(beta_raw)), 10);
+ q_alpha = find_proper_scale(find_expn(paprd_abs(alpha_raw)), 10);
+
+ beta_raw = beta_raw / (1 << q_beta);
+ alpha_raw = alpha_raw / (1 << q_alpha);
+ /* scale_b checked for zero previously */
+ alpha = (alpha_raw << 10) / scale_b;
+ beta = (beta_raw << 10) / scale_b;
+ order_1 = 3 * m - q_x - q_b1 - q_beta + 10 + q_scale_b + 5;
+ order_2 = 3 * m - q_x - q_b2 - q_alpha + 10 + q_scale_b + 5;
+
+ order1_5x = order_1 / 5;
+ order2_3x = order_2 / 3;
+
+ order1_5x_rem = order_1 - 5 * order1_5x;
+ order2_3x_rem = order_2 - 3 * order2_3x;
+
+ for (idx = 0; idx < AR9300_PAPRD_TABLE_SZ; idx++) {
+ tmp = idx * 32;
+
+ if (beta > 0) {
+ y5 = (((beta * tmp - 64) >> 6) -
+ (1 << order1_5x)) / (1 << order1_5x);
+ } else {
+ y5 = ((((beta * tmp - 64) >> 6) +
+ (1 << order1_5x)) / (1 << order1_5x));
+ }
+
+ y5 = (y5 * tmp) / (1 << order1_5x);
+ y5 = (y5 * tmp) / (1 << order1_5x);
+ y5 = (y5 * tmp) / (1 << order1_5x);
+ y5 = (y5 * tmp) / (1 << order1_5x);
+
+ y5 = y5 / (1 << order1_5x_rem);
+
+ if (beta > 0) {
+ y3 = (alpha * tmp - (1 << order2_3x)) / (1 << order2_3x);
+ } else {
+ y3 = (alpha * tmp + (1 << order2_3x)) / (1 << order2_3x);
+ }
+
+ y3 = (y3 * tmp) / (1 << order2_3x);
+ y3 = (y3 * tmp) / (1 << order2_3x);
+
+ y3 = y3 / (1 << order2_3x_rem);
+ pa_angle[idx] = y5 + y3;
+ /*printf("idx=%d, y5 = %d, y3=%d\n", idx, y5, y3);*/
+ pa_angle[idx] =
+ (pa_angle[idx] < -150) ? -150 : ((pa_angle[idx] >
+ 150) ? 150 : pa_angle[idx]);
+ }
+
+ pa_angle[0] = 0;
+ pa_angle[1] = 0;
+ pa_angle[2] = 0;
+ pa_angle[3] = 0;
+
+ pa_angle[4] = (pa_angle[5] + 2) >> 1;
+
+ for (idx = 0; idx < AR9300_PAPRD_TABLE_SZ; idx++) {
+ pa_table[idx] = ((pa_in[idx] & 0x7ff) << 11) + (pa_angle[idx] & 0x7ff);
+ /*
+ * HALDEBUG(
+ * NULL, HAL_DEBUG_UNMASKABLE,"%d\t%d\t0x%x\n",
+ * pa_in[idx], pa_angle[idx], pa_table[idx]);
+ */
+ }
+
+ /*HALDEBUG(NULL, HAL_DEBUG_UNMASKABLE, "g_fxp = %d\n", g_fxp);*/
+ *g_fxp_ext = g_fxp;
+ return AH_TRUE;
+}
+
+// Due to a hardware bug, when transmitting with just one chain the papd
+// data for chain 0 is always used. So when using chain 2 or 4, the
+// corresponding data must be copied into the chain 0 area.
+void ar9300_swizzle_paprd_entries(struct ath_hal *ah, unsigned int txchain)
+{
+ int i;
+ u_int32_t *paprd_table_val = NULL;
+ u_int32_t small_signal_gain = 0;
+ u_int32_t reg = 0;
+
+ reg = AR_PHY_PAPRD_MEM_TAB_B0;
+ switch (txchain) {
+ case 0x1:
+ case 0x3:
+ case 0x7:
+ paprd_table_val = &AH9300(ah)->pa_table[0][0];
+ small_signal_gain = AH9300(ah)->small_signal_gain[0];
+ break;
+ case 0x2:
+ paprd_table_val = &AH9300(ah)->pa_table[1][0];
+ small_signal_gain = AH9300(ah)->small_signal_gain[1];
+ break;
+ case 0x4:
+ paprd_table_val = &AH9300(ah)->pa_table[2][0];
+ small_signal_gain = AH9300(ah)->small_signal_gain[2];
+ break;
+ default:
+ // Error out.
+ ath_hal_printf(ah, "YAK! Bad chain mask %x\n", txchain);
+ return;
+ }
+ for (i = 0; i < AR9300_PAPRD_TABLE_SZ; i++) {
+ OS_REG_WRITE(ah, reg, paprd_table_val[i]);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] reg %08x = 0x%08x\n", __func__,
+ __LINE__, reg, paprd_table_val[i]);
+
+ reg = reg + 4;
+ }
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PA_GAIN123_B0,AR_PHY_PA_GAIN123_B0_PA_GAIN1_0, small_signal_gain);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] reg %08x small_signal_gain 0x%08x\n", __func__, __LINE__,
+ (unsigned) AR_PHY_PA_GAIN123_B0, OS_REG_READ(ah, AR_PHY_PA_GAIN123_B0));
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0, AR_PHY_PAPRD_CTRL1_B0_PAPRD_POWER_AT_AM2AM_CAL_0,
+ AH9300(ah)->paprd_training_power);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] reg %08x = 0x%08x\n", __func__, __LINE__,
+ (unsigned) AR_PHY_PAPRD_CTRL1_B0, OS_REG_READ(ah, AR_PHY_PAPRD_CTRL1_B0));
+
+}
+
+void ar9300_populate_paprd_single_table(struct ath_hal *ah, HAL_CHANNEL * chan,
+ int chain_num)
+{
+ int i, j, bad_read = 0;
+ u_int32_t *paprd_table_val = &AH9300(ah)->pa_table[chain_num][0];
+ u_int32_t small_signal_gain = AH9300(ah)->small_signal_gain[chain_num];
+ u_int32_t reg = 0;
+
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "%s[%d]: channel %d paprd_done %d write %d\n", __func__, __LINE__,
+ chan->channel, chan->paprd_done, chan->paprd_table_write_done);
+
+ if (chain_num == 0) {
+ reg = AR_PHY_PAPRD_MEM_TAB_B0;
+ } else if (chain_num == 1) {
+ reg = AR_PHY_PAPRD_MEM_TAB_B1;
+ } else if (chain_num == 2) {
+ reg = AR_PHY_PAPRD_MEM_TAB_B2;
+ }
+
+ for (i = 0; i < AR9300_PAPRD_TABLE_SZ; i++) {
+ if (AR_SREV_POSEIDON(ah)) {
+ HALASSERT(chain_num == 0x1);
+ if ((reg == AR_PHY_PAPRD_MEM_TAB_B1) ||
+ (reg == AR_PHY_PAPRD_MEM_TAB_B2)) {
+ continue;
+ }
+ }
+ /*
+ * sprintf(
+ * field_name, "%s%d[%d]%s\0", "BB_paprd_mem_tab_b",
+ * chain_num, i, ".paprd_mem");
+ */
+ OS_REG_WRITE(ah, reg, paprd_table_val[i]);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] reg %08x = 0x%08x\n", __func__,
+ __LINE__, reg, paprd_table_val[i]);
+ /*
+ * printf(
+ * "%s[%d] reg %08x = 0x%08x\n",
+ * __func__, __LINE__, reg, paprd_table_val[i]);
+ */
+ if (OS_REG_READ(ah, reg) == 0xdeadbeef) {
+ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
+ "%s: Reg0x%x = 0xdeadbeef\n", __func__, reg);
+ bad_read++;
+ for (j = AR_PHY_PAPRD_MEM_TAB_B0; j < (AR_PHY_PAPRD_MEM_TAB_B0 + 0x10); j+=4)
+ {
+ if (OS_REG_READ(ah, j) == 0xdeadbeef) {
+ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
+ "%s: Reg0x%x = 0xdeadbeef\n", __func__, j);
+ bad_read++;
+ }
+ }
+ for (j = AR_PHY_PAPRD_MEM_TAB_B1; j < (AR_PHY_PAPRD_MEM_TAB_B1 + 0x10); j+=4)
+ {
+ if (OS_REG_READ(ah, j) == 0xdeadbeef) {
+ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
+ "%s: Reg0x%x = 0xdeadbeef\n", __func__, j);
+ bad_read++;
+ }
+ }
+ }
+
+ reg = reg + 4;
+ }
+
+ if (bad_read > 4) {
+ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
+ "%s: Get %d 0xdeadbeef. Mark PAPRD as broken.\n",
+ __func__, bad_read);
+ AH9300(ah)->ah_paprd_broken = AH_TRUE;
+ }
+
+ if (chain_num == 0) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PA_GAIN123_B0,
+ AR_PHY_PA_GAIN123_B0_PA_GAIN1_0, small_signal_gain);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "%s[%d] reg %08x small_signal_gain 0x%08x\n", __func__, __LINE__,
+ (unsigned) AR_PHY_PA_GAIN123_B0,
+ OS_REG_READ(ah, AR_PHY_PA_GAIN123_B0));
+ } else if (chain_num == 1) {
+ if (!AR_SREV_POSEIDON(ah) && !AR_SREV_HORNET(ah) && !AR_SREV_APHRODITE(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PA_GAIN123_B1,
+ AR_PHY_PA_GAIN123_B1_PA_GAIN1_1, small_signal_gain);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "%s[%d] reg %08x small_signal_gain 0x%08x\n",
+ __func__, __LINE__,
+ (unsigned) AR_PHY_PA_GAIN123_B1,
+ OS_REG_READ(ah, AR_PHY_PA_GAIN123_B1));
+ }
+ } else if (chain_num == 2) {
+ if (!AR_SREV_POSEIDON(ah) && !AR_SREV_HORNET(ah) && !AR_SREV_APHRODITE(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PA_GAIN123_B2,
+ AR_PHY_PA_GAIN123_B2_PA_GAIN1_2, small_signal_gain);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "%s[%d] reg %08x small_signal_gain 0x%08x\n",
+ __func__, __LINE__,
+ (unsigned) AR_PHY_PA_GAIN123_B2,
+ OS_REG_READ(ah, AR_PHY_PA_GAIN123_B2));
+ }
+ } else {
+ /* invalid channel number */
+ }
+
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B0_PAPRD_POWER_AT_AM2AM_CAL_0,
+ AH9300(ah)->paprd_training_power);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] reg %08x = 0x%08x\n", __func__,
+ __LINE__, (unsigned) AR_PHY_PAPRD_CTRL1_B0,
+ OS_REG_READ(ah, AR_PHY_PAPRD_CTRL1_B0));
+ if (!AR_SREV_POSEIDON(ah) && !AR_SREV_HORNET(ah) && !AR_SREV_APHRODITE(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B1_PAPRD_POWER_AT_AM2AM_CAL_1,
+ AH9300(ah)->paprd_training_power);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s[%d] reg %08x = 0x%08x\n", __func__,
+ __LINE__, (unsigned) AR_PHY_PAPRD_CTRL1_B1,
+ OS_REG_READ(ah, AR_PHY_PAPRD_CTRL1_B1));
+ if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_B2_PAPRD_POWER_AT_AM2AM_CAL_2,
+ AH9300(ah)->paprd_training_power);
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "%s[%d] reg %08x = 0x%08x\n", __func__,
+ __LINE__, (unsigned) AR_PHY_PAPRD_CTRL1_B2,
+ OS_REG_READ(ah, AR_PHY_PAPRD_CTRL1_B2));
+ }
+ }
+ /*ar9300_enable_paprd(ah, AH_TRUE);*/
+}
+
+HAL_STATUS ar9300_paprd_setup_gain_table(struct ath_hal *ah, int chain_num)
+{
+ unsigned int i, desired_gain, gain_index;
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "Run papredistortion single table algorithm:: Training power = %d\n",
+ AH9300(ah)->paprd_training_power / 2);
+
+ if (AH9300(ah)->ah_tx_chainmask & (1 << chain_num)) {
+ /* this is an active chain */
+ desired_gain = ar9300_get_desired_gain_for_chain(
+ ah, chain_num, AH9300(ah)->paprd_training_power);
+ /* find out gain index */
+ gain_index = 0;
+
+ for (i = 0; i < 32; i++) {
+ if (AH9300(ah)->paprd_gain_table_index[i] < desired_gain) {
+ gain_index = gain_index + 1;
+ } else {
+ break;
+ }
+ }
+
+ /*printf("gain_index = %d\n", gain_index);*/
+ /*ath_hal_printf(ah, "++++ gain_index = %d\n", gain_index);*/
+ ar9300_tx_force_gain(ah, gain_index);
+ if (AR_SREV_POSEIDON(ah)) {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE, 0);
+ } else {
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE, 0);
+ }
+ }
+
+ return HAL_OK;
+}
+
+static HAL_BOOL ar9300_paprd_retrain_pain(struct ath_hal * ah, int * pa_in)
+{
+ int count = 0, i;
+ int capdiv_offset = 0, quick_drop_offset;
+ int capdiv2g, quick_drop;
+
+ capdiv2g = (OS_REG_READ(ah, AR_PHY_65NM_CH0_TXRF3) >> 1) & 0xF;
+ if (!AR_SREV_POSEIDON(ah)) {
+ quick_drop =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);
+ } else {
+ quick_drop =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);
+ }
+
+ if ( quick_drop != 0 ) {
+ quick_drop -= 0x40;
+ }
+ for (i = 0; i < (NUM_BIN + 1); i++) {
+ if (pa_in[i] == 1400) {
+ count++;
+ }
+ }
+
+ if (AR_SREV_POSEIDON(ah)) {
+ if ((pa_in[23] < 800) || (pa_in[23] == 1400)) {
+ if (pa_in[23] < 800) {
+ capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150);
+ capdiv2g = capdiv2g + capdiv_offset;
+ if (capdiv2g > 7) {
+ capdiv2g = 7;
+ if (pa_in[23] < 600) {
+ quick_drop = quick_drop + 1;
+ if (quick_drop > 0) {
+ quick_drop = 0;
+ }
+ }
+ }
+
+ OS_REG_RMW_FIELD(ah,
+ AR_PHY_65NM_CH0_TXRF3,
+ AR_PHY_65NM_CH0_TXRF3_CAPDIV2G,
+ capdiv2g);
+
+ OS_REG_RMW_FIELD_ALT(ah,
+ AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ quick_drop);
+
+ return AH_TRUE;
+ } /* end of if (pa_in[23] < 800) */
+ else if (pa_in[23] == 1400) {
+ quick_drop_offset = (int)(count / 3);
+ if (quick_drop_offset > 2) {
+ quick_drop_offset = 2;
+ }
+ quick_drop = quick_drop + quick_drop_offset;
+ capdiv2g = capdiv2g + (int)(quick_drop_offset / 2);
+ if (capdiv2g > 7) {
+ capdiv2g = 7;
+ }
+ if (quick_drop > 0) {
+ quick_drop = 0;
+ capdiv2g = capdiv2g - (int)(quick_drop_offset / 1);
+ if (capdiv2g < 0) {
+ capdiv2g = 0;
+ }
+ }
+ OS_REG_RMW_FIELD(ah,
+ AR_PHY_65NM_CH0_TXRF3,
+ AR_PHY_65NM_CH0_TXRF3_CAPDIV2G,
+ capdiv2g);
+
+ OS_REG_RMW_FIELD_ALT(ah,
+ AR_PHY_PAPRD_TRAINER_CNTL3_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ quick_drop);
+
+ return AH_TRUE;
+ /* sleep(1); */
+ } /* end of if (pa_in[23] == 1400)*/
+ } /* end of if ((pa_in[23] < 800) || (pa_in[23] == 1400)) */
+ }else if (AR_SREV_HORNET(ah)) {
+ if ((pa_in[23] < 1000) || (pa_in[23] == 1400)) {
+ if (pa_in[23] < 1000) {
+ capdiv_offset = ((1000 - pa_in[23]) / 100);
+ capdiv2g = capdiv2g + capdiv_offset;
+ if (capdiv_offset > 3) {
+ quick_drop_offset = 1;
+ quick_drop = quick_drop - quick_drop_offset;
+ capdiv2g = capdiv2g + 1;
+ if (capdiv2g > 6) {
+ capdiv2g = 6;
+ }
+ if (quick_drop < -4) {
+ quick_drop = -4;
+ }
+ OS_REG_RMW_FIELD(ah,
+ AR_PHY_65NM_CH0_TXRF3,
+ AR_PHY_65NM_CH0_TXRF3_CAPDIV2G,
+ capdiv2g);
+ OS_REG_RMW_FIELD_ALT(ah,
+ AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ quick_drop);
+ return AH_TRUE;
+ } else {
+ capdiv2g = capdiv2g + capdiv_offset;
+ if (capdiv2g > 6) {
+ capdiv2g = 6;
+ }
+ if (quick_drop < -4) {
+ quick_drop = -4;
+ }
+ OS_REG_RMW_FIELD(ah,
+ AR_PHY_65NM_CH0_TXRF3,
+ AR_PHY_65NM_CH0_TXRF3_CAPDIV2G,
+ capdiv2g);
+ OS_REG_RMW_FIELD_ALT(ah,
+ AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ quick_drop);
+ return AH_TRUE;
+ }
+ } /* end of if (PA_in[23] < 1000) */
+ else if (pa_in[23] == 1400) {
+ if (count > 3) {
+ quick_drop_offset = 1;
+ quick_drop = quick_drop + quick_drop_offset;
+ capdiv2g = capdiv2g - (count / 4);
+ if (capdiv2g < 0) {
+ capdiv2g = 0;
+ }
+ if (quick_drop > -2) {
+ quick_drop = -2;
+ }
+ OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
+ AR_PHY_65NM_CH0_TXRF3_CAPDIV2G,
+ capdiv2g);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ quick_drop);
+ return AH_TRUE;
+ } else {
+ capdiv2g = capdiv2g - 1;
+ if (capdiv2g < 0) {
+ capdiv2g = 0;
+ }
+ OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
+ AR_PHY_65NM_CH0_TXRF3_CAPDIV2G,
+ capdiv2g);
+ OS_REG_RMW_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ quick_drop);
+ return AH_TRUE;
+ }
+ } /* end of if (PA_in[23] == 1400)*/
+ } /* end of if ((PA_in[23] < 1000) || (PA_in[23] == 1400)) */
+ }
+
+ return AH_FALSE;
+}
+
+HAL_STATUS ar9300_paprd_create_curve(struct ath_hal * ah, HAL_CHANNEL * chan,
+ int chain_num)
+{
+ int status = 0;
+ u_int32_t *pa_table, small_signal_gain;
+ int pa_in[NUM_BIN + 1];
+
+ if (AH9300(ah)->ah_tx_chainmask & (1 << chain_num)) {
+ pa_table = &AH9300(ah)->pa_table[chain_num][0];
+ /* Compute PA table and gain index */
+ status = ar9300_create_pa_curve(ah, &pa_table[0], &small_signal_gain,
+ &pa_in[0]);
+
+ if (AR_SREV_WASP(ah)) {
+ OS_DELAY(1000);
+ }
+
+ if (status != 0) {
+ ath_hal_printf(ah, "ERROR:: paprd failed with error code = %d\n",
+ status);
+ return -1;
+ }
+ AH9300(ah)->small_signal_gain[chain_num] = small_signal_gain;
+
+ if (AR_SREV_POSEIDON(ah) || AR_SREV_HORNET(ah)) {
+ if (ar9300_paprd_retrain_pain(ah, pa_in)) {
+ /* need re-train PAPRD */
+ return HAL_EINPROGRESS;
+ }
+ }
+ }
+ return HAL_OK;
+}
+
+int ar9300_paprd_init_table(struct ath_hal *ah, HAL_CHANNEL * chan)
+{
+ if ((AR_SREV_WASP(ah) && IS_CHAN_5GHZ(chan)) ||
+ ar9300_paprd_setup_single_table(ah, chan)) {
+ goto FAIL;
+ }
+ OS_MEMZERO(AH9300(ah)->paprd_gain_table_entries,
+ sizeof(AH9300(ah)->paprd_gain_table_entries));
+ OS_MEMZERO(AH9300(ah)->paprd_gain_table_index,
+ sizeof(AH9300(ah)->paprd_gain_table_index));
+
+ ar9300_gain_table_entries(ah);
+ return 0;
+FAIL:
+ return -1;
+}
+
+int ar9300_paprd_is_done(struct ath_hal *ah)
+{
+ int temp, agc2_pwr;
+
+ /*field_read("BB_paprd_trainer_stat1.paprd_train_done", &temp);*/
+ if (!AR_SREV_POSEIDON(ah)) {
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+
+ if (temp == 0x1) {
+ agc2_pwr =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR);
+
+ HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
+ "%s AGC2_PWR=0x%2x Training done=0x%2x\n",
+ __func__, agc2_pwr, temp);
+
+ /* Retrain if agc2_pwr is not in ideal range */
+ if (agc2_pwr <= AH_PAPRD_IDEAL_AGC2_PWR_RANGE) {
+ temp = 0;
+ }
+ }
+ } else {
+ temp =
+ OS_REG_READ_FIELD_ALT(ah, AR_PHY_PAPRD_TRAINER_STAT1_POSEIDON,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+ }
+ if (!temp) {
+ /*ath_hal_printf(ah, "%s[%d] PAPRD TEMp Error\n", __func__, __LINE__);*/
+ }
+
+ return temp;
+}
+
+/*
+ * ar9300_paprd_dec_tx_pwr
+ *
+ * This function do decrease tx power if Paprd is off or train failed.
+ */
+void
+ar9300_paprd_dec_tx_pwr(struct ath_hal *ah)
+{
+ u_int32_t pwr_temp, pwr_reg;
+ int i, loop_cnt;
+ struct ar9300_paprd_pwr_adjust *p_item;
+ struct ath_hal_9300 *ahp = AH9300(ah);
+
+ if (AR_SREV_POSEIDON(ah)) {
+ loop_cnt =
+ (sizeof(ar9300_paprd_pwr_adj_array) /
+ sizeof(struct ar9300_paprd_pwr_adjust));
+ for (i = 0; i < loop_cnt; i++ )
+ {
+ p_item = &ar9300_paprd_pwr_adj_array[i];
+ pwr_reg = OS_REG_READ(ah, p_item->reg_addr);
+ pwr_temp = ahp->ah_default_tx_power[p_item->target_rate];
+ pwr_temp -= (p_item->sub_db * 2);
+ pwr_temp = pwr_temp << p_item->reg_mask_offset;
+ pwr_temp |= (pwr_reg&~(p_item->reg_mask <<p_item->reg_mask_offset));
+
+ if (pwr_temp != pwr_reg)
+ {
+ OS_REG_WRITE(ah, p_item->reg_addr, pwr_temp);
+ }
+ }
+ }
+ return;
+}
+
+int ar9300_paprd_thermal_send(struct ath_hal *ah)
+{
+ if (AR_SREV_HORNET(ah)) {
+ return OS_REG_READ(ah, AR_TFCNT);
+ } else {
+ return 1;
+ }
+}
+
+#if 0
+void ar9300_paprd_test_prints(struct ath_hal *ah)
+{
+ u_int32_t i, reg = 0;
+
+ HALDEBUG(NULL, HAL_DEBUG_CALIBRATE, "=====ar9300_paprd_test_prints=======\n");
+ /*printf("=====ar9300_paprd_test_prints=======\n");*/
+ HALDEBUG(NULL, HAL_DEBUG_CALIBRATE, "BB_paprd_ctrl0_b0 = 0x%08x\n",
+ OS_REG_READ(ah, AR_PHY_PAPRD_CTRL0_B0));
+ /*
+ * printf(
+ * "BB_paprd_ctrl0_b0 = 0x%08x\n",
+ * OS_REG_READ(ah, AR_PHY_PAPRD_CTRL0_B0));
+ */
+ if (!AR_SREV_POSEIDON(ah) && !AR_SREV_HORNET(ah)) {
+ HALDEBUG(NULL, HAL_DEBUG_CALIBRATE, "BB_paprd_ctrl0_b1 = 0x%08x\n",
+ OS_REG_READ(ah, AR_PHY_PAPRD_CTRL0_B1));
+ /*
+ * printf(
+ * "BB_paprd_ctrl0_b1 = 0x%08x\n",
+ * OS_REG_READ(ah, AR_PHY_PAPRD_CTRL0_B1));
+ */
+ HALDEBUG(NULL, HAL_DEBUG_CALIBRATE, "BB_paprd_ctrl0_b2 = 0x%08x\n",
+ OS_REG_READ(ah, AR_PHY_PAPRD_CTRL0_B2));
+ /*
+ * printf(
+ * "BB_paprd_ctrl0_b2 = 0x%08x\n",
+ * OS_REG_READ(ah, AR_PHY_PAPRD_CTRL0_B2));
+ */
+ }
+
+ reg = AR_PHY_PAPRD_MEM_TAB_B0;
+ HALDEBUG(NULL, HAL_DEBUG_CALIBRATE,
+ "%s[%d] reg %08lx small_signal_gain ch0 0x%08x\n", __func__, __LINE__,
+ AR_PHY_PA_GAIN123_B0, OS_REG_READ(ah, AR_PHY_PA_GAIN123_B0));
+ /*
+ * printf(
+ * "%s[%d] reg %08lx small_signal_gain ch0 0x%08x\n",
+ * __func__, __LINE__, AR_PHY_PA_GAIN123_B0,
+ * OS_REG_READ(ah, AR_PHY_PA_GAIN123_B0));
+ */
+
+ for (i = 0; i < 24; i++) {
+ HALDEBUG(NULL, HAL_DEBUG_CALIBRATE, "%s[%d] reg %08x = 0x%08x\n",
+ __func__, __LINE__, reg, OS_REG_READ(ah, reg));
+ /*
+ * printf(
+ * "%s[%d] reg %08x = 0x%08x\n", __func__, __LINE__,
+ * reg, OS_REG_READ(ah, reg));
+ */
+ reg = reg + 4;
+ }
+
+ ar9300_paprd_debug_print(ah);
+ HALDEBUG(NULL, HAL_DEBUG_CALIBRATE,
+ "=====ar9300_paprd_test_prints end=======\n");
+ /*printf("=====ar9300_paprd_test_prints end=======\n");*/
+
+ if (!AR_SREV_POSEIDON(ah)) {
+ reg = AR_PHY_PAPRD_MEM_TAB_B1;
+ printf("%s[%d] reg %08lx small_signal_gain ch1 0x%08x\n",
+ __func__, __LINE__,
+ AR_PHY_PA_GAIN123_B1, OS_REG_READ(ah, AR_PHY_PA_GAIN123_B1));
+ for (i = 0; i < 24; i++) {
+ OS_REG_WRITE(ah, reg, paprd_table_val[i]);
+ HALDEBUG(NULL, HAL_DEBUG_CALIBRATE, "%s[%d] reg %08x = 0x%08x\n",
+ __func__, __LINE__, reg, OS_REG_READ(ah, reg));
+ printf("%s[%d] reg %08x = 0x%08x\n", __func__, __LINE__, reg,
+ OS_REG_READ(ah, reg));
+ reg = reg + 4;
+ }
+
+ reg = AR_PHY_PAPRD_MEM_TAB_B2;
+ printf("%s[%d] reg %08lx small_signal_gain ch2 0x%08x\n",
+ __func__, __LINE__,
+ AR_PHY_PA_GAIN123_B2, OS_REG_READ(ah, AR_PHY_PA_GAIN123_B2));
+ }
+}
+#endif
+
+#else
+int
+ar9300_paprd_init_table(struct ath_hal *ah, HAL_CHANNEL * chan)
+{
+ return 0;
+}
+
+HAL_STATUS
+ar9300_paprd_setup_gain_table(struct ath_hal * ah, int chain_num)
+{
+ return HAL_OK;
+}
+
+HAL_STATUS
+ar9300_paprd_create_curve(struct ath_hal * ah, HAL_CHANNEL * chan,
+ int chain_num)
+{
+ return HAL_OK;
+}
+
+int
+ar9300_paprd_is_done(struct ath_hal *ah)
+{
+ return 0;
+}
+
+void
+ar9300_enable_paprd(struct ath_hal *ah, HAL_BOOL enable_flag, HAL_CHANNEL * chan)
+{
+ return;
+}
+
+void
+ar9300_populate_paprd_single_table(struct ath_hal *ah, HAL_CHANNEL * chan,
+ int chain_num)
+{
+ return;
+}
+
+void
+ar9300_paprd_dec_tx_pwr(struct ath_hal *ah)
+{
+ return;
+}
+
+int ar9300_paprd_thermal_send(struct ath_hal *ah)
+{
+ return 1;
+}
+#endif /* ATH_SUPPORT_PAPRD */
OpenPOWER on IntegriCloud