162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2010-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/export.h> 1862306a36Sopenharmony_ci#include "hw.h" 1962306a36Sopenharmony_ci#include "ar9003_phy.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_civoid ar9003_paprd_enable(struct ath_hw *ah, bool val) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct ath9k_channel *chan = ah->curchan; 2462306a36Sopenharmony_ci bool is2ghz = IS_CHAN_2GHZ(chan); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* 2762306a36Sopenharmony_ci * 3 bits for modalHeader5G.papdRateMaskHt20 2862306a36Sopenharmony_ci * is used for sub-band disabling of PAPRD. 2962306a36Sopenharmony_ci * 5G band is divided into 3 sub-bands -- upper, 3062306a36Sopenharmony_ci * middle, lower. 3162306a36Sopenharmony_ci * if bit 30 of modalHeader5G.papdRateMaskHt20 is set 3262306a36Sopenharmony_ci * -- disable PAPRD for upper band 5GHz 3362306a36Sopenharmony_ci * if bit 29 of modalHeader5G.papdRateMaskHt20 is set 3462306a36Sopenharmony_ci * -- disable PAPRD for middle band 5GHz 3562306a36Sopenharmony_ci * if bit 28 of modalHeader5G.papdRateMaskHt20 is set 3662306a36Sopenharmony_ci * -- disable PAPRD for lower band 5GHz 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (!is2ghz) { 4062306a36Sopenharmony_ci if (chan->channel >= UPPER_5G_SUB_BAND_START) { 4162306a36Sopenharmony_ci if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) 4262306a36Sopenharmony_ci & BIT(30)) 4362306a36Sopenharmony_ci val = false; 4462306a36Sopenharmony_ci } else if (chan->channel >= MID_5G_SUB_BAND_START) { 4562306a36Sopenharmony_ci if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) 4662306a36Sopenharmony_ci & BIT(29)) 4762306a36Sopenharmony_ci val = false; 4862306a36Sopenharmony_ci } else { 4962306a36Sopenharmony_ci if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) 5062306a36Sopenharmony_ci & BIT(28)) 5162306a36Sopenharmony_ci val = false; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (val) { 5662306a36Sopenharmony_ci ah->paprd_table_write_done = true; 5762306a36Sopenharmony_ci ath9k_hw_apply_txpower(ah, chan, false); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0, 6162306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 6262306a36Sopenharmony_ci if (ah->caps.tx_chainmask & BIT(1)) 6362306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1, 6462306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 6562306a36Sopenharmony_ci if (ah->caps.tx_chainmask & BIT(2)) 6662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2, 6762306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ciEXPORT_SYMBOL(ar9003_paprd_enable); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int ar9003_get_training_power_2g(struct ath_hw *ah) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct ath9k_channel *chan = ah->curchan; 7462306a36Sopenharmony_ci unsigned int power, scale, delta; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci scale = ar9003_get_paprd_scale_factor(ah, chan); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || 7962306a36Sopenharmony_ci AR_SREV_9462(ah) || AR_SREV_9565(ah)) { 8062306a36Sopenharmony_ci power = ah->paprd_target_power + 2; 8162306a36Sopenharmony_ci } else if (AR_SREV_9485(ah)) { 8262306a36Sopenharmony_ci power = 25; 8362306a36Sopenharmony_ci } else { 8462306a36Sopenharmony_ci power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, 8562306a36Sopenharmony_ci AR_PHY_POWERTX_RATE5_POWERTXHT20_0); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci delta = abs((int) ah->paprd_target_power - (int) power); 8862306a36Sopenharmony_ci if (delta > scale) 8962306a36Sopenharmony_ci return -1; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (delta < 4) 9262306a36Sopenharmony_ci power -= 4 - delta; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return power; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int ar9003_get_training_power_5g(struct ath_hw *ah) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 10162306a36Sopenharmony_ci struct ath9k_channel *chan = ah->curchan; 10262306a36Sopenharmony_ci unsigned int power, scale, delta; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci scale = ar9003_get_paprd_scale_factor(ah, chan); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (IS_CHAN_HT40(chan)) 10762306a36Sopenharmony_ci power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8, 10862306a36Sopenharmony_ci AR_PHY_POWERTX_RATE8_POWERTXHT40_5); 10962306a36Sopenharmony_ci else 11062306a36Sopenharmony_ci power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6, 11162306a36Sopenharmony_ci AR_PHY_POWERTX_RATE6_POWERTXHT20_5); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci power += scale; 11462306a36Sopenharmony_ci delta = abs((int) ah->paprd_target_power - (int) power); 11562306a36Sopenharmony_ci if (delta > scale) 11662306a36Sopenharmony_ci return -1; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci switch (get_streams(ah->txchainmask)) { 11962306a36Sopenharmony_ci case 1: 12062306a36Sopenharmony_ci delta = 6; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci case 2: 12362306a36Sopenharmony_ci delta = 4; 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci case 3: 12662306a36Sopenharmony_ci delta = 2; 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci default: 12962306a36Sopenharmony_ci delta = 0; 13062306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Invalid tx-chainmask: %u\n", 13162306a36Sopenharmony_ci ah->txchainmask); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci power += delta; 13562306a36Sopenharmony_ci return power; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int ar9003_paprd_setup_single_table(struct ath_hw *ah) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 14162306a36Sopenharmony_ci static const u32 ctrl0[3] = { 14262306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL0_B0, 14362306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL0_B1, 14462306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL0_B2 14562306a36Sopenharmony_ci }; 14662306a36Sopenharmony_ci static const u32 ctrl1[3] = { 14762306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_B0, 14862306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_B1, 14962306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_B2 15062306a36Sopenharmony_ci }; 15162306a36Sopenharmony_ci int training_power; 15262306a36Sopenharmony_ci int i, val; 15362306a36Sopenharmony_ci u32 am2pm_mask = ah->paprd_ratemask; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (IS_CHAN_2GHZ(ah->curchan)) 15662306a36Sopenharmony_ci training_power = ar9003_get_training_power_2g(ah); 15762306a36Sopenharmony_ci else 15862306a36Sopenharmony_ci training_power = ar9003_get_training_power_5g(ah); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Training power: %d, Target power: %d\n", 16162306a36Sopenharmony_ci training_power, ah->paprd_target_power); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (training_power < 0) { 16462306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 16562306a36Sopenharmony_ci "PAPRD target power delta out of range\n"); 16662306a36Sopenharmony_ci return -ERANGE; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci ah->paprd_training_power = training_power; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (AR_SREV_9330(ah)) 17162306a36Sopenharmony_ci am2pm_mask = 0; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, 17462306a36Sopenharmony_ci ah->paprd_ratemask); 17562306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, 17662306a36Sopenharmony_ci am2pm_mask); 17762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, 17862306a36Sopenharmony_ci ah->paprd_ratemask_ht40); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "PAPRD HT20 mask: 0x%x, HT40 mask: 0x%x\n", 18162306a36Sopenharmony_ci ah->paprd_ratemask, ah->paprd_ratemask_ht40); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci for (i = 0; i < ah->caps.max_txchains; i++) { 18462306a36Sopenharmony_ci REG_RMW_FIELD(ah, ctrl0[i], 18562306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1); 18662306a36Sopenharmony_ci REG_RMW_FIELD(ah, ctrl1[i], 18762306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1); 18862306a36Sopenharmony_ci REG_RMW_FIELD(ah, ctrl1[i], 18962306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1); 19062306a36Sopenharmony_ci REG_RMW_FIELD(ah, ctrl1[i], 19162306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 19262306a36Sopenharmony_ci REG_RMW_FIELD(ah, ctrl1[i], 19362306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181); 19462306a36Sopenharmony_ci REG_RMW_FIELD(ah, ctrl1[i], 19562306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361); 19662306a36Sopenharmony_ci REG_RMW_FIELD(ah, ctrl1[i], 19762306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 19862306a36Sopenharmony_ci REG_RMW_FIELD(ah, ctrl0[i], 19962306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci ar9003_paprd_enable(ah, false); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 20562306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30); 20662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 20762306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1); 20862306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 20962306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1); 21062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 21162306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0); 21262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 21362306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0); 21462306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 21562306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28); 21662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), 21762306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (AR_SREV_9485(ah)) { 22062306a36Sopenharmony_ci val = 148; 22162306a36Sopenharmony_ci } else { 22262306a36Sopenharmony_ci if (IS_CHAN_2GHZ(ah->curchan)) { 22362306a36Sopenharmony_ci if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) 22462306a36Sopenharmony_ci val = 145; 22562306a36Sopenharmony_ci else 22662306a36Sopenharmony_ci val = 147; 22762306a36Sopenharmony_ci } else { 22862306a36Sopenharmony_ci val = 137; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2(ah), 23362306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val); 23462306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 23562306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4); 23662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 23762306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4); 23862306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 23962306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); 24062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 24162306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (AR_SREV_9485(ah) || 24462306a36Sopenharmony_ci AR_SREV_9462(ah) || 24562306a36Sopenharmony_ci AR_SREV_9565(ah) || 24662306a36Sopenharmony_ci AR_SREV_9550(ah) || 24762306a36Sopenharmony_ci AR_SREV_9330(ah) || 24862306a36Sopenharmony_ci AR_SREV_9340(ah)) 24962306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 25062306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3); 25162306a36Sopenharmony_ci else 25262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 25362306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci val = -10; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (IS_CHAN_2GHZ(ah->curchan) && !AR_SREV_9462(ah) && !AR_SREV_9565(ah)) 25862306a36Sopenharmony_ci val = -15; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 26162306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, 26262306a36Sopenharmony_ci val); 26362306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 26462306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1); 26562306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), 26662306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0); 26762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), 26862306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400); 26962306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), 27062306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES, 27162306a36Sopenharmony_ci 100); 27262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0, 27362306a36Sopenharmony_ci AR_PHY_PAPRD_PRE_POST_SCALING, 261376); 27462306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0, 27562306a36Sopenharmony_ci AR_PHY_PAPRD_PRE_POST_SCALING, 248079); 27662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0, 27762306a36Sopenharmony_ci AR_PHY_PAPRD_PRE_POST_SCALING, 233759); 27862306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0, 27962306a36Sopenharmony_ci AR_PHY_PAPRD_PRE_POST_SCALING, 220464); 28062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0, 28162306a36Sopenharmony_ci AR_PHY_PAPRD_PRE_POST_SCALING, 208194); 28262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0, 28362306a36Sopenharmony_ci AR_PHY_PAPRD_PRE_POST_SCALING, 196949); 28462306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0, 28562306a36Sopenharmony_ci AR_PHY_PAPRD_PRE_POST_SCALING, 185706); 28662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0, 28762306a36Sopenharmony_ci AR_PHY_PAPRD_PRE_POST_SCALING, 175487); 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic void ar9003_paprd_get_gain_table(struct ath_hw *ah) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci u32 *entry = ah->paprd_gain_table_entries; 29462306a36Sopenharmony_ci u8 *index = ah->paprd_gain_table_index; 29562306a36Sopenharmony_ci u32 reg = AR_PHY_TXGAIN_TABLE; 29662306a36Sopenharmony_ci int i; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { 29962306a36Sopenharmony_ci entry[i] = REG_READ(ah, reg); 30062306a36Sopenharmony_ci index[i] = (entry[i] >> 24) & 0xff; 30162306a36Sopenharmony_ci reg += 4; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, 30662306a36Sopenharmony_ci int target_power) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci int olpc_gain_delta = 0, cl_gain_mod; 30962306a36Sopenharmony_ci int alpha_therm, alpha_volt; 31062306a36Sopenharmony_ci int therm_cal_value, volt_cal_value; 31162306a36Sopenharmony_ci int therm_value, volt_value; 31262306a36Sopenharmony_ci int thermal_gain_corr, voltage_gain_corr; 31362306a36Sopenharmony_ci int desired_scale, desired_gain = 0; 31462306a36Sopenharmony_ci u32 reg_olpc = 0, reg_cl_gain = 0; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 31762306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 31862306a36Sopenharmony_ci desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12, 31962306a36Sopenharmony_ci AR_PHY_TPC_12_DESIRED_SCALE_HT40_5); 32062306a36Sopenharmony_ci alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19, 32162306a36Sopenharmony_ci AR_PHY_TPC_19_ALPHA_THERM); 32262306a36Sopenharmony_ci alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19, 32362306a36Sopenharmony_ci AR_PHY_TPC_19_ALPHA_VOLT); 32462306a36Sopenharmony_ci therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 32562306a36Sopenharmony_ci AR_PHY_TPC_18_THERM_CAL_VALUE); 32662306a36Sopenharmony_ci volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 32762306a36Sopenharmony_ci AR_PHY_TPC_18_VOLT_CAL_VALUE); 32862306a36Sopenharmony_ci therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 32962306a36Sopenharmony_ci AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE); 33062306a36Sopenharmony_ci volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 33162306a36Sopenharmony_ci AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci switch (chain) { 33462306a36Sopenharmony_ci case 0: 33562306a36Sopenharmony_ci reg_olpc = AR_PHY_TPC_11_B0; 33662306a36Sopenharmony_ci reg_cl_gain = AR_PHY_CL_TAB_0; 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci case 1: 33962306a36Sopenharmony_ci reg_olpc = AR_PHY_TPC_11_B1; 34062306a36Sopenharmony_ci reg_cl_gain = AR_PHY_CL_TAB_1; 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci case 2: 34362306a36Sopenharmony_ci reg_olpc = AR_PHY_TPC_11_B2; 34462306a36Sopenharmony_ci reg_cl_gain = AR_PHY_CL_TAB_2; 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci default: 34762306a36Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 34862306a36Sopenharmony_ci "Invalid chainmask: %d\n", chain); 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci olpc_gain_delta = REG_READ_FIELD(ah, reg_olpc, 35362306a36Sopenharmony_ci AR_PHY_TPC_11_OLPC_GAIN_DELTA); 35462306a36Sopenharmony_ci cl_gain_mod = REG_READ_FIELD(ah, reg_cl_gain, 35562306a36Sopenharmony_ci AR_PHY_CL_TAB_CL_GAIN_MOD); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (olpc_gain_delta >= 128) 35862306a36Sopenharmony_ci olpc_gain_delta = olpc_gain_delta - 256; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) + 36162306a36Sopenharmony_ci (256 / 2)) / 256; 36262306a36Sopenharmony_ci voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) + 36362306a36Sopenharmony_ci (128 / 2)) / 128; 36462306a36Sopenharmony_ci desired_gain = target_power - olpc_gain_delta - thermal_gain_corr - 36562306a36Sopenharmony_ci voltage_gain_corr + desired_scale + cl_gain_mod; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return desired_gain; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain; 37362306a36Sopenharmony_ci int padrvgnA, padrvgnB, padrvgnC, padrvgnD; 37462306a36Sopenharmony_ci u32 *gain_table_entries = ah->paprd_gain_table_entries; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci selected_gain_entry = gain_table_entries[gain_index]; 37762306a36Sopenharmony_ci txbb1dbgain = selected_gain_entry & 0x7; 37862306a36Sopenharmony_ci txbb6dbgain = (selected_gain_entry >> 3) & 0x3; 37962306a36Sopenharmony_ci txmxrgain = (selected_gain_entry >> 5) & 0xf; 38062306a36Sopenharmony_ci padrvgnA = (selected_gain_entry >> 9) & 0xf; 38162306a36Sopenharmony_ci padrvgnB = (selected_gain_entry >> 13) & 0xf; 38262306a36Sopenharmony_ci padrvgnC = (selected_gain_entry >> 17) & 0xf; 38362306a36Sopenharmony_ci padrvgnD = (selected_gain_entry >> 21) & 0x3; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 38662306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain); 38762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 38862306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain); 38962306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 39062306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain); 39162306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 39262306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA); 39362306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 39462306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB); 39562306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 39662306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC); 39762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 39862306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD); 39962306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 40062306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0); 40162306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 40262306a36Sopenharmony_ci AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0); 40362306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0); 40462306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic inline int find_expn(int num) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci return fls(num) - 1; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic inline int find_proper_scale(int expn, int N) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci return (expn > N) ? expn - 10 : 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci#define NUM_BIN 23 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci unsigned int thresh_accum_cnt; 42262306a36Sopenharmony_ci int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1]; 42362306a36Sopenharmony_ci int PA_in[NUM_BIN + 1]; 42462306a36Sopenharmony_ci int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1]; 42562306a36Sopenharmony_ci unsigned int B1_abs_max, B2_abs_max; 42662306a36Sopenharmony_ci int max_index, scale_factor; 42762306a36Sopenharmony_ci int y_est[NUM_BIN + 1]; 42862306a36Sopenharmony_ci int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1]; 42962306a36Sopenharmony_ci unsigned int x_tilde_abs; 43062306a36Sopenharmony_ci int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad; 43162306a36Sopenharmony_ci int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B; 43262306a36Sopenharmony_ci int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2; 43362306a36Sopenharmony_ci int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem; 43462306a36Sopenharmony_ci int y5, y3, tmp; 43562306a36Sopenharmony_ci int theta_low_bin = 0; 43662306a36Sopenharmony_ci int i; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* disregard any bin that contains <= 16 samples */ 43962306a36Sopenharmony_ci thresh_accum_cnt = 16; 44062306a36Sopenharmony_ci scale_factor = 5; 44162306a36Sopenharmony_ci max_index = 0; 44262306a36Sopenharmony_ci memset(theta, 0, sizeof(theta)); 44362306a36Sopenharmony_ci memset(x_est, 0, sizeof(x_est)); 44462306a36Sopenharmony_ci memset(Y, 0, sizeof(Y)); 44562306a36Sopenharmony_ci memset(y_est, 0, sizeof(y_est)); 44662306a36Sopenharmony_ci memset(x_tilde, 0, sizeof(x_tilde)); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci for (i = 0; i < NUM_BIN; i++) { 44962306a36Sopenharmony_ci s32 accum_cnt, accum_tx, accum_rx, accum_ang; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* number of samples */ 45262306a36Sopenharmony_ci accum_cnt = data_L[i] & 0xffff; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (accum_cnt <= thresh_accum_cnt) 45562306a36Sopenharmony_ci continue; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci max_index++; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* sum(tx amplitude) */ 46062306a36Sopenharmony_ci accum_tx = ((data_L[i] >> 16) & 0xffff) | 46162306a36Sopenharmony_ci ((data_U[i] & 0x7ff) << 16); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* sum(rx amplitude distance to lower bin edge) */ 46462306a36Sopenharmony_ci accum_rx = ((data_U[i] >> 11) & 0x1f) | 46562306a36Sopenharmony_ci ((data_L[i + 23] & 0xffff) << 5); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* sum(angles) */ 46862306a36Sopenharmony_ci accum_ang = ((data_L[i + 23] >> 16) & 0xffff) | 46962306a36Sopenharmony_ci ((data_U[i + 23] & 0x7ff) << 16); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci accum_tx <<= scale_factor; 47262306a36Sopenharmony_ci accum_rx <<= scale_factor; 47362306a36Sopenharmony_ci x_est[max_index] = 47462306a36Sopenharmony_ci (((accum_tx + accum_cnt) / accum_cnt) + 32) >> 47562306a36Sopenharmony_ci scale_factor; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci Y[max_index] = 47862306a36Sopenharmony_ci ((((accum_rx + accum_cnt) / accum_cnt) + 32) >> 47962306a36Sopenharmony_ci scale_factor) + 48062306a36Sopenharmony_ci (1 << scale_factor) * i + 16; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (accum_ang >= (1 << 26)) 48362306a36Sopenharmony_ci accum_ang -= 1 << 27; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci theta[max_index] = 48662306a36Sopenharmony_ci ((accum_ang * (1 << scale_factor)) + accum_cnt) / 48762306a36Sopenharmony_ci accum_cnt; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* 49162306a36Sopenharmony_ci * Find average theta of first 5 bin and all of those to same value. 49262306a36Sopenharmony_ci * Curve is linear at that range. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci for (i = 1; i < 6; i++) 49562306a36Sopenharmony_ci theta_low_bin += theta[i]; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci theta_low_bin = theta_low_bin / 5; 49862306a36Sopenharmony_ci for (i = 1; i < 6; i++) 49962306a36Sopenharmony_ci theta[i] = theta_low_bin; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci /* Set values at origin */ 50262306a36Sopenharmony_ci theta[0] = theta_low_bin; 50362306a36Sopenharmony_ci for (i = 0; i <= max_index; i++) 50462306a36Sopenharmony_ci theta[i] -= theta_low_bin; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci x_est[0] = 0; 50762306a36Sopenharmony_ci Y[0] = 0; 50862306a36Sopenharmony_ci scale_factor = 8; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* low signal gain */ 51162306a36Sopenharmony_ci if (x_est[6] == x_est[3]) 51262306a36Sopenharmony_ci return false; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci G_fxp = 51562306a36Sopenharmony_ci (((Y[6] - Y[3]) * 1 << scale_factor) + 51662306a36Sopenharmony_ci (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* prevent division by zero */ 51962306a36Sopenharmony_ci if (G_fxp == 0) 52062306a36Sopenharmony_ci return false; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci Y_intercept = 52362306a36Sopenharmony_ci (G_fxp * (x_est[0] - x_est[3]) + 52462306a36Sopenharmony_ci (1 << scale_factor)) / (1 << scale_factor) + Y[3]; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci for (i = 0; i <= max_index; i++) 52762306a36Sopenharmony_ci y_est[i] = Y[i] - Y_intercept; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci for (i = 0; i <= 3; i++) { 53062306a36Sopenharmony_ci y_est[i] = i * 32; 53162306a36Sopenharmony_ci x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (y_est[max_index] == 0) 53562306a36Sopenharmony_ci return false; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci x_est_fxp1_nonlin = 53862306a36Sopenharmony_ci x_est[max_index] - ((1 << scale_factor) * y_est[max_index] + 53962306a36Sopenharmony_ci G_fxp) / G_fxp; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci order_x_by_y = 54262306a36Sopenharmony_ci (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index]; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (order_x_by_y == 0) 54562306a36Sopenharmony_ci M = 10; 54662306a36Sopenharmony_ci else if (order_x_by_y == 1) 54762306a36Sopenharmony_ci M = 9; 54862306a36Sopenharmony_ci else 54962306a36Sopenharmony_ci M = 8; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci I = (max_index > 15) ? 7 : max_index >> 1; 55262306a36Sopenharmony_ci L = max_index - I; 55362306a36Sopenharmony_ci scale_factor = 8; 55462306a36Sopenharmony_ci sum_y_sqr = 0; 55562306a36Sopenharmony_ci sum_y_quad = 0; 55662306a36Sopenharmony_ci x_tilde_abs = 0; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci for (i = 0; i <= L; i++) { 55962306a36Sopenharmony_ci unsigned int y_sqr; 56062306a36Sopenharmony_ci unsigned int y_quad; 56162306a36Sopenharmony_ci unsigned int tmp_abs; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* prevent division by zero */ 56462306a36Sopenharmony_ci if (y_est[i + I] == 0) 56562306a36Sopenharmony_ci return false; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci x_est_fxp1_nonlin = 56862306a36Sopenharmony_ci x_est[i + I] - ((1 << scale_factor) * y_est[i + I] + 56962306a36Sopenharmony_ci G_fxp) / G_fxp; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci x_tilde[i] = 57262306a36Sopenharmony_ci (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i + 57362306a36Sopenharmony_ci I]; 57462306a36Sopenharmony_ci x_tilde[i] = 57562306a36Sopenharmony_ci (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 57662306a36Sopenharmony_ci x_tilde[i] = 57762306a36Sopenharmony_ci (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 57862306a36Sopenharmony_ci y_sqr = 57962306a36Sopenharmony_ci (y_est[i + I] * y_est[i + I] + 58062306a36Sopenharmony_ci (scale_factor * scale_factor)) / (scale_factor * 58162306a36Sopenharmony_ci scale_factor); 58262306a36Sopenharmony_ci tmp_abs = abs(x_tilde[i]); 58362306a36Sopenharmony_ci if (tmp_abs > x_tilde_abs) 58462306a36Sopenharmony_ci x_tilde_abs = tmp_abs; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci y_quad = y_sqr * y_sqr; 58762306a36Sopenharmony_ci sum_y_sqr = sum_y_sqr + y_sqr; 58862306a36Sopenharmony_ci sum_y_quad = sum_y_quad + y_quad; 58962306a36Sopenharmony_ci B1_tmp[i] = y_sqr * (L + 1); 59062306a36Sopenharmony_ci B2_tmp[i] = y_sqr; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci B1_abs_max = 0; 59462306a36Sopenharmony_ci B2_abs_max = 0; 59562306a36Sopenharmony_ci for (i = 0; i <= L; i++) { 59662306a36Sopenharmony_ci int abs_val; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci B1_tmp[i] -= sum_y_sqr; 59962306a36Sopenharmony_ci B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i]; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci abs_val = abs(B1_tmp[i]); 60262306a36Sopenharmony_ci if (abs_val > B1_abs_max) 60362306a36Sopenharmony_ci B1_abs_max = abs_val; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci abs_val = abs(B2_tmp[i]); 60662306a36Sopenharmony_ci if (abs_val > B2_abs_max) 60762306a36Sopenharmony_ci B2_abs_max = abs_val; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci Q_x = find_proper_scale(find_expn(x_tilde_abs), 10); 61162306a36Sopenharmony_ci Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10); 61262306a36Sopenharmony_ci Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci beta_raw = 0; 61562306a36Sopenharmony_ci alpha_raw = 0; 61662306a36Sopenharmony_ci for (i = 0; i <= L; i++) { 61762306a36Sopenharmony_ci x_tilde[i] = x_tilde[i] / (1 << Q_x); 61862306a36Sopenharmony_ci B1_tmp[i] = B1_tmp[i] / (1 << Q_B1); 61962306a36Sopenharmony_ci B2_tmp[i] = B2_tmp[i] / (1 << Q_B2); 62062306a36Sopenharmony_ci beta_raw = beta_raw + B1_tmp[i] * x_tilde[i]; 62162306a36Sopenharmony_ci alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i]; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci scale_B = 62562306a36Sopenharmony_ci ((sum_y_quad / scale_factor) * (L + 1) - 62662306a36Sopenharmony_ci (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10); 62962306a36Sopenharmony_ci scale_B = scale_B / (1 << Q_scale_B); 63062306a36Sopenharmony_ci if (scale_B == 0) 63162306a36Sopenharmony_ci return false; 63262306a36Sopenharmony_ci Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 63362306a36Sopenharmony_ci Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 63462306a36Sopenharmony_ci beta_raw = beta_raw / (1 << Q_beta); 63562306a36Sopenharmony_ci alpha_raw = alpha_raw / (1 << Q_alpha); 63662306a36Sopenharmony_ci alpha = (alpha_raw << 10) / scale_B; 63762306a36Sopenharmony_ci beta = (beta_raw << 10) / scale_B; 63862306a36Sopenharmony_ci order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B; 63962306a36Sopenharmony_ci order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B; 64062306a36Sopenharmony_ci order1_5x = order_1 / 5; 64162306a36Sopenharmony_ci order2_3x = order_2 / 3; 64262306a36Sopenharmony_ci order1_5x_rem = order_1 - 5 * order1_5x; 64362306a36Sopenharmony_ci order2_3x_rem = order_2 - 3 * order2_3x; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci for (i = 0; i < PAPRD_TABLE_SZ; i++) { 64662306a36Sopenharmony_ci tmp = i * 32; 64762306a36Sopenharmony_ci y5 = ((beta * tmp) >> 6) >> order1_5x; 64862306a36Sopenharmony_ci y5 = (y5 * tmp) >> order1_5x; 64962306a36Sopenharmony_ci y5 = (y5 * tmp) >> order1_5x; 65062306a36Sopenharmony_ci y5 = (y5 * tmp) >> order1_5x; 65162306a36Sopenharmony_ci y5 = (y5 * tmp) >> order1_5x; 65262306a36Sopenharmony_ci y5 = y5 >> order1_5x_rem; 65362306a36Sopenharmony_ci y3 = (alpha * tmp) >> order2_3x; 65462306a36Sopenharmony_ci y3 = (y3 * tmp) >> order2_3x; 65562306a36Sopenharmony_ci y3 = (y3 * tmp) >> order2_3x; 65662306a36Sopenharmony_ci y3 = y3 >> order2_3x_rem; 65762306a36Sopenharmony_ci PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (i >= 2) { 66062306a36Sopenharmony_ci tmp = PA_in[i] - PA_in[i - 1]; 66162306a36Sopenharmony_ci if (tmp < 0) 66262306a36Sopenharmony_ci PA_in[i] = 66362306a36Sopenharmony_ci PA_in[i - 1] + (PA_in[i - 1] - 66462306a36Sopenharmony_ci PA_in[i - 2]); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci beta_raw = 0; 67162306a36Sopenharmony_ci alpha_raw = 0; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci for (i = 0; i <= L; i++) { 67462306a36Sopenharmony_ci int theta_tilde = 67562306a36Sopenharmony_ci ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I]; 67662306a36Sopenharmony_ci theta_tilde = 67762306a36Sopenharmony_ci ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 67862306a36Sopenharmony_ci theta_tilde = 67962306a36Sopenharmony_ci ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 68062306a36Sopenharmony_ci beta_raw = beta_raw + B1_tmp[i] * theta_tilde; 68162306a36Sopenharmony_ci alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 68562306a36Sopenharmony_ci Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 68662306a36Sopenharmony_ci beta_raw = beta_raw / (1 << Q_beta); 68762306a36Sopenharmony_ci alpha_raw = alpha_raw / (1 << Q_alpha); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci alpha = (alpha_raw << 10) / scale_B; 69062306a36Sopenharmony_ci beta = (beta_raw << 10) / scale_B; 69162306a36Sopenharmony_ci order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5; 69262306a36Sopenharmony_ci order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5; 69362306a36Sopenharmony_ci order1_5x = order_1 / 5; 69462306a36Sopenharmony_ci order2_3x = order_2 / 3; 69562306a36Sopenharmony_ci order1_5x_rem = order_1 - 5 * order1_5x; 69662306a36Sopenharmony_ci order2_3x_rem = order_2 - 3 * order2_3x; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci for (i = 0; i < PAPRD_TABLE_SZ; i++) { 69962306a36Sopenharmony_ci int PA_angle; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* pa_table[4] is calculated from PA_angle for i=5 */ 70262306a36Sopenharmony_ci if (i == 4) 70362306a36Sopenharmony_ci continue; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci tmp = i * 32; 70662306a36Sopenharmony_ci if (beta > 0) 70762306a36Sopenharmony_ci y5 = (((beta * tmp - 64) >> 6) - 70862306a36Sopenharmony_ci (1 << order1_5x)) / (1 << order1_5x); 70962306a36Sopenharmony_ci else 71062306a36Sopenharmony_ci y5 = ((((beta * tmp - 64) >> 6) + 71162306a36Sopenharmony_ci (1 << order1_5x)) / (1 << order1_5x)); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci y5 = (y5 * tmp) / (1 << order1_5x); 71462306a36Sopenharmony_ci y5 = (y5 * tmp) / (1 << order1_5x); 71562306a36Sopenharmony_ci y5 = (y5 * tmp) / (1 << order1_5x); 71662306a36Sopenharmony_ci y5 = (y5 * tmp) / (1 << order1_5x); 71762306a36Sopenharmony_ci y5 = y5 / (1 << order1_5x_rem); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (beta > 0) 72062306a36Sopenharmony_ci y3 = (alpha * tmp - 72162306a36Sopenharmony_ci (1 << order2_3x)) / (1 << order2_3x); 72262306a36Sopenharmony_ci else 72362306a36Sopenharmony_ci y3 = (alpha * tmp + 72462306a36Sopenharmony_ci (1 << order2_3x)) / (1 << order2_3x); 72562306a36Sopenharmony_ci y3 = (y3 * tmp) / (1 << order2_3x); 72662306a36Sopenharmony_ci y3 = (y3 * tmp) / (1 << order2_3x); 72762306a36Sopenharmony_ci y3 = y3 / (1 << order2_3x_rem); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (i < 4) { 73062306a36Sopenharmony_ci PA_angle = 0; 73162306a36Sopenharmony_ci } else { 73262306a36Sopenharmony_ci PA_angle = y5 + y3; 73362306a36Sopenharmony_ci if (PA_angle < -150) 73462306a36Sopenharmony_ci PA_angle = -150; 73562306a36Sopenharmony_ci else if (PA_angle > 150) 73662306a36Sopenharmony_ci PA_angle = 150; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff); 74062306a36Sopenharmony_ci if (i == 5) { 74162306a36Sopenharmony_ci PA_angle = (PA_angle + 2) >> 1; 74262306a36Sopenharmony_ci pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) + 74362306a36Sopenharmony_ci (PA_angle & 0x7ff); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci *gain = G_fxp; 74862306a36Sopenharmony_ci return true; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_civoid ar9003_paprd_populate_single_table(struct ath_hw *ah, 75262306a36Sopenharmony_ci struct ath9k_hw_cal_data *caldata, 75362306a36Sopenharmony_ci int chain) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci u32 *paprd_table_val = caldata->pa_table[chain]; 75662306a36Sopenharmony_ci u32 small_signal_gain = caldata->small_signal_gain[chain]; 75762306a36Sopenharmony_ci u32 training_power = ah->paprd_training_power; 75862306a36Sopenharmony_ci u32 reg = 0; 75962306a36Sopenharmony_ci int i; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (chain == 0) 76262306a36Sopenharmony_ci reg = AR_PHY_PAPRD_MEM_TAB_B0; 76362306a36Sopenharmony_ci else if (chain == 1) 76462306a36Sopenharmony_ci reg = AR_PHY_PAPRD_MEM_TAB_B1; 76562306a36Sopenharmony_ci else if (chain == 2) 76662306a36Sopenharmony_ci reg = AR_PHY_PAPRD_MEM_TAB_B2; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci for (i = 0; i < PAPRD_TABLE_SZ; i++) { 76962306a36Sopenharmony_ci REG_WRITE(ah, reg, paprd_table_val[i]); 77062306a36Sopenharmony_ci reg = reg + 4; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (chain == 0) 77462306a36Sopenharmony_ci reg = AR_PHY_PA_GAIN123_B0; 77562306a36Sopenharmony_ci else if (chain == 1) 77662306a36Sopenharmony_ci reg = AR_PHY_PA_GAIN123_B1; 77762306a36Sopenharmony_ci else 77862306a36Sopenharmony_ci reg = AR_PHY_PA_GAIN123_B2; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0, 78362306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 78462306a36Sopenharmony_ci training_power); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (ah->caps.tx_chainmask & BIT(1)) 78762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1, 78862306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 78962306a36Sopenharmony_ci training_power); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (ah->caps.tx_chainmask & BIT(2)) 79262306a36Sopenharmony_ci /* val AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL correct? */ 79362306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2, 79462306a36Sopenharmony_ci AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 79562306a36Sopenharmony_ci training_power); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ciEXPORT_SYMBOL(ar9003_paprd_populate_single_table); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_civoid ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci unsigned int i, desired_gain, gain_index; 80262306a36Sopenharmony_ci unsigned int train_power = ah->paprd_training_power; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci desired_gain = ar9003_get_desired_gain(ah, chain, train_power); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci gain_index = 0; 80762306a36Sopenharmony_ci for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { 80862306a36Sopenharmony_ci if (ah->paprd_gain_table_index[i] >= desired_gain) 80962306a36Sopenharmony_ci break; 81062306a36Sopenharmony_ci gain_index++; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci ar9003_tx_force_gain(ah, gain_index); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 81662306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ciEXPORT_SYMBOL(ar9003_paprd_setup_gain_table); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah, 82162306a36Sopenharmony_ci struct ath9k_hw_cal_data *caldata, 82262306a36Sopenharmony_ci int chain) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci u32 *pa_in = caldata->pa_table[chain]; 82562306a36Sopenharmony_ci int capdiv_offset, quick_drop_offset; 82662306a36Sopenharmony_ci int capdiv2g, quick_drop; 82762306a36Sopenharmony_ci int count = 0; 82862306a36Sopenharmony_ci int i; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah)) 83162306a36Sopenharmony_ci return false; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, 83462306a36Sopenharmony_ci AR_PHY_65NM_CH0_TXRF3_CAPDIV2G); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 83762306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (quick_drop) 84062306a36Sopenharmony_ci quick_drop -= 0x40; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci for (i = 0; i < NUM_BIN + 1; i++) { 84362306a36Sopenharmony_ci if (pa_in[i] == 1400) 84462306a36Sopenharmony_ci count++; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (AR_SREV_9485(ah)) { 84862306a36Sopenharmony_ci if (pa_in[23] < 800) { 84962306a36Sopenharmony_ci capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150); 85062306a36Sopenharmony_ci capdiv2g += capdiv_offset; 85162306a36Sopenharmony_ci if (capdiv2g > 7) { 85262306a36Sopenharmony_ci capdiv2g = 7; 85362306a36Sopenharmony_ci if (pa_in[23] < 600) { 85462306a36Sopenharmony_ci quick_drop++; 85562306a36Sopenharmony_ci if (quick_drop > 0) 85662306a36Sopenharmony_ci quick_drop = 0; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci } else if (pa_in[23] == 1400) { 86062306a36Sopenharmony_ci quick_drop_offset = min_t(int, count / 3, 2); 86162306a36Sopenharmony_ci quick_drop += quick_drop_offset; 86262306a36Sopenharmony_ci capdiv2g += quick_drop_offset / 2; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (capdiv2g > 7) 86562306a36Sopenharmony_ci capdiv2g = 7; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (quick_drop > 0) { 86862306a36Sopenharmony_ci quick_drop = 0; 86962306a36Sopenharmony_ci capdiv2g -= quick_drop_offset; 87062306a36Sopenharmony_ci if (capdiv2g < 0) 87162306a36Sopenharmony_ci capdiv2g = 0; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci } else { 87462306a36Sopenharmony_ci return false; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci } else if (AR_SREV_9330(ah)) { 87762306a36Sopenharmony_ci if (pa_in[23] < 1000) { 87862306a36Sopenharmony_ci capdiv_offset = (1000 - pa_in[23]) / 100; 87962306a36Sopenharmony_ci capdiv2g += capdiv_offset; 88062306a36Sopenharmony_ci if (capdiv_offset > 3) { 88162306a36Sopenharmony_ci capdiv_offset = 1; 88262306a36Sopenharmony_ci quick_drop--; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci capdiv2g += capdiv_offset; 88662306a36Sopenharmony_ci if (capdiv2g > 6) 88762306a36Sopenharmony_ci capdiv2g = 6; 88862306a36Sopenharmony_ci if (quick_drop < -4) 88962306a36Sopenharmony_ci quick_drop = -4; 89062306a36Sopenharmony_ci } else if (pa_in[23] == 1400) { 89162306a36Sopenharmony_ci if (count > 3) { 89262306a36Sopenharmony_ci quick_drop++; 89362306a36Sopenharmony_ci capdiv2g -= count / 4; 89462306a36Sopenharmony_ci if (quick_drop > -2) 89562306a36Sopenharmony_ci quick_drop = -2; 89662306a36Sopenharmony_ci } else { 89762306a36Sopenharmony_ci capdiv2g--; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (capdiv2g < 0) 90162306a36Sopenharmony_ci capdiv2g = 0; 90262306a36Sopenharmony_ci } else { 90362306a36Sopenharmony_ci return false; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, 90862306a36Sopenharmony_ci AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g); 90962306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), 91062306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, 91162306a36Sopenharmony_ci quick_drop); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci return true; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ciint ar9003_paprd_create_curve(struct ath_hw *ah, 91762306a36Sopenharmony_ci struct ath9k_hw_cal_data *caldata, int chain) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci u16 *small_signal_gain = &caldata->small_signal_gain[chain]; 92062306a36Sopenharmony_ci u32 *pa_table = caldata->pa_table[chain]; 92162306a36Sopenharmony_ci u32 *data_L, *data_U; 92262306a36Sopenharmony_ci int i, status = 0; 92362306a36Sopenharmony_ci u32 *buf; 92462306a36Sopenharmony_ci u32 reg; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci buf = kmalloc_array(2 * 48, sizeof(u32), GFP_KERNEL); 92962306a36Sopenharmony_ci if (!buf) 93062306a36Sopenharmony_ci return -ENOMEM; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci data_L = &buf[0]; 93362306a36Sopenharmony_ci data_U = &buf[48]; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY(ah), 93662306a36Sopenharmony_ci AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci reg = AR_PHY_CHAN_INFO_TAB_0; 93962306a36Sopenharmony_ci for (i = 0; i < 48; i++) 94062306a36Sopenharmony_ci data_L[i] = REG_READ(ah, reg + (i << 2)); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY(ah), 94362306a36Sopenharmony_ci AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci for (i = 0; i < 48; i++) 94662306a36Sopenharmony_ci data_U[i] = REG_READ(ah, reg + (i << 2)); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain)) 94962306a36Sopenharmony_ci status = -2; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (ar9003_paprd_retrain_pa_in(ah, caldata, chain)) 95262306a36Sopenharmony_ci status = -EINPROGRESS; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 95562306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci kfree(buf); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci return status; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ciEXPORT_SYMBOL(ar9003_paprd_create_curve); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ciint ar9003_paprd_init_table(struct ath_hw *ah) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci int ret; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci ret = ar9003_paprd_setup_single_table(ah); 96862306a36Sopenharmony_ci if (ret < 0) 96962306a36Sopenharmony_ci return ret; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci ar9003_paprd_get_gain_table(ah); 97262306a36Sopenharmony_ci return 0; 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ciEXPORT_SYMBOL(ar9003_paprd_init_table); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cibool ar9003_paprd_is_done(struct ath_hw *ah) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci int paprd_done, agc2_pwr; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci paprd_done = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 98162306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (AR_SREV_9485(ah)) 98462306a36Sopenharmony_ci goto exit; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (paprd_done == 0x1) { 98762306a36Sopenharmony_ci agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), 98862306a36Sopenharmony_ci AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 99162306a36Sopenharmony_ci "AGC2_PWR = 0x%x training done = 0x%x\n", 99262306a36Sopenharmony_ci agc2_pwr, paprd_done); 99362306a36Sopenharmony_ci /* 99462306a36Sopenharmony_ci * agc2_pwr range should not be less than 'IDEAL_AGC2_PWR_CHANGE' 99562306a36Sopenharmony_ci * when the training is completely done, otherwise retraining is 99662306a36Sopenharmony_ci * done to make sure the value is in ideal range 99762306a36Sopenharmony_ci */ 99862306a36Sopenharmony_ci if (agc2_pwr <= PAPRD_IDEAL_AGC2_PWR_RANGE) 99962306a36Sopenharmony_ci paprd_done = 0; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ciexit: 100262306a36Sopenharmony_ci return !!paprd_done; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ciEXPORT_SYMBOL(ar9003_paprd_is_done); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cibool ar9003_is_paprd_enabled(struct ath_hw *ah) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci if ((ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->config.enable_paprd) 100962306a36Sopenharmony_ci return true; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci return false; 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ciEXPORT_SYMBOL(ar9003_is_paprd_enabled); 1014