2008-10-29 10:16:30 +05:30
/*
* Copyright ( c ) 2008 Atheros Communications 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 "core.h"
# include "hw.h"
# include "reg.h"
# include "phy.h"
static const int16_t NOISE_FLOOR [ ] = { - 96 , - 93 , - 98 , - 96 , - 93 , - 96 } ;
/* We can tune this as we go by monitoring really low values */
# define ATH9K_NF_TOO_LOW -60
/* AR5416 may return very high value (like -31 dBm), in those cases the nf
* is incorrect and we should use the static NF value . Later we can try to
* find out why they are reporting these values */
static bool ath9k_hw_nf_in_range ( struct ath_hal * ah , s16 nf )
{
if ( nf > ATH9K_NF_TOO_LOW ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" noise floor value detected (%d) is "
2008-10-29 10:16:30 +05:30
" lower than what we think is a "
" reasonable value (%d) \n " ,
2008-11-28 22:18:05 +05:30
nf , ATH9K_NF_TOO_LOW ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
return true ;
}
static int16_t ath9k_hw_get_nf_hist_mid ( int16_t * nfCalBuffer )
{
int16_t nfval ;
int16_t sort [ ATH9K_NF_CAL_HIST_MAX ] ;
int i , j ;
for ( i = 0 ; i < ATH9K_NF_CAL_HIST_MAX ; i + + )
sort [ i ] = nfCalBuffer [ i ] ;
for ( i = 0 ; i < ATH9K_NF_CAL_HIST_MAX - 1 ; i + + ) {
for ( j = 1 ; j < ATH9K_NF_CAL_HIST_MAX - i ; j + + ) {
if ( sort [ j ] > sort [ j - 1 ] ) {
nfval = sort [ j ] ;
sort [ j ] = sort [ j - 1 ] ;
sort [ j - 1 ] = nfval ;
}
}
}
nfval = sort [ ( ATH9K_NF_CAL_HIST_MAX - 1 ) > > 1 ] ;
return nfval ;
}
static void ath9k_hw_update_nfcal_hist_buffer ( struct ath9k_nfcal_hist * h ,
int16_t * nfarray )
{
int i ;
for ( i = 0 ; i < NUM_NF_READINGS ; i + + ) {
h [ i ] . nfCalBuffer [ h [ i ] . currIndex ] = nfarray [ i ] ;
if ( + + h [ i ] . currIndex > = ATH9K_NF_CAL_HIST_MAX )
h [ i ] . currIndex = 0 ;
if ( h [ i ] . invalidNFcount > 0 ) {
if ( nfarray [ i ] < AR_PHY_CCA_MIN_BAD_VALUE | |
nfarray [ i ] > AR_PHY_CCA_MAX_HIGH_VALUE ) {
h [ i ] . invalidNFcount = ATH9K_NF_CAL_HIST_MAX ;
} else {
h [ i ] . invalidNFcount - - ;
h [ i ] . privNF = nfarray [ i ] ;
}
} else {
h [ i ] . privNF =
ath9k_hw_get_nf_hist_mid ( h [ i ] . nfCalBuffer ) ;
}
}
return ;
}
static void ath9k_hw_do_getnf ( struct ath_hal * ah ,
int16_t nfarray [ NUM_NF_READINGS ] )
{
int16_t nf ;
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
nf = MS ( REG_READ ( ah , AR_PHY_CCA ) , AR9280_PHY_MINCCA_PWR ) ;
else
nf = MS ( REG_READ ( ah , AR_PHY_CCA ) , AR_PHY_MINCCA_PWR ) ;
if ( nf & 0x100 )
nf = 0 - ( ( nf ^ 0x1ff ) + 1 ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" NF calibrated [ctl] [chain 0] is %d \n " , nf ) ;
nfarray [ 0 ] = nf ;
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
nf = MS ( REG_READ ( ah , AR_PHY_CH1_CCA ) ,
AR9280_PHY_CH1_MINCCA_PWR ) ;
else
nf = MS ( REG_READ ( ah , AR_PHY_CH1_CCA ) ,
AR_PHY_CH1_MINCCA_PWR ) ;
if ( nf & 0x100 )
nf = 0 - ( ( nf ^ 0x1ff ) + 1 ) ;
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-10-29 10:16:30 +05:30
" NF calibrated [ctl] [chain 1] is %d \n " , nf ) ;
nfarray [ 1 ] = nf ;
if ( ! AR_SREV_9280 ( ah ) ) {
nf = MS ( REG_READ ( ah , AR_PHY_CH2_CCA ) ,
AR_PHY_CH2_MINCCA_PWR ) ;
if ( nf & 0x100 )
nf = 0 - ( ( nf ^ 0x1ff ) + 1 ) ;
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-10-29 10:16:30 +05:30
" NF calibrated [ctl] [chain 2] is %d \n " , nf ) ;
nfarray [ 2 ] = nf ;
}
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
nf = MS ( REG_READ ( ah , AR_PHY_EXT_CCA ) ,
AR9280_PHY_EXT_MINCCA_PWR ) ;
else
nf = MS ( REG_READ ( ah , AR_PHY_EXT_CCA ) ,
AR_PHY_EXT_MINCCA_PWR ) ;
if ( nf & 0x100 )
nf = 0 - ( ( nf ^ 0x1ff ) + 1 ) ;
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-10-29 10:16:30 +05:30
" NF calibrated [ext] [chain 0] is %d \n " , nf ) ;
nfarray [ 3 ] = nf ;
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
nf = MS ( REG_READ ( ah , AR_PHY_CH1_EXT_CCA ) ,
AR9280_PHY_CH1_EXT_MINCCA_PWR ) ;
else
nf = MS ( REG_READ ( ah , AR_PHY_CH1_EXT_CCA ) ,
AR_PHY_CH1_EXT_MINCCA_PWR ) ;
if ( nf & 0x100 )
nf = 0 - ( ( nf ^ 0x1ff ) + 1 ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" NF calibrated [ext] [chain 1] is %d \n " , nf ) ;
nfarray [ 4 ] = nf ;
if ( ! AR_SREV_9280 ( ah ) ) {
nf = MS ( REG_READ ( ah , AR_PHY_CH2_EXT_CCA ) ,
AR_PHY_CH2_EXT_MINCCA_PWR ) ;
if ( nf & 0x100 )
nf = 0 - ( ( nf ^ 0x1ff ) + 1 ) ;
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-10-29 10:16:30 +05:30
" NF calibrated [ext] [chain 2] is %d \n " , nf ) ;
nfarray [ 5 ] = nf ;
}
}
static bool getNoiseFloorThresh ( struct ath_hal * ah ,
const struct ath9k_channel * chan ,
int16_t * nft )
{
switch ( chan - > chanmode ) {
case CHANNEL_A :
case CHANNEL_A_HT20 :
case CHANNEL_A_HT40PLUS :
case CHANNEL_A_HT40MINUS :
2008-11-13 17:59:36 +05:30
* nft = ( int8_t ) ath9k_hw_get_eeprom ( ah , EEP_NFTHRESH_5 ) ;
2008-10-29 10:16:30 +05:30
break ;
case CHANNEL_B :
case CHANNEL_G :
case CHANNEL_G_HT20 :
case CHANNEL_G_HT40PLUS :
case CHANNEL_G_HT40MINUS :
2008-11-13 17:59:36 +05:30
* nft = ( int8_t ) ath9k_hw_get_eeprom ( ah , EEP_NFTHRESH_2 ) ;
2008-10-29 10:16:30 +05:30
break ;
default :
DPRINTF ( ah - > ah_sc , ATH_DBG_CHANNEL ,
2008-11-28 22:18:05 +05:30
" invalid channel flags 0x%x \n " , chan - > channelFlags ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
return true ;
}
static void ath9k_hw_setup_calibration ( struct ath_hal * ah ,
struct hal_cal_list * currCal )
{
REG_RMW_FIELD ( ah , AR_PHY_TIMING_CTRL4 ( 0 ) ,
AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX ,
currCal - > calData - > calCountMax ) ;
switch ( currCal - > calData - > calType ) {
case IQ_MISMATCH_CAL :
REG_WRITE ( ah , AR_PHY_CALMODE , AR_PHY_CALMODE_IQ ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" starting IQ Mismatch Calibration \n " ) ;
2008-10-29 10:16:30 +05:30
break ;
case ADC_GAIN_CAL :
REG_WRITE ( ah , AR_PHY_CALMODE , AR_PHY_CALMODE_ADC_GAIN ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" starting ADC Gain Calibration \n " ) ;
2008-10-29 10:16:30 +05:30
break ;
case ADC_DC_CAL :
REG_WRITE ( ah , AR_PHY_CALMODE , AR_PHY_CALMODE_ADC_DC_PER ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" starting ADC DC Calibration \n " ) ;
2008-10-29 10:16:30 +05:30
break ;
case ADC_DC_INIT_CAL :
REG_WRITE ( ah , AR_PHY_CALMODE , AR_PHY_CALMODE_ADC_DC_INIT ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" starting Init ADC DC Calibration \n " ) ;
2008-10-29 10:16:30 +05:30
break ;
}
REG_SET_BIT ( ah , AR_PHY_TIMING_CTRL4 ( 0 ) ,
AR_PHY_TIMING_CTRL4_DO_CAL ) ;
}
static void ath9k_hw_reset_calibration ( struct ath_hal * ah ,
struct hal_cal_list * currCal )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
int i ;
ath9k_hw_setup_calibration ( ah , currCal ) ;
currCal - > calState = CAL_RUNNING ;
for ( i = 0 ; i < AR5416_MAX_CHAINS ; i + + ) {
ahp - > ah_Meas0 . sign [ i ] = 0 ;
ahp - > ah_Meas1 . sign [ i ] = 0 ;
ahp - > ah_Meas2 . sign [ i ] = 0 ;
ahp - > ah_Meas3 . sign [ i ] = 0 ;
}
ahp - > ah_CalSamples = 0 ;
}
static void ath9k_hw_per_calibration ( struct ath_hal * ah ,
struct ath9k_channel * ichan ,
u8 rxchainmask ,
struct hal_cal_list * currCal ,
bool * isCalDone )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
* isCalDone = false ;
if ( currCal - > calState = = CAL_RUNNING ) {
if ( ! ( REG_READ ( ah , AR_PHY_TIMING_CTRL4 ( 0 ) ) &
AR_PHY_TIMING_CTRL4_DO_CAL ) ) {
currCal - > calData - > calCollect ( ah ) ;
ahp - > ah_CalSamples + + ;
if ( ahp - > ah_CalSamples > = currCal - > calData - > calNumSamples ) {
int i , numChains = 0 ;
for ( i = 0 ; i < AR5416_MAX_CHAINS ; i + + ) {
if ( rxchainmask & ( 1 < < i ) )
numChains + + ;
}
currCal - > calData - > calPostProc ( ah , numChains ) ;
ichan - > CalValid | = currCal - > calData - > calType ;
currCal - > calState = CAL_DONE ;
* isCalDone = true ;
} else {
ath9k_hw_setup_calibration ( ah , currCal ) ;
}
}
} else if ( ! ( ichan - > CalValid & currCal - > calData - > calType ) ) {
ath9k_hw_reset_calibration ( ah , currCal ) ;
}
}
static bool ath9k_hw_iscal_supported ( struct ath_hal * ah ,
struct ath9k_channel * chan ,
enum hal_cal_types calType )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
bool retval = false ;
switch ( calType & ahp - > ah_suppCals ) {
case IQ_MISMATCH_CAL :
if ( ! IS_CHAN_B ( chan ) )
retval = true ;
break ;
case ADC_GAIN_CAL :
case ADC_DC_CAL :
if ( ! IS_CHAN_B ( chan )
& & ! ( IS_CHAN_2GHZ ( chan ) & & IS_CHAN_HT20 ( chan ) ) )
retval = true ;
break ;
}
return retval ;
}
static void ath9k_hw_iqcal_collect ( struct ath_hal * ah )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
int i ;
for ( i = 0 ; i < AR5416_MAX_CHAINS ; i + + ) {
ahp - > ah_totalPowerMeasI [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_0 ( i ) ) ;
ahp - > ah_totalPowerMeasQ [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_1 ( i ) ) ;
ahp - > ah_totalIqCorrMeas [ i ] + =
( int32_t ) REG_READ ( ah , AR_PHY_CAL_MEAS_2 ( i ) ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" %d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x; \n " ,
ahp - > ah_CalSamples , i , ahp - > ah_totalPowerMeasI [ i ] ,
ahp - > ah_totalPowerMeasQ [ i ] ,
ahp - > ah_totalIqCorrMeas [ i ] ) ;
}
}
static void ath9k_hw_adc_gaincal_collect ( struct ath_hal * ah )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
int i ;
for ( i = 0 ; i < AR5416_MAX_CHAINS ; i + + ) {
ahp - > ah_totalAdcIOddPhase [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_0 ( i ) ) ;
ahp - > ah_totalAdcIEvenPhase [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_1 ( i ) ) ;
ahp - > ah_totalAdcQOddPhase [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_2 ( i ) ) ;
ahp - > ah_totalAdcQEvenPhase [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_3 ( i ) ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" %d: Chn %d oddi=0x%08x; eveni=0x%08x; "
" oddq=0x%08x; evenq=0x%08x; \n " ,
ahp - > ah_CalSamples , i ,
ahp - > ah_totalAdcIOddPhase [ i ] ,
ahp - > ah_totalAdcIEvenPhase [ i ] ,
ahp - > ah_totalAdcQOddPhase [ i ] ,
ahp - > ah_totalAdcQEvenPhase [ i ] ) ;
}
}
static void ath9k_hw_adc_dccal_collect ( struct ath_hal * ah )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
int i ;
for ( i = 0 ; i < AR5416_MAX_CHAINS ; i + + ) {
ahp - > ah_totalAdcDcOffsetIOddPhase [ i ] + =
( int32_t ) REG_READ ( ah , AR_PHY_CAL_MEAS_0 ( i ) ) ;
ahp - > ah_totalAdcDcOffsetIEvenPhase [ i ] + =
( int32_t ) REG_READ ( ah , AR_PHY_CAL_MEAS_1 ( i ) ) ;
ahp - > ah_totalAdcDcOffsetQOddPhase [ i ] + =
( int32_t ) REG_READ ( ah , AR_PHY_CAL_MEAS_2 ( i ) ) ;
ahp - > ah_totalAdcDcOffsetQEvenPhase [ i ] + =
( int32_t ) REG_READ ( ah , AR_PHY_CAL_MEAS_3 ( i ) ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" %d: Chn %d oddi=0x%08x; eveni=0x%08x; "
" oddq=0x%08x; evenq=0x%08x; \n " ,
ahp - > ah_CalSamples , i ,
ahp - > ah_totalAdcDcOffsetIOddPhase [ i ] ,
ahp - > ah_totalAdcDcOffsetIEvenPhase [ i ] ,
ahp - > ah_totalAdcDcOffsetQOddPhase [ i ] ,
ahp - > ah_totalAdcDcOffsetQEvenPhase [ i ] ) ;
}
}
static void ath9k_hw_iqcalibrate ( struct ath_hal * ah , u8 numChains )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
u32 powerMeasQ , powerMeasI , iqCorrMeas ;
u32 qCoffDenom , iCoffDenom ;
int32_t qCoff , iCoff ;
int iqCorrNeg , i ;
for ( i = 0 ; i < numChains ; i + + ) {
powerMeasI = ahp - > ah_totalPowerMeasI [ i ] ;
powerMeasQ = ahp - > ah_totalPowerMeasQ [ i ] ;
iqCorrMeas = ahp - > ah_totalIqCorrMeas [ i ] ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Starting IQ Cal and Correction for Chain %d \n " ,
i ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Orignal: Chn %diq_corr_meas = 0x%08x \n " ,
i , ahp - > ah_totalIqCorrMeas [ i ] ) ;
iqCorrNeg = 0 ;
if ( iqCorrMeas > 0x80000000 ) {
iqCorrMeas = ( 0xffffffff - iqCorrMeas ) + 1 ;
iqCorrNeg = 1 ;
}
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_i = 0x%08x \n " , i , powerMeasI ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_q = 0x%08x \n " , i , powerMeasQ ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE , " iqCorrNeg is 0x%08x \n " ,
iqCorrNeg ) ;
iCoffDenom = ( powerMeasI / 2 + powerMeasQ / 2 ) / 128 ;
qCoffDenom = powerMeasQ / 64 ;
if ( powerMeasQ ! = 0 ) {
iCoff = iqCorrMeas / iCoffDenom ;
qCoff = powerMeasI / qCoffDenom - 64 ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d iCoff = 0x%08x \n " , i , iCoff ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d qCoff = 0x%08x \n " , i , qCoff ) ;
iCoff = iCoff & 0x3f ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" New: Chn %d iCoff = 0x%08x \n " , i , iCoff ) ;
if ( iqCorrNeg = = 0x0 )
iCoff = 0x40 - iCoff ;
if ( qCoff > 15 )
qCoff = 15 ;
else if ( qCoff < = - 16 )
qCoff = 16 ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d : iCoff = 0x%x qCoff = 0x%x \n " ,
i , iCoff , qCoff ) ;
REG_RMW_FIELD ( ah , AR_PHY_TIMING_CTRL4 ( i ) ,
AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF ,
iCoff ) ;
REG_RMW_FIELD ( ah , AR_PHY_TIMING_CTRL4 ( i ) ,
AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF ,
qCoff ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" IQ Cal and Correction done for Chain %d \n " ,
i ) ;
}
}
REG_SET_BIT ( ah , AR_PHY_TIMING_CTRL4 ( 0 ) ,
AR_PHY_TIMING_CTRL4_IQCORR_ENABLE ) ;
}
static void ath9k_hw_adc_gaincal_calibrate ( struct ath_hal * ah , u8 numChains )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
u32 iOddMeasOffset , iEvenMeasOffset , qOddMeasOffset , qEvenMeasOffset ;
u32 qGainMismatch , iGainMismatch , val , i ;
for ( i = 0 ; i < numChains ; i + + ) {
iOddMeasOffset = ahp - > ah_totalAdcIOddPhase [ i ] ;
iEvenMeasOffset = ahp - > ah_totalAdcIEvenPhase [ i ] ;
qOddMeasOffset = ahp - > ah_totalAdcQOddPhase [ i ] ;
qEvenMeasOffset = ahp - > ah_totalAdcQEvenPhase [ i ] ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Starting ADC Gain Cal for Chain %d \n " , i ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_odd_i = 0x%08x \n " , i ,
iOddMeasOffset ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_even_i = 0x%08x \n " , i ,
iEvenMeasOffset ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_odd_q = 0x%08x \n " , i ,
qOddMeasOffset ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_even_q = 0x%08x \n " , i ,
qEvenMeasOffset ) ;
if ( iOddMeasOffset ! = 0 & & qEvenMeasOffset ! = 0 ) {
iGainMismatch =
( ( iEvenMeasOffset * 32 ) /
iOddMeasOffset ) & 0x3f ;
qGainMismatch =
( ( qOddMeasOffset * 32 ) /
qEvenMeasOffset ) & 0x3f ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d gain_mismatch_i = 0x%08x \n " , i ,
iGainMismatch ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d gain_mismatch_q = 0x%08x \n " , i ,
qGainMismatch ) ;
val = REG_READ ( ah , AR_PHY_NEW_ADC_DC_GAIN_CORR ( i ) ) ;
val & = 0xfffff000 ;
val | = ( qGainMismatch ) | ( iGainMismatch < < 6 ) ;
REG_WRITE ( ah , AR_PHY_NEW_ADC_DC_GAIN_CORR ( i ) , val ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" ADC Gain Cal done for Chain %d \n " , i ) ;
}
}
REG_WRITE ( ah , AR_PHY_NEW_ADC_DC_GAIN_CORR ( 0 ) ,
REG_READ ( ah , AR_PHY_NEW_ADC_DC_GAIN_CORR ( 0 ) ) |
AR_PHY_NEW_ADC_GAIN_CORR_ENABLE ) ;
}
static void ath9k_hw_adc_dccal_calibrate ( struct ath_hal * ah , u8 numChains )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
u32 iOddMeasOffset , iEvenMeasOffset , val , i ;
int32_t qOddMeasOffset , qEvenMeasOffset , qDcMismatch , iDcMismatch ;
const struct hal_percal_data * calData =
ahp - > ah_cal_list_curr - > calData ;
u32 numSamples =
( 1 < < ( calData - > calCountMax + 5 ) ) * calData - > calNumSamples ;
for ( i = 0 ; i < numChains ; i + + ) {
iOddMeasOffset = ahp - > ah_totalAdcDcOffsetIOddPhase [ i ] ;
iEvenMeasOffset = ahp - > ah_totalAdcDcOffsetIEvenPhase [ i ] ;
qOddMeasOffset = ahp - > ah_totalAdcDcOffsetQOddPhase [ i ] ;
qEvenMeasOffset = ahp - > ah_totalAdcDcOffsetQEvenPhase [ i ] ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Starting ADC DC Offset Cal for Chain %d \n " , i ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_odd_i = %d \n " , i ,
iOddMeasOffset ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_even_i = %d \n " , i ,
iEvenMeasOffset ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_odd_q = %d \n " , i ,
qOddMeasOffset ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_even_q = %d \n " , i ,
qEvenMeasOffset ) ;
iDcMismatch = ( ( ( iEvenMeasOffset - iOddMeasOffset ) * 2 ) /
numSamples ) & 0x1ff ;
qDcMismatch = ( ( ( qOddMeasOffset - qEvenMeasOffset ) * 2 ) /
numSamples ) & 0x1ff ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d dc_offset_mismatch_i = 0x%08x \n " , i ,
iDcMismatch ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" Chn %d dc_offset_mismatch_q = 0x%08x \n " , i ,
qDcMismatch ) ;
val = REG_READ ( ah , AR_PHY_NEW_ADC_DC_GAIN_CORR ( i ) ) ;
val & = 0xc0000fff ;
val | = ( qDcMismatch < < 12 ) | ( iDcMismatch < < 21 ) ;
REG_WRITE ( ah , AR_PHY_NEW_ADC_DC_GAIN_CORR ( i ) , val ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" ADC DC Offset Cal done for Chain %d \n " , i ) ;
}
REG_WRITE ( ah , AR_PHY_NEW_ADC_DC_GAIN_CORR ( 0 ) ,
REG_READ ( ah , AR_PHY_NEW_ADC_DC_GAIN_CORR ( 0 ) ) |
AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE ) ;
}
void ath9k_hw_reset_calvalid ( struct ath_hal * ah , struct ath9k_channel * chan ,
bool * isCalDone )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
struct ath9k_channel * ichan =
ath9k_regd_check_channel ( ah , chan ) ;
struct hal_cal_list * currCal = ahp - > ah_cal_list_curr ;
* isCalDone = true ;
if ( ! AR_SREV_9100 ( ah ) & & ! AR_SREV_9160_10_OR_LATER ( ah ) )
return ;
if ( currCal = = NULL )
return ;
if ( ichan = = NULL ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" invalid channel %u/0x%x; no mapping \n " ,
chan - > channel , chan - > channelFlags ) ;
2008-10-29 10:16:30 +05:30
return ;
}
if ( currCal - > calState ! = CAL_DONE ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" Calibration state incorrect, %d \n " ,
currCal - > calState ) ;
2008-10-29 10:16:30 +05:30
return ;
}
if ( ! ath9k_hw_iscal_supported ( ah , chan , currCal - > calData - > calType ) )
return ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" Resetting Cal %d state for channel %u/0x%x \n " ,
currCal - > calData - > calType , chan - > channel ,
2008-10-29 10:16:30 +05:30
chan - > channelFlags ) ;
ichan - > CalValid & = ~ currCal - > calData - > calType ;
currCal - > calState = CAL_WAITING ;
* isCalDone = false ;
}
void ath9k_hw_start_nfcal ( struct ath_hal * ah )
{
REG_SET_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_ENABLE_NF ) ;
REG_SET_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_NO_UPDATE_NF ) ;
REG_SET_BIT ( ah , AR_PHY_AGC_CONTROL , AR_PHY_AGC_CONTROL_NF ) ;
}
void ath9k_hw_loadnf ( struct ath_hal * ah , struct ath9k_channel * chan )
{
struct ath9k_nfcal_hist * h ;
int i , j ;
int32_t val ;
const u32 ar5416_cca_regs [ 6 ] = {
AR_PHY_CCA ,
AR_PHY_CH1_CCA ,
AR_PHY_CH2_CCA ,
AR_PHY_EXT_CCA ,
AR_PHY_CH1_EXT_CCA ,
AR_PHY_CH2_EXT_CCA
} ;
u8 chainmask ;
if ( AR_SREV_9280 ( ah ) )
chainmask = 0x1B ;
else
chainmask = 0x3F ;
# ifdef ATH_NF_PER_CHAN
h = chan - > nfCalHist ;
# else
h = ah - > nfCalHist ;
# endif
for ( i = 0 ; i < NUM_NF_READINGS ; i + + ) {
if ( chainmask & ( 1 < < i ) ) {
val = REG_READ ( ah , ar5416_cca_regs [ i ] ) ;
val & = 0xFFFFFE00 ;
val | = ( ( ( u32 ) ( h [ i ] . privNF ) < < 1 ) & 0x1ff ) ;
REG_WRITE ( ah , ar5416_cca_regs [ i ] , val ) ;
}
}
REG_CLR_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_ENABLE_NF ) ;
REG_CLR_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_NO_UPDATE_NF ) ;
REG_SET_BIT ( ah , AR_PHY_AGC_CONTROL , AR_PHY_AGC_CONTROL_NF ) ;
for ( j = 0 ; j < 1000 ; j + + ) {
if ( ( REG_READ ( ah , AR_PHY_AGC_CONTROL ) &
AR_PHY_AGC_CONTROL_NF ) = = 0 )
break ;
udelay ( 10 ) ;
}
for ( i = 0 ; i < NUM_NF_READINGS ; i + + ) {
if ( chainmask & ( 1 < < i ) ) {
val = REG_READ ( ah , ar5416_cca_regs [ i ] ) ;
val & = 0xFFFFFE00 ;
val | = ( ( ( u32 ) ( - 50 ) < < 1 ) & 0x1ff ) ;
REG_WRITE ( ah , ar5416_cca_regs [ i ] , val ) ;
}
}
}
int16_t ath9k_hw_getnf ( struct ath_hal * ah ,
struct ath9k_channel * chan )
{
int16_t nf , nfThresh ;
int16_t nfarray [ NUM_NF_READINGS ] = { 0 } ;
struct ath9k_nfcal_hist * h ;
u8 chainmask ;
if ( AR_SREV_9280 ( ah ) )
chainmask = 0x1B ;
else
chainmask = 0x3F ;
chan - > channelFlags & = ( ~ CHANNEL_CW_INT ) ;
if ( REG_READ ( ah , AR_PHY_AGC_CONTROL ) & AR_PHY_AGC_CONTROL_NF ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" NF did not complete in calibration window \n " ) ;
2008-10-29 10:16:30 +05:30
nf = 0 ;
chan - > rawNoiseFloor = nf ;
return chan - > rawNoiseFloor ;
} else {
ath9k_hw_do_getnf ( ah , nfarray ) ;
nf = nfarray [ 0 ] ;
if ( getNoiseFloorThresh ( ah , chan , & nfThresh )
& & nf > nfThresh ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" noise floor failed detected; "
" detected %d, threshold %d \n " ,
2008-10-29 10:16:30 +05:30
nf , nfThresh ) ;
chan - > channelFlags | = CHANNEL_CW_INT ;
}
}
# ifdef ATH_NF_PER_CHAN
h = chan - > nfCalHist ;
# else
h = ah - > nfCalHist ;
# endif
ath9k_hw_update_nfcal_hist_buffer ( h , nfarray ) ;
chan - > rawNoiseFloor = h [ 0 ] . privNF ;
return chan - > rawNoiseFloor ;
}
void ath9k_init_nfcal_hist_buffer ( struct ath_hal * ah )
{
int i , j ;
for ( i = 0 ; i < NUM_NF_READINGS ; i + + ) {
ah - > nfCalHist [ i ] . currIndex = 0 ;
ah - > nfCalHist [ i ] . privNF = AR_PHY_CCA_MAX_GOOD_VALUE ;
ah - > nfCalHist [ i ] . invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH ;
for ( j = 0 ; j < ATH9K_NF_CAL_HIST_MAX ; j + + ) {
ah - > nfCalHist [ i ] . nfCalBuffer [ j ] =
AR_PHY_CCA_MAX_GOOD_VALUE ;
}
}
return ;
}
s16 ath9k_hw_getchan_noise ( struct ath_hal * ah , struct ath9k_channel * chan )
{
struct ath9k_channel * ichan ;
s16 nf ;
ichan = ath9k_regd_check_channel ( ah , chan ) ;
if ( ichan = = NULL ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
" invalid channel %u/0x%x; no mapping \n " ,
chan - > channel , chan - > channelFlags ) ;
2008-10-29 10:16:30 +05:30
return ATH_DEFAULT_NOISE_FLOOR ;
}
if ( ichan - > rawNoiseFloor = = 0 ) {
enum wireless_mode mode = ath9k_hw_chan2wmode ( ah , chan ) ;
nf = NOISE_FLOOR [ mode ] ;
} else
nf = ichan - > rawNoiseFloor ;
if ( ! ath9k_hw_nf_in_range ( ah , nf ) )
nf = ATH_DEFAULT_NOISE_FLOOR ;
return nf ;
}
bool ath9k_hw_calibrate ( struct ath_hal * ah , struct ath9k_channel * chan ,
u8 rxchainmask , bool longcal ,
bool * isCalDone )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
struct hal_cal_list * currCal = ahp - > ah_cal_list_curr ;
struct ath9k_channel * ichan = ath9k_regd_check_channel ( ah , chan ) ;
* isCalDone = true ;
if ( ichan = = NULL ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_CHANNEL ,
2008-11-28 22:18:05 +05:30
" invalid channel %u/0x%x; no mapping \n " ,
chan - > channel , chan - > channelFlags ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
if ( currCal & &
( currCal - > calState = = CAL_RUNNING | |
currCal - > calState = = CAL_WAITING ) ) {
ath9k_hw_per_calibration ( ah , ichan , rxchainmask , currCal ,
isCalDone ) ;
if ( * isCalDone ) {
ahp - > ah_cal_list_curr = currCal = currCal - > calNext ;
if ( currCal - > calState = = CAL_WAITING ) {
* isCalDone = false ;
ath9k_hw_reset_calibration ( ah , currCal ) ;
}
}
}
if ( longcal ) {
ath9k_hw_getnf ( ah , ichan ) ;
ath9k_hw_loadnf ( ah , ah - > ah_curchan ) ;
ath9k_hw_start_nfcal ( ah ) ;
if ( ( ichan - > channelFlags & CHANNEL_CW_INT ) ! = 0 ) {
chan - > channelFlags | = CHANNEL_CW_INT ;
ichan - > channelFlags & = ~ CHANNEL_CW_INT ;
}
}
return true ;
}
bool ath9k_hw_init_cal ( struct ath_hal * ah ,
struct ath9k_channel * chan )
{
struct ath_hal_5416 * ahp = AH5416 ( ah ) ;
struct ath9k_channel * ichan = ath9k_regd_check_channel ( ah , chan ) ;
REG_WRITE ( ah , AR_PHY_AGC_CONTROL ,
REG_READ ( ah , AR_PHY_AGC_CONTROL ) |
AR_PHY_AGC_CONTROL_CAL ) ;
if ( ! ath9k_hw_wait ( ah , AR_PHY_AGC_CONTROL , AR_PHY_AGC_CONTROL_CAL , 0 ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" offset calibration failed to complete in 1ms; "
" noisy environment? \n " ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
REG_WRITE ( ah , AR_PHY_AGC_CONTROL ,
REG_READ ( ah , AR_PHY_AGC_CONTROL ) |
AR_PHY_AGC_CONTROL_NF ) ;
ahp - > ah_cal_list = ahp - > ah_cal_list_last = ahp - > ah_cal_list_curr = NULL ;
if ( AR_SREV_9100 ( ah ) | | AR_SREV_9160_10_OR_LATER ( ah ) ) {
if ( ath9k_hw_iscal_supported ( ah , chan , ADC_GAIN_CAL ) ) {
INIT_CAL ( & ahp - > ah_adcGainCalData ) ;
INSERT_CAL ( ahp , & ahp - > ah_adcGainCalData ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" enabling ADC Gain Calibration. \n " ) ;
2008-10-29 10:16:30 +05:30
}
if ( ath9k_hw_iscal_supported ( ah , chan , ADC_DC_CAL ) ) {
INIT_CAL ( & ahp - > ah_adcDcCalData ) ;
INSERT_CAL ( ahp , & ahp - > ah_adcDcCalData ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" enabling ADC DC Calibration. \n " ) ;
2008-10-29 10:16:30 +05:30
}
if ( ath9k_hw_iscal_supported ( ah , chan , IQ_MISMATCH_CAL ) ) {
INIT_CAL ( & ahp - > ah_iqCalData ) ;
INSERT_CAL ( ahp , & ahp - > ah_iqCalData ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_CALIBRATE ,
2008-11-28 22:18:05 +05:30
" enabling IQ Calibration. \n " ) ;
2008-10-29 10:16:30 +05:30
}
ahp - > ah_cal_list_curr = ahp - > ah_cal_list ;
if ( ahp - > ah_cal_list_curr )
ath9k_hw_reset_calibration ( ah , ahp - > ah_cal_list_curr ) ;
}
ichan - > CalValid = 0 ;
return true ;
}
const struct hal_percal_data iq_cal_multi_sample = {
IQ_MISMATCH_CAL ,
MAX_CAL_SAMPLES ,
PER_MIN_LOG_COUNT ,
ath9k_hw_iqcal_collect ,
ath9k_hw_iqcalibrate
} ;
const struct hal_percal_data iq_cal_single_sample = {
IQ_MISMATCH_CAL ,
MIN_CAL_SAMPLES ,
PER_MAX_LOG_COUNT ,
ath9k_hw_iqcal_collect ,
ath9k_hw_iqcalibrate
} ;
const struct hal_percal_data adc_gain_cal_multi_sample = {
ADC_GAIN_CAL ,
MAX_CAL_SAMPLES ,
PER_MIN_LOG_COUNT ,
ath9k_hw_adc_gaincal_collect ,
ath9k_hw_adc_gaincal_calibrate
} ;
const struct hal_percal_data adc_gain_cal_single_sample = {
ADC_GAIN_CAL ,
MIN_CAL_SAMPLES ,
PER_MAX_LOG_COUNT ,
ath9k_hw_adc_gaincal_collect ,
ath9k_hw_adc_gaincal_calibrate
} ;
const struct hal_percal_data adc_dc_cal_multi_sample = {
ADC_DC_CAL ,
MAX_CAL_SAMPLES ,
PER_MIN_LOG_COUNT ,
ath9k_hw_adc_dccal_collect ,
ath9k_hw_adc_dccal_calibrate
} ;
const struct hal_percal_data adc_dc_cal_single_sample = {
ADC_DC_CAL ,
MIN_CAL_SAMPLES ,
PER_MAX_LOG_COUNT ,
ath9k_hw_adc_dccal_collect ,
ath9k_hw_adc_dccal_calibrate
} ;
const struct hal_percal_data adc_init_dc_cal = {
ADC_DC_INIT_CAL ,
MIN_CAL_SAMPLES ,
INIT_LOG_COUNT ,
ath9k_hw_adc_dccal_collect ,
ath9k_hw_adc_dccal_calibrate
} ;