2010-06-12 00:34:00 -04:00
/*
2011-05-17 13:36:18 +05:30
* Copyright ( c ) 2010 - 2011 Atheros Communications Inc .
2010-06-12 00:34:00 -04:00
*
* 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 .
*/
2011-05-27 16:14:23 -04:00
# include <linux/export.h>
2010-06-12 00:34:00 -04:00
# include "hw.h"
# include "ar9003_phy.h"
void ar9003_paprd_enable ( struct ath_hw * ah , bool val )
{
2010-12-15 07:30:53 -08:00
struct ath9k_channel * chan = ah - > curchan ;
2011-07-08 13:01:32 +05:30
struct ar9300_eeprom * eep = & ah - > eeprom . ar9300_eep ;
/*
* 3 bits for modalHeader5G . papdRateMaskHt20
* is used for sub - band disabling of PAPRD .
* 5 G band is divided into 3 sub - bands - - upper ,
* middle , lower .
* if bit 30 of modalHeader5G . papdRateMaskHt20 is set
* - - disable PAPRD for upper band 5 GHz
* if bit 29 of modalHeader5G . papdRateMaskHt20 is set
* - - disable PAPRD for middle band 5 GHz
* if bit 28 of modalHeader5G . papdRateMaskHt20 is set
* - - disable PAPRD for lower band 5 GHz
*/
if ( IS_CHAN_5GHZ ( chan ) ) {
if ( chan - > channel > = UPPER_5G_SUB_BAND_START ) {
if ( le32_to_cpu ( eep - > modalHeader5G . papdRateMaskHt20 )
& BIT ( 30 ) )
val = false ;
} else if ( chan - > channel > = MID_5G_SUB_BAND_START ) {
if ( le32_to_cpu ( eep - > modalHeader5G . papdRateMaskHt20 )
& BIT ( 29 ) )
val = false ;
} else {
if ( le32_to_cpu ( eep - > modalHeader5G . papdRateMaskHt20 )
& BIT ( 28 ) )
val = false ;
}
}
2010-12-15 07:30:53 -08:00
if ( val ) {
ah - > paprd_table_write_done = true ;
2012-04-15 20:38:05 +02:00
ath9k_hw_apply_txpower ( ah , chan , false ) ;
2010-12-15 07:30:53 -08:00
}
2010-06-12 00:34:00 -04:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_CTRL0_B0 ,
AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE , ! ! val ) ;
2010-12-06 04:27:58 -08:00
if ( ah - > caps . tx_chainmask & BIT ( 1 ) )
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_CTRL0_B1 ,
AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE , ! ! val ) ;
if ( ah - > caps . tx_chainmask & BIT ( 2 ) )
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_CTRL0_B2 ,
AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE , ! ! val ) ;
2010-06-12 00:34:00 -04:00
}
EXPORT_SYMBOL ( ar9003_paprd_enable ) ;
2010-12-13 08:40:54 +01:00
static int ar9003_get_training_power_2g ( struct ath_hw * ah )
2010-06-12 00:34:00 -04:00
{
2011-06-06 23:02:33 +05:30
struct ath9k_channel * chan = ah - > curchan ;
2010-12-13 08:40:54 +01:00
unsigned int power , scale , delta ;
2011-06-06 23:02:33 +05:30
scale = ar9003_get_paprd_scale_factor ( ah , chan ) ;
2010-12-13 08:40:54 +01:00
power = REG_READ_FIELD ( ah , AR_PHY_POWERTX_RATE5 ,
AR_PHY_POWERTX_RATE5_POWERTXHT20_0 ) ;
delta = abs ( ( int ) ah - > paprd_target_power - ( int ) power ) ;
if ( delta > scale )
return - 1 ;
if ( delta < 4 )
power - = 4 - delta ;
return power ;
}
static int ar9003_get_training_power_5g ( struct ath_hw * ah )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
struct ath9k_channel * chan = ah - > curchan ;
unsigned int power , scale , delta ;
2011-06-06 23:02:33 +05:30
scale = ar9003_get_paprd_scale_factor ( ah , chan ) ;
2010-12-13 08:40:54 +01:00
if ( IS_CHAN_HT40 ( chan ) )
power = REG_READ_FIELD ( ah , AR_PHY_POWERTX_RATE8 ,
AR_PHY_POWERTX_RATE8_POWERTXHT40_5 ) ;
else
power = REG_READ_FIELD ( ah , AR_PHY_POWERTX_RATE6 ,
AR_PHY_POWERTX_RATE6_POWERTXHT20_5 ) ;
power + = scale ;
delta = abs ( ( int ) ah - > paprd_target_power - ( int ) power ) ;
if ( delta > scale )
return - 1 ;
2011-09-03 01:40:23 +02:00
switch ( get_streams ( ah - > txchainmask ) ) {
2011-06-21 14:51:46 +05:30
case 1 :
delta = 6 ;
break ;
case 2 :
delta = 4 ;
break ;
case 3 :
delta = 2 ;
break ;
default :
delta = 0 ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " Invalid tx-chainmask: %u \n " ,
ah - > txchainmask ) ;
2011-06-21 14:51:46 +05:30
}
power + = delta ;
2010-12-13 08:40:54 +01:00
return power ;
}
static int ar9003_paprd_setup_single_table ( struct ath_hw * ah )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
2010-11-20 18:38:53 -08:00
static const u32 ctrl0 [ 3 ] = {
2010-06-12 00:34:00 -04:00
AR_PHY_PAPRD_CTRL0_B0 ,
AR_PHY_PAPRD_CTRL0_B1 ,
AR_PHY_PAPRD_CTRL0_B2
} ;
2010-11-20 18:38:53 -08:00
static const u32 ctrl1 [ 3 ] = {
2010-06-12 00:34:00 -04:00
AR_PHY_PAPRD_CTRL1_B0 ,
AR_PHY_PAPRD_CTRL1_B1 ,
AR_PHY_PAPRD_CTRL1_B2
} ;
2010-12-13 08:40:54 +01:00
int training_power ;
2011-09-13 22:38:18 +05:30
int i , val ;
2012-08-27 17:00:04 +02:00
u32 am2pm_mask = ah - > paprd_ratemask ;
2010-06-12 00:34:00 -04:00
2010-12-13 08:40:54 +01:00
if ( IS_CHAN_2GHZ ( ah - > curchan ) )
training_power = ar9003_get_training_power_2g ( ah ) ;
else
training_power = ar9003_get_training_power_5g ( ah ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " Training power: %d, Target power: %d \n " ,
2011-05-26 11:41:13 +05:30
training_power , ah - > paprd_target_power ) ;
2010-12-13 08:40:54 +01:00
if ( training_power < 0 ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
" PAPRD target power delta out of range \n " ) ;
2010-12-13 08:40:54 +01:00
return - ERANGE ;
}
ah - > paprd_training_power = training_power ;
2012-08-27 17:00:04 +02:00
if ( AR_SREV_9330 ( ah ) )
am2pm_mask = 0 ;
2010-12-15 07:30:52 -08:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_AM2AM , AR_PHY_PAPRD_AM2AM_MASK ,
ah - > paprd_ratemask ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_AM2PM , AR_PHY_PAPRD_AM2PM_MASK ,
2012-08-27 17:00:04 +02:00
am2pm_mask ) ;
2010-12-15 07:30:52 -08:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_HT40 , AR_PHY_PAPRD_HT40_MASK ,
2010-12-19 00:31:54 +01:00
ah - > paprd_ratemask_ht40 ) ;
2010-06-12 00:34:00 -04:00
2012-12-10 07:22:33 +05:30
ath_dbg ( common , CALIBRATE , " PAPRD HT20 mask: 0x%x, HT40 mask: 0x%x \n " ,
ah - > paprd_ratemask , ah - > paprd_ratemask_ht40 ) ;
2010-12-06 04:27:58 -08:00
for ( i = 0 ; i < ah - > caps . max_txchains ; i + + ) {
2010-06-12 00:34:00 -04:00
REG_RMW_FIELD ( ah , ctrl0 [ i ] ,
AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK , 1 ) ;
REG_RMW_FIELD ( ah , ctrl1 [ i ] ,
AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE , 1 ) ;
REG_RMW_FIELD ( ah , ctrl1 [ i ] ,
AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE , 1 ) ;
REG_RMW_FIELD ( ah , ctrl1 [ i ] ,
AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA , 0 ) ;
REG_RMW_FIELD ( ah , ctrl1 [ i ] ,
AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK , 181 ) ;
REG_RMW_FIELD ( ah , ctrl1 [ i ] ,
AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT , 361 ) ;
REG_RMW_FIELD ( ah , ctrl1 [ i ] ,
AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA , 0 ) ;
REG_RMW_FIELD ( ah , ctrl0 [ i ] ,
AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH , 3 ) ;
}
ar9003_paprd_enable ( ah , false ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL1 ,
AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP , 0x30 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL1 ,
AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE , 1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL1 ,
AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE , 1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL1 ,
AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE , 0 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL1 ,
AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE , 0 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL1 ,
AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING , 28 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL1 ,
AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE , 1 ) ;
2012-12-10 07:22:32 +05:30
if ( AR_SREV_9485 ( ah ) ) {
val = 148 ;
} else {
if ( IS_CHAN_2GHZ ( ah - > curchan ) ) {
if ( AR_SREV_9462 ( ah ) | | AR_SREV_9565 ( ah ) )
val = 145 ;
else
val = 147 ;
} else {
val = 137 ;
}
}
2010-06-12 00:34:00 -04:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL2 ,
2011-09-13 22:38:18 +05:30
AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN , val ) ;
2010-06-12 00:34:00 -04:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN , 4 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN , 4 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES , 7 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL , 1 ) ;
2012-12-10 07:22:32 +05:30
if ( AR_SREV_9485 ( ah ) | |
AR_SREV_9462 ( ah ) | |
AR_SREV_9565 ( ah ) | |
AR_SREV_9550 ( ah ) | |
AR_SREV_9330 ( ah ) | |
AR_SREV_9340 ( ah ) )
2010-12-06 04:27:58 -08:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
2012-12-10 07:22:32 +05:30
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP , - 3 ) ;
2010-12-06 04:27:58 -08:00
else
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
2012-12-10 07:22:32 +05:30
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP , - 6 ) ;
val = - 10 ;
if ( IS_CHAN_2GHZ ( ah - > curchan ) & & ! AR_SREV_9462 ( ah ) & & ! AR_SREV_9565 ( ah ) )
val = - 15 ;
2010-06-12 00:34:00 -04:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE ,
2011-09-13 22:38:18 +05:30
val ) ;
2010-06-12 00:34:00 -04:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE , 1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL4 ,
AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA , 0 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL4 ,
AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR , 400 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL4 ,
AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES ,
100 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_PRE_POST_SCALE_0_B0 ,
AR_PHY_PAPRD_PRE_POST_SCALING , 261376 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_PRE_POST_SCALE_1_B0 ,
AR_PHY_PAPRD_PRE_POST_SCALING , 248079 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_PRE_POST_SCALE_2_B0 ,
AR_PHY_PAPRD_PRE_POST_SCALING , 233759 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_PRE_POST_SCALE_3_B0 ,
AR_PHY_PAPRD_PRE_POST_SCALING , 220464 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_PRE_POST_SCALE_4_B0 ,
AR_PHY_PAPRD_PRE_POST_SCALING , 208194 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_PRE_POST_SCALE_5_B0 ,
AR_PHY_PAPRD_PRE_POST_SCALING , 196949 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_PRE_POST_SCALE_6_B0 ,
AR_PHY_PAPRD_PRE_POST_SCALING , 185706 ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_PRE_POST_SCALE_7_B0 ,
AR_PHY_PAPRD_PRE_POST_SCALING , 175487 ) ;
2010-12-13 08:40:54 +01:00
return 0 ;
2010-06-12 00:34:00 -04:00
}
static void ar9003_paprd_get_gain_table ( struct ath_hw * ah )
{
u32 * entry = ah - > paprd_gain_table_entries ;
u8 * index = ah - > paprd_gain_table_index ;
u32 reg = AR_PHY_TXGAIN_TABLE ;
int i ;
2011-06-23 20:14:29 +05:30
for ( i = 0 ; i < PAPRD_GAIN_TABLE_ENTRIES ; i + + ) {
2010-06-12 00:34:00 -04:00
entry [ i ] = REG_READ ( ah , reg ) ;
index [ i ] = ( entry [ i ] > > 24 ) & 0xff ;
reg + = 4 ;
}
}
static unsigned int ar9003_get_desired_gain ( struct ath_hw * ah , int chain ,
int target_power )
{
2011-06-23 20:03:38 +05:30
int olpc_gain_delta = 0 , cl_gain_mod ;
2010-06-12 00:34:00 -04:00
int alpha_therm , alpha_volt ;
int therm_cal_value , volt_cal_value ;
int therm_value , volt_value ;
int thermal_gain_corr , voltage_gain_corr ;
int desired_scale , desired_gain = 0 ;
2011-06-23 20:03:38 +05:30
u32 reg_olpc = 0 , reg_cl_gain = 0 ;
2010-06-12 00:34:00 -04:00
REG_CLR_BIT ( ah , AR_PHY_PAPRD_TRAINER_STAT1 ,
AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE ) ;
desired_scale = REG_READ_FIELD ( ah , AR_PHY_TPC_12 ,
AR_PHY_TPC_12_DESIRED_SCALE_HT40_5 ) ;
alpha_therm = REG_READ_FIELD ( ah , AR_PHY_TPC_19 ,
AR_PHY_TPC_19_ALPHA_THERM ) ;
alpha_volt = REG_READ_FIELD ( ah , AR_PHY_TPC_19 ,
AR_PHY_TPC_19_ALPHA_VOLT ) ;
therm_cal_value = REG_READ_FIELD ( ah , AR_PHY_TPC_18 ,
AR_PHY_TPC_18_THERM_CAL_VALUE ) ;
volt_cal_value = REG_READ_FIELD ( ah , AR_PHY_TPC_18 ,
AR_PHY_TPC_18_VOLT_CAL_VALUE ) ;
therm_value = REG_READ_FIELD ( ah , AR_PHY_BB_THERM_ADC_4 ,
AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE ) ;
volt_value = REG_READ_FIELD ( ah , AR_PHY_BB_THERM_ADC_4 ,
AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE ) ;
2011-06-23 20:03:38 +05:30
switch ( chain ) {
case 0 :
reg_olpc = AR_PHY_TPC_11_B0 ;
reg_cl_gain = AR_PHY_CL_TAB_0 ;
break ;
case 1 :
reg_olpc = AR_PHY_TPC_11_B1 ;
reg_cl_gain = AR_PHY_CL_TAB_1 ;
break ;
case 2 :
reg_olpc = AR_PHY_TPC_11_B2 ;
reg_cl_gain = AR_PHY_CL_TAB_2 ;
break ;
default :
2011-12-15 14:55:53 -08:00
ath_dbg ( ath9k_hw_common ( ah ) , CALIBRATE ,
" Invalid chainmask: %d \n " , chain ) ;
2011-06-23 20:03:38 +05:30
break ;
}
2010-06-12 00:34:00 -04:00
2011-06-23 20:03:38 +05:30
olpc_gain_delta = REG_READ_FIELD ( ah , reg_olpc ,
2010-06-12 00:34:00 -04:00
AR_PHY_TPC_11_OLPC_GAIN_DELTA ) ;
2011-06-23 20:03:38 +05:30
cl_gain_mod = REG_READ_FIELD ( ah , reg_cl_gain ,
AR_PHY_CL_TAB_CL_GAIN_MOD ) ;
2010-06-12 00:34:00 -04:00
if ( olpc_gain_delta > = 128 )
olpc_gain_delta = olpc_gain_delta - 256 ;
thermal_gain_corr = ( alpha_therm * ( therm_value - therm_cal_value ) +
( 256 / 2 ) ) / 256 ;
voltage_gain_corr = ( alpha_volt * ( volt_value - volt_cal_value ) +
( 128 / 2 ) ) / 128 ;
desired_gain = target_power - olpc_gain_delta - thermal_gain_corr -
2011-06-23 20:03:38 +05:30
voltage_gain_corr + desired_scale + cl_gain_mod ;
2010-06-12 00:34:00 -04:00
return desired_gain ;
}
static void ar9003_tx_force_gain ( struct ath_hw * ah , unsigned int gain_index )
{
int selected_gain_entry , txbb1dbgain , txbb6dbgain , txmxrgain ;
int padrvgnA , padrvgnB , padrvgnC , padrvgnD ;
u32 * gain_table_entries = ah - > paprd_gain_table_entries ;
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 ;
padrvgnA = ( selected_gain_entry > > 9 ) & 0xf ;
padrvgnB = ( selected_gain_entry > > 13 ) & 0xf ;
padrvgnC = ( selected_gain_entry > > 17 ) & 0xf ;
padrvgnD = ( selected_gain_entry > > 21 ) & 0x3 ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN , txbb1dbgain ) ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN , txbb6dbgain ) ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN , txmxrgain ) ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA , padrvgnA ) ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB , padrvgnB ) ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC , padrvgnC ) ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND , padrvgnD ) ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL , 0 ) ;
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN , 0 ) ;
REG_RMW_FIELD ( ah , AR_PHY_TPC_1 , AR_PHY_TPC_1_FORCED_DAC_GAIN , 0 ) ;
REG_RMW_FIELD ( ah , AR_PHY_TPC_1 , AR_PHY_TPC_1_FORCE_DAC_GAIN , 0 ) ;
}
static inline int find_expn ( int num )
{
return fls ( num ) - 1 ;
}
static inline int find_proper_scale ( int expn , int N )
{
return ( expn > N ) ? expn - 10 : 0 ;
}
# define NUM_BIN 23
static bool create_pa_curve ( u32 * data_L , u32 * data_U , u32 * pa_table , u16 * gain )
{
unsigned int thresh_accum_cnt ;
int x_est [ NUM_BIN + 1 ] , Y [ NUM_BIN + 1 ] , theta [ NUM_BIN + 1 ] ;
int PA_in [ NUM_BIN + 1 ] ;
int B1_tmp [ NUM_BIN + 1 ] , B2_tmp [ NUM_BIN + 1 ] ;
unsigned int B1_abs_max , B2_abs_max ;
int max_index , scale_factor ;
int y_est [ NUM_BIN + 1 ] ;
int x_est_fxp1_nonlin , x_tilde [ NUM_BIN + 1 ] ;
unsigned int x_tilde_abs ;
int G_fxp , Y_intercept , order_x_by_y , M , I , L , sum_y_sqr , sum_y_quad ;
int Q_x , Q_B1 , Q_B2 , beta_raw , alpha_raw , scale_B ;
int Q_scale_B , Q_beta , Q_alpha , alpha , beta , order_1 , order_2 ;
int order1_5x , order2_3x , order1_5x_rem , order2_3x_rem ;
int y5 , y3 , tmp ;
int theta_low_bin = 0 ;
int i ;
/* disregard any bin that contains <= 16 samples */
thresh_accum_cnt = 16 ;
scale_factor = 5 ;
max_index = 0 ;
memset ( theta , 0 , sizeof ( theta ) ) ;
memset ( x_est , 0 , sizeof ( x_est ) ) ;
memset ( Y , 0 , sizeof ( Y ) ) ;
memset ( y_est , 0 , sizeof ( y_est ) ) ;
memset ( x_tilde , 0 , sizeof ( x_tilde ) ) ;
for ( i = 0 ; i < NUM_BIN ; i + + ) {
s32 accum_cnt , accum_tx , accum_rx , accum_ang ;
/* number of samples */
accum_cnt = data_L [ i ] & 0xffff ;
if ( accum_cnt < = thresh_accum_cnt )
continue ;
/* sum(tx amplitude) */
accum_tx = ( ( data_L [ i ] > > 16 ) & 0xffff ) |
( ( data_U [ i ] & 0x7ff ) < < 16 ) ;
/* sum(rx amplitude distance to lower bin edge) */
accum_rx = ( ( data_U [ i ] > > 11 ) & 0x1f ) |
( ( data_L [ i + 23 ] & 0xffff ) < < 5 ) ;
/* sum(angles) */
accum_ang = ( ( data_L [ i + 23 ] > > 16 ) & 0xffff ) |
( ( data_U [ i + 23 ] & 0x7ff ) < < 16 ) ;
accum_tx < < = scale_factor ;
accum_rx < < = scale_factor ;
x_est [ i + 1 ] = ( ( ( accum_tx + accum_cnt ) / accum_cnt ) + 32 ) > >
scale_factor ;
Y [ i + 1 ] = ( ( ( ( accum_rx + accum_cnt ) / accum_cnt ) + 32 ) > >
scale_factor ) +
( 1 < < scale_factor ) * max_index + 16 ;
if ( accum_ang > = ( 1 < < 26 ) )
accum_ang - = 1 < < 27 ;
theta [ i + 1 ] = ( ( accum_ang * ( 1 < < scale_factor ) ) + accum_cnt ) /
accum_cnt ;
max_index + + ;
}
/*
* Find average theta of first 5 bin and all of those to same value .
* Curve is linear at that range .
*/
for ( i = 1 ; i < 6 ; i + + )
theta_low_bin + = theta [ i ] ;
theta_low_bin = theta_low_bin / 5 ;
for ( i = 1 ; i < 6 ; i + + )
theta [ i ] = theta_low_bin ;
/* Set values at origin */
theta [ 0 ] = theta_low_bin ;
for ( i = 0 ; i < = max_index ; i + + )
theta [ i ] - = theta_low_bin ;
x_est [ 0 ] = 0 ;
Y [ 0 ] = 0 ;
scale_factor = 8 ;
/* low signal gain */
if ( x_est [ 6 ] = = x_est [ 3 ] )
return false ;
G_fxp =
( ( ( Y [ 6 ] - Y [ 3 ] ) * 1 < < scale_factor ) +
( x_est [ 6 ] - x_est [ 3 ] ) ) / ( x_est [ 6 ] - x_est [ 3 ] ) ;
2010-10-19 20:01:41 +05:30
/* prevent division by zero */
if ( G_fxp = = 0 )
return false ;
2010-06-12 00:34:00 -04:00
Y_intercept =
( G_fxp * ( x_est [ 0 ] - x_est [ 3 ] ) +
( 1 < < scale_factor ) ) / ( 1 < < scale_factor ) + Y [ 3 ] ;
for ( i = 0 ; i < = max_index ; i + + )
y_est [ i ] = Y [ i ] - Y_intercept ;
for ( i = 0 ; i < = 3 ; i + + ) {
y_est [ i ] = i * 32 ;
x_est [ i ] = ( ( y_est [ i ] * 1 < < scale_factor ) + G_fxp ) / G_fxp ;
}
2010-10-19 20:01:41 +05:30
if ( y_est [ max_index ] = = 0 )
return false ;
2010-06-12 00:34:00 -04:00
x_est_fxp1_nonlin =
x_est [ max_index ] - ( ( 1 < < scale_factor ) * y_est [ max_index ] +
G_fxp ) / G_fxp ;
order_x_by_y =
( x_est_fxp1_nonlin + 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 ;
I = ( max_index > 15 ) ? 7 : max_index > > 1 ;
L = max_index - I ;
scale_factor = 8 ;
sum_y_sqr = 0 ;
sum_y_quad = 0 ;
x_tilde_abs = 0 ;
for ( i = 0 ; i < = L ; i + + ) {
unsigned int y_sqr ;
unsigned int y_quad ;
unsigned int tmp_abs ;
/* prevent division by zero */
if ( y_est [ i + I ] = = 0 )
return false ;
x_est_fxp1_nonlin =
x_est [ i + I ] - ( ( 1 < < scale_factor ) * y_est [ i + I ] +
G_fxp ) / G_fxp ;
x_tilde [ i ] =
( x_est_fxp1_nonlin * ( 1 < < M ) + y_est [ i + I ] ) / y_est [ i +
I ] ;
x_tilde [ i ] =
( x_tilde [ i ] * ( 1 < < M ) + y_est [ i + I ] ) / y_est [ i + I ] ;
x_tilde [ i ] =
( x_tilde [ i ] * ( 1 < < M ) + y_est [ i + I ] ) / y_est [ i + I ] ;
y_sqr =
( y_est [ i + I ] * y_est [ i + I ] +
( scale_factor * scale_factor ) ) / ( scale_factor *
scale_factor ) ;
tmp_abs = abs ( x_tilde [ i ] ) ;
if ( tmp_abs > x_tilde_abs )
x_tilde_abs = tmp_abs ;
y_quad = y_sqr * y_sqr ;
sum_y_sqr = sum_y_sqr + y_sqr ;
sum_y_quad = sum_y_quad + y_quad ;
B1_tmp [ i ] = y_sqr * ( L + 1 ) ;
B2_tmp [ i ] = y_sqr ;
}
B1_abs_max = 0 ;
B2_abs_max = 0 ;
for ( i = 0 ; i < = L ; i + + ) {
int abs_val ;
B1_tmp [ i ] - = sum_y_sqr ;
B2_tmp [ i ] = sum_y_quad - sum_y_sqr * B2_tmp [ i ] ;
abs_val = abs ( B1_tmp [ i ] ) ;
if ( abs_val > B1_abs_max )
B1_abs_max = abs_val ;
abs_val = abs ( B2_tmp [ i ] ) ;
if ( abs_val > B2_abs_max )
B2_abs_max = abs_val ;
}
Q_x = find_proper_scale ( find_expn ( x_tilde_abs ) , 10 ) ;
Q_B1 = find_proper_scale ( find_expn ( B1_abs_max ) , 10 ) ;
Q_B2 = find_proper_scale ( find_expn ( B2_abs_max ) , 10 ) ;
beta_raw = 0 ;
alpha_raw = 0 ;
for ( i = 0 ; i < = L ; i + + ) {
x_tilde [ i ] = x_tilde [ i ] / ( 1 < < Q_x ) ;
B1_tmp [ i ] = B1_tmp [ i ] / ( 1 < < Q_B1 ) ;
B2_tmp [ i ] = B2_tmp [ i ] / ( 1 < < Q_B2 ) ;
beta_raw = beta_raw + B1_tmp [ i ] * x_tilde [ i ] ;
alpha_raw = alpha_raw + B2_tmp [ i ] * x_tilde [ i ] ;
}
scale_B =
( ( sum_y_quad / scale_factor ) * ( L + 1 ) -
( sum_y_sqr / scale_factor ) * sum_y_sqr ) * scale_factor ;
Q_scale_B = find_proper_scale ( find_expn ( abs ( scale_B ) ) , 10 ) ;
scale_B = scale_B / ( 1 < < Q_scale_B ) ;
2010-10-19 20:01:41 +05:30
if ( scale_B = = 0 )
return false ;
2010-06-12 00:34:00 -04:00
Q_beta = find_proper_scale ( find_expn ( abs ( beta_raw ) ) , 10 ) ;
Q_alpha = find_proper_scale ( find_expn ( 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 ( i = 0 ; i < PAPRD_TABLE_SZ ; i + + ) {
tmp = i * 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 ;
PA_in [ i ] = y5 + y3 + ( 256 * tmp ) / G_fxp ;
if ( i > = 2 ) {
tmp = PA_in [ i ] - PA_in [ i - 1 ] ;
if ( tmp < 0 )
PA_in [ i ] =
PA_in [ i - 1 ] + ( PA_in [ i - 1 ] -
PA_in [ i - 2 ] ) ;
}
PA_in [ i ] = ( PA_in [ i ] < 1400 ) ? PA_in [ i ] : 1400 ;
}
beta_raw = 0 ;
alpha_raw = 0 ;
for ( i = 0 ; i < = L ; i + + ) {
int theta_tilde =
( ( theta [ i + I ] < < M ) + y_est [ i + I ] ) / y_est [ i + I ] ;
theta_tilde =
( ( theta_tilde < < M ) + y_est [ i + I ] ) / y_est [ i + I ] ;
theta_tilde =
( ( theta_tilde < < M ) + y_est [ i + I ] ) / y_est [ i + I ] ;
beta_raw = beta_raw + B1_tmp [ i ] * theta_tilde ;
alpha_raw = alpha_raw + B2_tmp [ i ] * theta_tilde ;
}
Q_beta = find_proper_scale ( find_expn ( abs ( beta_raw ) ) , 10 ) ;
Q_alpha = find_proper_scale ( find_expn ( 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 + 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 ( i = 0 ; i < PAPRD_TABLE_SZ ; i + + ) {
int PA_angle ;
/* pa_table[4] is calculated from PA_angle for i=5 */
if ( i = = 4 )
continue ;
tmp = i * 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 ) ;
if ( i < 4 ) {
PA_angle = 0 ;
} else {
PA_angle = y5 + y3 ;
if ( PA_angle < - 150 )
PA_angle = - 150 ;
else if ( PA_angle > 150 )
PA_angle = 150 ;
}
pa_table [ i ] = ( ( PA_in [ i ] & 0x7ff ) < < 11 ) + ( PA_angle & 0x7ff ) ;
if ( i = = 5 ) {
PA_angle = ( PA_angle + 2 ) > > 1 ;
pa_table [ i - 1 ] = ( ( PA_in [ i - 1 ] & 0x7ff ) < < 11 ) +
( PA_angle & 0x7ff ) ;
}
}
* gain = G_fxp ;
return true ;
}
void ar9003_paprd_populate_single_table ( struct ath_hw * ah ,
2010-07-31 00:12:00 +02:00
struct ath9k_hw_cal_data * caldata ,
int chain )
2010-06-12 00:34:00 -04:00
{
2010-07-31 00:12:00 +02:00
u32 * paprd_table_val = caldata - > pa_table [ chain ] ;
u32 small_signal_gain = caldata - > small_signal_gain [ chain ] ;
2010-12-13 08:40:54 +01:00
u32 training_power = ah - > paprd_training_power ;
2010-06-12 00:34:00 -04:00
u32 reg = 0 ;
int i ;
if ( chain = = 0 )
reg = AR_PHY_PAPRD_MEM_TAB_B0 ;
else if ( chain = = 1 )
reg = AR_PHY_PAPRD_MEM_TAB_B1 ;
else if ( chain = = 2 )
reg = AR_PHY_PAPRD_MEM_TAB_B2 ;
for ( i = 0 ; i < PAPRD_TABLE_SZ ; i + + ) {
REG_WRITE ( ah , reg , paprd_table_val [ i ] ) ;
reg = reg + 4 ;
}
if ( chain = = 0 )
reg = AR_PHY_PA_GAIN123_B0 ;
else if ( chain = = 1 )
reg = AR_PHY_PA_GAIN123_B1 ;
else
reg = AR_PHY_PA_GAIN123_B2 ;
REG_RMW_FIELD ( ah , reg , AR_PHY_PA_GAIN123_PA_GAIN1 , small_signal_gain ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_CTRL1_B0 ,
AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL ,
training_power ) ;
2010-12-06 04:27:58 -08:00
if ( ah - > caps . tx_chainmask & BIT ( 1 ) )
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_CTRL1_B1 ,
AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL ,
training_power ) ;
2010-06-12 00:34:00 -04:00
2010-12-06 04:27:58 -08:00
if ( ah - > caps . tx_chainmask & BIT ( 2 ) )
2011-09-13 22:38:18 +05:30
/* val AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL correct? */
2010-12-06 04:27:58 -08:00
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_CTRL1_B2 ,
AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL ,
training_power ) ;
2010-06-12 00:34:00 -04:00
}
EXPORT_SYMBOL ( ar9003_paprd_populate_single_table ) ;
2012-12-10 07:22:35 +05:30
void ar9003_paprd_setup_gain_table ( struct ath_hw * ah , int chain )
2010-06-12 00:34:00 -04:00
{
unsigned int i , desired_gain , gain_index ;
2010-12-13 08:40:54 +01:00
unsigned int train_power = ah - > paprd_training_power ;
2010-06-12 00:34:00 -04:00
desired_gain = ar9003_get_desired_gain ( ah , chain , train_power ) ;
gain_index = 0 ;
2011-06-23 20:14:29 +05:30
for ( i = 0 ; i < PAPRD_GAIN_TABLE_ENTRIES ; i + + ) {
2010-06-12 00:34:00 -04:00
if ( ah - > paprd_gain_table_index [ i ] > = desired_gain )
break ;
gain_index + + ;
}
ar9003_tx_force_gain ( ah , gain_index ) ;
REG_CLR_BIT ( ah , AR_PHY_PAPRD_TRAINER_STAT1 ,
AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE ) ;
}
EXPORT_SYMBOL ( ar9003_paprd_setup_gain_table ) ;
2012-08-27 17:00:05 +02:00
static bool ar9003_paprd_retrain_pa_in ( struct ath_hw * ah ,
struct ath9k_hw_cal_data * caldata ,
int chain )
{
u32 * pa_in = caldata - > pa_table [ chain ] ;
int capdiv_offset , quick_drop_offset ;
int capdiv2g , quick_drop ;
int count = 0 ;
int i ;
if ( ! AR_SREV_9485 ( ah ) & & ! AR_SREV_9330 ( ah ) )
return false ;
capdiv2g = REG_READ_FIELD ( ah , AR_PHY_65NM_CH0_TXRF3 ,
AR_PHY_65NM_CH0_TXRF3_CAPDIV2G ) ;
quick_drop = REG_READ_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP ) ;
if ( quick_drop )
quick_drop - = 0x40 ;
for ( i = 0 ; i < NUM_BIN + 1 ; i + + ) {
if ( pa_in [ i ] = = 1400 )
count + + ;
}
if ( AR_SREV_9485 ( ah ) ) {
if ( pa_in [ 23 ] < 800 ) {
capdiv_offset = ( int ) ( ( 1000 - pa_in [ 23 ] + 75 ) / 150 ) ;
capdiv2g + = capdiv_offset ;
if ( capdiv2g > 7 ) {
capdiv2g = 7 ;
if ( pa_in [ 23 ] < 600 ) {
quick_drop + + ;
if ( quick_drop > 0 )
quick_drop = 0 ;
}
}
} else if ( pa_in [ 23 ] = = 1400 ) {
quick_drop_offset = min_t ( int , count / 3 , 2 ) ;
quick_drop + = quick_drop_offset ;
capdiv2g + = quick_drop_offset / 2 ;
if ( capdiv2g > 7 )
capdiv2g = 7 ;
if ( quick_drop > 0 ) {
quick_drop = 0 ;
capdiv2g - = quick_drop_offset ;
if ( capdiv2g < 0 )
capdiv2g = 0 ;
}
} else {
return false ;
}
} else if ( AR_SREV_9330 ( ah ) ) {
if ( pa_in [ 23 ] < 1000 ) {
capdiv_offset = ( 1000 - pa_in [ 23 ] ) / 100 ;
capdiv2g + = capdiv_offset ;
if ( capdiv_offset > 3 ) {
capdiv_offset = 1 ;
quick_drop - - ;
}
capdiv2g + = capdiv_offset ;
if ( capdiv2g > 6 )
capdiv2g = 6 ;
if ( quick_drop < - 4 )
quick_drop = - 4 ;
} else if ( pa_in [ 23 ] = = 1400 ) {
if ( count > 3 ) {
quick_drop + + ;
capdiv2g - = count / 4 ;
if ( quick_drop > - 2 )
quick_drop = - 2 ;
} else {
capdiv2g - - ;
}
if ( capdiv2g < 0 )
capdiv2g = 0 ;
} else {
return false ;
}
}
REG_RMW_FIELD ( ah , AR_PHY_65NM_CH0_TXRF3 ,
AR_PHY_65NM_CH0_TXRF3_CAPDIV2G , capdiv2g ) ;
REG_RMW_FIELD ( ah , AR_PHY_PAPRD_TRAINER_CNTL3 ,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP ,
quick_drop ) ;
return true ;
}
2010-07-31 00:12:00 +02:00
int ar9003_paprd_create_curve ( struct ath_hw * ah ,
struct ath9k_hw_cal_data * caldata , int chain )
2010-06-12 00:34:00 -04:00
{
2010-07-31 00:12:00 +02:00
u16 * small_signal_gain = & caldata - > small_signal_gain [ chain ] ;
u32 * pa_table = caldata - > pa_table [ chain ] ;
2010-06-12 00:34:00 -04:00
u32 * data_L , * data_U ;
int i , status = 0 ;
u32 * buf ;
u32 reg ;
2010-07-31 00:12:00 +02:00
memset ( caldata - > pa_table [ chain ] , 0 , sizeof ( caldata - > pa_table [ chain ] ) ) ;
2010-06-12 00:34:00 -04:00
2012-12-10 07:22:35 +05:30
buf = kmalloc ( 2 * 48 * sizeof ( u32 ) , GFP_KERNEL ) ;
2010-06-12 00:34:00 -04:00
if ( ! buf )
return - ENOMEM ;
data_L = & buf [ 0 ] ;
data_U = & buf [ 48 ] ;
REG_CLR_BIT ( ah , AR_PHY_CHAN_INFO_MEMORY ,
AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ ) ;
reg = AR_PHY_CHAN_INFO_TAB_0 ;
for ( i = 0 ; i < 48 ; i + + )
data_L [ i ] = REG_READ ( ah , reg + ( i < < 2 ) ) ;
REG_SET_BIT ( ah , AR_PHY_CHAN_INFO_MEMORY ,
AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ ) ;
for ( i = 0 ; i < 48 ; i + + )
data_U [ i ] = REG_READ ( ah , reg + ( i < < 2 ) ) ;
if ( ! create_pa_curve ( data_L , data_U , pa_table , small_signal_gain ) )
status = - 2 ;
2012-08-27 17:00:05 +02:00
if ( ar9003_paprd_retrain_pa_in ( ah , caldata , chain ) )
status = - EINPROGRESS ;
2010-06-12 00:34:00 -04:00
REG_CLR_BIT ( ah , AR_PHY_PAPRD_TRAINER_STAT1 ,
AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE ) ;
kfree ( buf ) ;
return status ;
}
EXPORT_SYMBOL ( ar9003_paprd_create_curve ) ;
int ar9003_paprd_init_table ( struct ath_hw * ah )
{
2010-12-13 08:40:54 +01:00
int ret ;
ret = ar9003_paprd_setup_single_table ( ah ) ;
if ( ret < 0 )
return ret ;
2010-06-12 00:34:00 -04:00
ar9003_paprd_get_gain_table ( ah ) ;
return 0 ;
}
EXPORT_SYMBOL ( ar9003_paprd_init_table ) ;
bool ar9003_paprd_is_done ( struct ath_hw * ah )
{
2011-06-17 14:08:42 +05:30
int paprd_done , agc2_pwr ;
2012-12-10 07:22:36 +05:30
2011-06-17 14:08:42 +05:30
paprd_done = REG_READ_FIELD ( ah , AR_PHY_PAPRD_TRAINER_STAT1 ,
2010-06-12 00:34:00 -04:00
AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE ) ;
2011-06-17 14:08:42 +05:30
2012-12-10 07:22:36 +05:30
if ( AR_SREV_9485 ( ah ) )
goto exit ;
2011-06-17 14:08:42 +05:30
if ( paprd_done = = 0x1 ) {
agc2_pwr = REG_READ_FIELD ( ah , AR_PHY_PAPRD_TRAINER_STAT1 ,
AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( ath9k_hw_common ( ah ) , CALIBRATE ,
2011-06-17 14:08:42 +05:30
" AGC2_PWR = 0x%x training done = 0x%x \n " ,
agc2_pwr , paprd_done ) ;
/*
* agc2_pwr range should not be less than ' IDEAL_AGC2_PWR_CHANGE '
* when the training is completely done , otherwise retraining is
* done to make sure the value is in ideal range
*/
if ( agc2_pwr < = PAPRD_IDEAL_AGC2_PWR_RANGE )
paprd_done = 0 ;
}
2012-12-10 07:22:36 +05:30
exit :
2011-06-17 14:08:42 +05:30
return ! ! paprd_done ;
2010-06-12 00:34:00 -04:00
}
EXPORT_SYMBOL ( ar9003_paprd_is_done ) ;