2010-04-15 17:39:00 -04:00
/*
2011-05-17 13:36:18 +05:30
* Copyright ( c ) 2010 - 2011 Atheros Communications Inc .
2010-04-15 17:39: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 .
*/
# include "hw.h"
# include "hw-ops.h"
# include "ar9003_phy.h"
2011-10-13 11:00:41 +05:30
# include "ar9003_rtt.h"
2011-11-30 10:41:26 +05:30
# include "ar9003_mci.h"
2010-04-15 17:39:00 -04:00
2011-10-13 11:00:35 +05:30
# define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
2011-04-24 21:34:39 +05:30
# define MAX_MAG_DELTA 11
# define MAX_PHS_DELTA 10
2014-02-07 10:29:53 +05:30
# define MAXIQCAL 3
2010-12-06 04:27:56 -08:00
struct coeff {
2014-02-07 10:29:54 +05:30
int mag_coeff [ AR9300_MAX_CHAINS ] [ MAX_MEASUREMENT ] [ MAXIQCAL ] ;
int phs_coeff [ AR9300_MAX_CHAINS ] [ MAX_MEASUREMENT ] [ MAXIQCAL ] ;
2010-12-06 04:27:56 -08:00
int iqc_coeff [ 2 ] ;
} ;
2010-10-03 19:07:16 +02:00
enum ar9003_cal_types {
IQ_MISMATCH_CAL = BIT ( 0 ) ,
} ;
2010-04-15 17:39:00 -04:00
static void ar9003_hw_setup_calibration ( struct ath_hw * ah ,
struct ath9k_cal_list * currCal )
{
2010-04-15 17:39:10 -04:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
/* Select calibration to run */
switch ( currCal - > calData - > calType ) {
case IQ_MISMATCH_CAL :
/*
* Start calibration with
* 2 ^ ( INIT_IQCAL_LOG_COUNT_MAX + 1 ) samples
*/
REG_RMW_FIELD ( ah , AR_PHY_TIMING4 ,
AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX ,
2013-01-03 12:21:23 +05:30
currCal - > calData - > calCountMax ) ;
2010-04-15 17:39:10 -04:00
REG_WRITE ( ah , AR_PHY_CALMODE , AR_PHY_CALMODE_IQ ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" starting IQ Mismatch Calibration \n " ) ;
2010-04-15 17:39:10 -04:00
/* Kick-off cal */
REG_SET_BIT ( ah , AR_PHY_TIMING4 , AR_PHY_TIMING4_DO_CAL ) ;
break ;
2013-01-03 12:21:23 +05:30
default :
ath_err ( common , " Invalid calibration type \n " ) ;
2010-04-15 17:39:10 -04:00
break ;
}
2010-04-15 17:39:00 -04:00
}
2010-04-15 17:39:11 -04:00
/*
* Generic calibration routine .
* Recalibrate the lower PHY chips to account for temperature / environment
* changes .
*/
static bool ar9003_hw_per_calibration ( struct ath_hw * ah ,
struct ath9k_channel * ichan ,
u8 rxchainmask ,
struct ath9k_cal_list * currCal )
{
2010-07-31 00:12:00 +02:00
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
2010-04-15 17:39:11 -04:00
/* Cal is assumed not done until explicitly set below */
bool iscaldone = false ;
/* Calibration in progress. */
if ( currCal - > calState = = CAL_RUNNING ) {
/* Check to see if it has finished. */
if ( ! ( REG_READ ( ah , AR_PHY_TIMING4 ) & AR_PHY_TIMING4_DO_CAL ) ) {
/*
* Accumulate cal measures for active chains
*/
currCal - > calData - > calCollect ( ah ) ;
ah - > cal_samples + + ;
if ( ah - > cal_samples > =
currCal - > calData - > calNumSamples ) {
unsigned int i , numChains = 0 ;
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
if ( rxchainmask & ( 1 < < i ) )
numChains + + ;
}
/*
* Process accumulated data
*/
currCal - > calData - > calPostProc ( ah , numChains ) ;
/* Calibration has finished. */
2010-07-31 00:12:00 +02:00
caldata - > CalValid | = currCal - > calData - > calType ;
2010-04-15 17:39:11 -04:00
currCal - > calState = CAL_DONE ;
iscaldone = true ;
} else {
/*
* Set - up collection of another sub - sample until we
* get desired number
*/
ar9003_hw_setup_calibration ( ah , currCal ) ;
}
}
2010-07-31 00:12:00 +02:00
} else if ( ! ( caldata - > CalValid & currCal - > calData - > calType ) ) {
2010-04-15 17:39:11 -04:00
/* If current cal is marked invalid in channel, kick it off */
ath9k_hw_reset_calibration ( ah , currCal ) ;
}
return iscaldone ;
}
2014-10-25 17:19:30 +02:00
static int ar9003_hw_calibrate ( struct ath_hw * ah , struct ath9k_channel * chan ,
u8 rxchainmask , bool longcal )
2010-04-15 17:39:00 -04:00
{
2010-04-15 17:39:11 -04:00
bool iscaldone = true ;
struct ath9k_cal_list * currCal = ah - > cal_list_curr ;
2014-10-25 17:19:30 +02:00
int ret ;
2010-04-15 17:39:11 -04:00
/*
* For given calibration :
* 1. Call generic cal routine
* 2. When this cal is done ( isCalDone ) if we have more cals waiting
* ( eg after reset ) , mask this to upper layers by not propagating
* isCalDone if it is set to TRUE .
* Instead , change isCalDone to FALSE and setup the waiting cal ( s )
* to be run .
*/
if ( currCal & &
( currCal - > calState = = CAL_RUNNING | |
currCal - > calState = = CAL_WAITING ) ) {
iscaldone = ar9003_hw_per_calibration ( ah , chan ,
rxchainmask , currCal ) ;
if ( iscaldone ) {
ah - > cal_list_curr = currCal = currCal - > calNext ;
if ( currCal - > calState = = CAL_WAITING ) {
iscaldone = false ;
ath9k_hw_reset_calibration ( ah , currCal ) ;
}
}
}
2010-04-15 17:39:00 -04:00
2012-07-01 19:53:52 +05:30
/*
* Do NF cal only at longer intervals . Get the value from
* the previous NF cal and update history buffer .
*/
if ( longcal & & ath9k_hw_getnf ( ah , chan ) ) {
2010-04-15 17:39:11 -04:00
/*
* Load the NF from history buffer of the current channel .
* NF is slow time - variant , so it is OK to use a historical
* value .
*/
2014-10-25 17:19:30 +02:00
ret = ath9k_hw_loadnf ( ah , ah - > curchan ) ;
if ( ret < 0 )
return ret ;
2010-04-15 17:39:11 -04:00
/* start NF calibration, without updating BB NF register */
2010-07-30 21:02:09 +02:00
ath9k_hw_start_nfcal ( ah , false ) ;
2010-04-15 17:39:11 -04:00
}
return iscaldone ;
2010-04-15 17:39:00 -04:00
}
2010-04-15 17:39:01 -04:00
static void ar9003_hw_iqcal_collect ( struct ath_hw * ah )
{
int i ;
/* Accumulate IQ cal measures for active chains */
for ( i = 0 ; i < AR5416_MAX_CHAINS ; i + + ) {
2011-04-19 19:29:16 +05:30
if ( ah - > txchainmask & BIT ( i ) ) {
ah - > totalPowerMeasI [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_0 ( i ) ) ;
ah - > totalPowerMeasQ [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_1 ( i ) ) ;
ah - > totalIqCorrMeas [ i ] + =
( int32_t ) REG_READ ( ah , AR_PHY_CAL_MEAS_2 ( i ) ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( ath9k_hw_common ( ah ) , CALIBRATE ,
2011-04-19 19:29:16 +05:30
" %d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x; \n " ,
ah - > cal_samples , i , ah - > totalPowerMeasI [ i ] ,
ah - > totalPowerMeasQ [ i ] ,
ah - > totalIqCorrMeas [ i ] ) ;
}
2010-04-15 17:39:01 -04:00
}
}
static void ar9003_hw_iqcalibrate ( struct ath_hw * ah , u8 numChains )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
u32 powerMeasQ , powerMeasI , iqCorrMeas ;
u32 qCoffDenom , iCoffDenom ;
int32_t qCoff , iCoff ;
int iqCorrNeg , i ;
2010-11-20 18:38:53 -08:00
static const u_int32_t offset_array [ 3 ] = {
2010-04-15 17:39:01 -04:00
AR_PHY_RX_IQCAL_CORR_B0 ,
AR_PHY_RX_IQCAL_CORR_B1 ,
AR_PHY_RX_IQCAL_CORR_B2 ,
} ;
for ( i = 0 ; i < numChains ; i + + ) {
powerMeasI = ah - > totalPowerMeasI [ i ] ;
powerMeasQ = ah - > totalPowerMeasQ [ i ] ;
iqCorrMeas = ah - > totalIqCorrMeas [ i ] ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
" Starting IQ Cal and Correction for Chain %d \n " , i ) ;
2010-04-15 17:39:01 -04:00
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2011-12-02 22:39:14 -05:00
" Original: Chn %d iq_corr_meas = 0x%08x \n " ,
2010-12-02 19:12:37 -08:00
i , ah - > totalIqCorrMeas [ i ] ) ;
2010-04-15 17:39:01 -04:00
iqCorrNeg = 0 ;
if ( iqCorrMeas > 0x80000000 ) {
iqCorrMeas = ( 0xffffffff - iqCorrMeas ) + 1 ;
iqCorrNeg = 1 ;
}
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " Chn %d pwr_meas_i = 0x%08x \n " ,
i , powerMeasI ) ;
ath_dbg ( common , CALIBRATE , " Chn %d pwr_meas_q = 0x%08x \n " ,
i , powerMeasQ ) ;
ath_dbg ( common , CALIBRATE , " iqCorrNeg is 0x%08x \n " , iqCorrNeg ) ;
2010-04-15 17:39:01 -04:00
iCoffDenom = ( powerMeasI / 2 + powerMeasQ / 2 ) / 256 ;
qCoffDenom = powerMeasQ / 64 ;
if ( ( iCoffDenom ! = 0 ) & & ( qCoffDenom ! = 0 ) ) {
iCoff = iqCorrMeas / iCoffDenom ;
qCoff = powerMeasI / qCoffDenom - 64 ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " Chn %d iCoff = 0x%08x \n " ,
i , iCoff ) ;
ath_dbg ( common , CALIBRATE , " Chn %d qCoff = 0x%08x \n " ,
i , qCoff ) ;
2010-04-15 17:39:01 -04:00
/* Force bounds on iCoff */
if ( iCoff > = 63 )
iCoff = 63 ;
else if ( iCoff < = - 63 )
iCoff = - 63 ;
/* Negate iCoff if iqCorrNeg == 0 */
if ( iqCorrNeg = = 0x0 )
iCoff = - iCoff ;
/* Force bounds on qCoff */
if ( qCoff > = 63 )
qCoff = 63 ;
else if ( qCoff < = - 63 )
qCoff = - 63 ;
iCoff = iCoff & 0x7f ;
qCoff = qCoff & 0x7f ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" Chn %d : iCoff = 0x%x qCoff = 0x%x \n " ,
i , iCoff , qCoff ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" Register offset (0x%04x) before update = 0x%x \n " ,
offset_array [ i ] ,
REG_READ ( ah , offset_array [ i ] ) ) ;
2010-04-15 17:39:01 -04:00
2012-10-15 15:29:51 +05:30
if ( AR_SREV_9565 ( ah ) & &
( iCoff = = 63 | | qCoff = = 63 | |
iCoff = = - 63 | | qCoff = = - 63 ) )
return ;
2010-04-15 17:39:01 -04:00
REG_RMW_FIELD ( ah , offset_array [ i ] ,
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF ,
iCoff ) ;
REG_RMW_FIELD ( ah , offset_array [ i ] ,
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF ,
qCoff ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x \n " ,
offset_array [ i ] ,
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF ,
REG_READ ( ah , offset_array [ i ] ) ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x \n " ,
offset_array [ i ] ,
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF ,
REG_READ ( ah , offset_array [ i ] ) ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" IQ Cal and Correction done for Chain %d \n " , i ) ;
2010-04-15 17:39:01 -04:00
}
}
REG_SET_BIT ( ah , AR_PHY_RX_IQCAL_CORR_B0 ,
AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x \n " ,
( unsigned ) ( AR_PHY_RX_IQCAL_CORR_B0 ) ,
AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE ,
REG_READ ( ah , AR_PHY_RX_IQCAL_CORR_B0 ) ) ;
2010-04-15 17:39:01 -04:00
}
static const struct ath9k_percal_data iq_cal_single_sample = {
IQ_MISMATCH_CAL ,
MIN_CAL_SAMPLES ,
PER_MAX_LOG_COUNT ,
ar9003_hw_iqcal_collect ,
ar9003_hw_iqcalibrate
} ;
2010-04-15 17:39:00 -04:00
static void ar9003_hw_init_cal_settings ( struct ath_hw * ah )
{
2010-04-15 17:39:01 -04:00
ah - > iq_caldata . calData = & iq_cal_single_sample ;
2013-01-03 12:21:21 +05:30
if ( AR_SREV_9300_20_OR_LATER ( ah ) ) {
ah - > enabled_cals | = TX_IQ_CAL ;
2013-01-03 14:55:48 +05:30
if ( AR_SREV_9485_OR_LATER ( ah ) & & ! AR_SREV_9340 ( ah ) )
2013-01-03 12:21:21 +05:30
ah - > enabled_cals | = TX_IQ_ON_AGC_CAL ;
}
ah - > supp_cals = IQ_MISMATCH_CAL ;
2010-04-15 17:39:00 -04:00
}
2014-01-02 10:06:21 +05:30
# define OFF_UPPER_LT 24
# define OFF_LOWER_LT 7
static bool ar9003_hw_dynamic_osdac_selection ( struct ath_hw * ah ,
bool txiqcal_done )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
int ch0_done , osdac_ch0 , dc_off_ch0_i1 , dc_off_ch0_q1 , dc_off_ch0_i2 ,
dc_off_ch0_q2 , dc_off_ch0_i3 , dc_off_ch0_q3 ;
int ch1_done , osdac_ch1 , dc_off_ch1_i1 , dc_off_ch1_q1 , dc_off_ch1_i2 ,
dc_off_ch1_q2 , dc_off_ch1_i3 , dc_off_ch1_q3 ;
int ch2_done , osdac_ch2 , dc_off_ch2_i1 , dc_off_ch2_q1 , dc_off_ch2_i2 ,
dc_off_ch2_q2 , dc_off_ch2_i3 , dc_off_ch2_q3 ;
bool status ;
u32 temp , val ;
/*
* Clear offset and IQ calibration , run AGC cal .
*/
REG_CLR_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_OFFSET_CAL ) ;
REG_CLR_BIT ( ah , AR_PHY_TX_IQCAL_CONTROL_0 ,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL ) ;
REG_WRITE ( ah , AR_PHY_AGC_CONTROL ,
REG_READ ( ah , AR_PHY_AGC_CONTROL ) | AR_PHY_AGC_CONTROL_CAL ) ;
status = ath9k_hw_wait ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_CAL ,
0 , AH_WAIT_TIMEOUT ) ;
if ( ! status ) {
ath_dbg ( common , CALIBRATE ,
" AGC cal without offset cal failed to complete in 1ms " ) ;
return false ;
}
/*
* Allow only offset calibration and disable the others
* ( Carrier Leak calibration , TX Filter calibration and
* Peak Detector offset calibration ) .
*/
REG_SET_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_OFFSET_CAL ) ;
REG_CLR_BIT ( ah , AR_PHY_CL_CAL_CTL ,
AR_PHY_CL_CAL_ENABLE ) ;
REG_CLR_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_FLTR_CAL ) ;
REG_CLR_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_PKDET_CAL ) ;
ch0_done = 0 ;
ch1_done = 0 ;
ch2_done = 0 ;
while ( ( ch0_done = = 0 ) | | ( ch1_done = = 0 ) | | ( ch2_done = = 0 ) ) {
osdac_ch0 = ( REG_READ ( ah , AR_PHY_65NM_CH0_BB1 ) > > 30 ) & 0x3 ;
osdac_ch1 = ( REG_READ ( ah , AR_PHY_65NM_CH1_BB1 ) > > 30 ) & 0x3 ;
osdac_ch2 = ( REG_READ ( ah , AR_PHY_65NM_CH2_BB1 ) > > 30 ) & 0x3 ;
REG_SET_BIT ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_EN ) ;
REG_WRITE ( ah , AR_PHY_AGC_CONTROL ,
REG_READ ( ah , AR_PHY_AGC_CONTROL ) | AR_PHY_AGC_CONTROL_CAL ) ;
status = ath9k_hw_wait ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_CAL ,
0 , AH_WAIT_TIMEOUT ) ;
if ( ! status ) {
ath_dbg ( common , CALIBRATE ,
" DC offset cal failed to complete in 1ms " ) ;
return false ;
}
REG_CLR_BIT ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_EN ) ;
/*
* High gain .
*/
REG_WRITE ( ah , AR_PHY_65NM_CH0_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH0_BB3 ) & 0xfffffcff ) | ( 1 < < 8 ) ) ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH1_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH1_BB3 ) & 0xfffffcff ) | ( 1 < < 8 ) ) ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH2_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH2_BB3 ) & 0xfffffcff ) | ( 1 < < 8 ) ) ) ;
temp = REG_READ ( ah , AR_PHY_65NM_CH0_BB3 ) ;
dc_off_ch0_i1 = ( temp > > 26 ) & 0x1f ;
dc_off_ch0_q1 = ( temp > > 21 ) & 0x1f ;
temp = REG_READ ( ah , AR_PHY_65NM_CH1_BB3 ) ;
dc_off_ch1_i1 = ( temp > > 26 ) & 0x1f ;
dc_off_ch1_q1 = ( temp > > 21 ) & 0x1f ;
temp = REG_READ ( ah , AR_PHY_65NM_CH2_BB3 ) ;
dc_off_ch2_i1 = ( temp > > 26 ) & 0x1f ;
dc_off_ch2_q1 = ( temp > > 21 ) & 0x1f ;
/*
* Low gain .
*/
REG_WRITE ( ah , AR_PHY_65NM_CH0_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH0_BB3 ) & 0xfffffcff ) | ( 2 < < 8 ) ) ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH1_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH1_BB3 ) & 0xfffffcff ) | ( 2 < < 8 ) ) ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH2_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH2_BB3 ) & 0xfffffcff ) | ( 2 < < 8 ) ) ) ;
temp = REG_READ ( ah , AR_PHY_65NM_CH0_BB3 ) ;
dc_off_ch0_i2 = ( temp > > 26 ) & 0x1f ;
dc_off_ch0_q2 = ( temp > > 21 ) & 0x1f ;
temp = REG_READ ( ah , AR_PHY_65NM_CH1_BB3 ) ;
dc_off_ch1_i2 = ( temp > > 26 ) & 0x1f ;
dc_off_ch1_q2 = ( temp > > 21 ) & 0x1f ;
temp = REG_READ ( ah , AR_PHY_65NM_CH2_BB3 ) ;
dc_off_ch2_i2 = ( temp > > 26 ) & 0x1f ;
dc_off_ch2_q2 = ( temp > > 21 ) & 0x1f ;
/*
* Loopback .
*/
REG_WRITE ( ah , AR_PHY_65NM_CH0_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH0_BB3 ) & 0xfffffcff ) | ( 3 < < 8 ) ) ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH1_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH1_BB3 ) & 0xfffffcff ) | ( 3 < < 8 ) ) ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH2_BB3 ,
( ( REG_READ ( ah , AR_PHY_65NM_CH2_BB3 ) & 0xfffffcff ) | ( 3 < < 8 ) ) ) ;
temp = REG_READ ( ah , AR_PHY_65NM_CH0_BB3 ) ;
dc_off_ch0_i3 = ( temp > > 26 ) & 0x1f ;
dc_off_ch0_q3 = ( temp > > 21 ) & 0x1f ;
temp = REG_READ ( ah , AR_PHY_65NM_CH1_BB3 ) ;
dc_off_ch1_i3 = ( temp > > 26 ) & 0x1f ;
dc_off_ch1_q3 = ( temp > > 21 ) & 0x1f ;
temp = REG_READ ( ah , AR_PHY_65NM_CH2_BB3 ) ;
dc_off_ch2_i3 = ( temp > > 26 ) & 0x1f ;
dc_off_ch2_q3 = ( temp > > 21 ) & 0x1f ;
if ( ( dc_off_ch0_i1 > OFF_UPPER_LT ) | | ( dc_off_ch0_i1 < OFF_LOWER_LT ) | |
( dc_off_ch0_i2 > OFF_UPPER_LT ) | | ( dc_off_ch0_i2 < OFF_LOWER_LT ) | |
( dc_off_ch0_i3 > OFF_UPPER_LT ) | | ( dc_off_ch0_i3 < OFF_LOWER_LT ) | |
( dc_off_ch0_q1 > OFF_UPPER_LT ) | | ( dc_off_ch0_q1 < OFF_LOWER_LT ) | |
( dc_off_ch0_q2 > OFF_UPPER_LT ) | | ( dc_off_ch0_q2 < OFF_LOWER_LT ) | |
( dc_off_ch0_q3 > OFF_UPPER_LT ) | | ( dc_off_ch0_q3 < OFF_LOWER_LT ) ) {
if ( osdac_ch0 = = 3 ) {
ch0_done = 1 ;
} else {
osdac_ch0 + + ;
val = REG_READ ( ah , AR_PHY_65NM_CH0_BB1 ) & 0x3fffffff ;
val | = ( osdac_ch0 < < 30 ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH0_BB1 , val ) ;
ch0_done = 0 ;
}
} else {
ch0_done = 1 ;
}
if ( ( dc_off_ch1_i1 > OFF_UPPER_LT ) | | ( dc_off_ch1_i1 < OFF_LOWER_LT ) | |
( dc_off_ch1_i2 > OFF_UPPER_LT ) | | ( dc_off_ch1_i2 < OFF_LOWER_LT ) | |
( dc_off_ch1_i3 > OFF_UPPER_LT ) | | ( dc_off_ch1_i3 < OFF_LOWER_LT ) | |
( dc_off_ch1_q1 > OFF_UPPER_LT ) | | ( dc_off_ch1_q1 < OFF_LOWER_LT ) | |
( dc_off_ch1_q2 > OFF_UPPER_LT ) | | ( dc_off_ch1_q2 < OFF_LOWER_LT ) | |
( dc_off_ch1_q3 > OFF_UPPER_LT ) | | ( dc_off_ch1_q3 < OFF_LOWER_LT ) ) {
if ( osdac_ch1 = = 3 ) {
ch1_done = 1 ;
} else {
osdac_ch1 + + ;
val = REG_READ ( ah , AR_PHY_65NM_CH1_BB1 ) & 0x3fffffff ;
val | = ( osdac_ch1 < < 30 ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH1_BB1 , val ) ;
ch1_done = 0 ;
}
} else {
ch1_done = 1 ;
}
if ( ( dc_off_ch2_i1 > OFF_UPPER_LT ) | | ( dc_off_ch2_i1 < OFF_LOWER_LT ) | |
( dc_off_ch2_i2 > OFF_UPPER_LT ) | | ( dc_off_ch2_i2 < OFF_LOWER_LT ) | |
( dc_off_ch2_i3 > OFF_UPPER_LT ) | | ( dc_off_ch2_i3 < OFF_LOWER_LT ) | |
( dc_off_ch2_q1 > OFF_UPPER_LT ) | | ( dc_off_ch2_q1 < OFF_LOWER_LT ) | |
( dc_off_ch2_q2 > OFF_UPPER_LT ) | | ( dc_off_ch2_q2 < OFF_LOWER_LT ) | |
( dc_off_ch2_q3 > OFF_UPPER_LT ) | | ( dc_off_ch2_q3 < OFF_LOWER_LT ) ) {
if ( osdac_ch2 = = 3 ) {
ch2_done = 1 ;
} else {
osdac_ch2 + + ;
val = REG_READ ( ah , AR_PHY_65NM_CH2_BB1 ) & 0x3fffffff ;
val | = ( osdac_ch2 < < 30 ) ;
REG_WRITE ( ah , AR_PHY_65NM_CH2_BB1 , val ) ;
ch2_done = 0 ;
}
} else {
ch2_done = 1 ;
}
}
REG_CLR_BIT ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_OFFSET_CAL ) ;
REG_SET_BIT ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_EN ) ;
/*
* We don ' t need to check txiqcal_done here since it is always
* set for AR9550 .
*/
REG_SET_BIT ( ah , AR_PHY_TX_IQCAL_CONTROL_0 ,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL ) ;
return true ;
}
2010-04-15 17:39:11 -04:00
/*
* solve 4 x4 linear equation used in loopback iq cal .
*/
static bool ar9003_hw_solve_iq_cal ( struct ath_hw * ah ,
s32 sin_2phi_1 ,
s32 cos_2phi_1 ,
s32 sin_2phi_2 ,
s32 cos_2phi_2 ,
s32 mag_a0_d0 ,
s32 phs_a0_d0 ,
s32 mag_a1_d0 ,
s32 phs_a1_d0 ,
s32 solved_eq [ ] )
{
s32 f1 = cos_2phi_1 - cos_2phi_2 ,
f3 = sin_2phi_1 - sin_2phi_2 ,
f2 ;
s32 mag_tx , phs_tx , mag_rx , phs_rx ;
const s32 result_shift = 1 < < 15 ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
2014-01-14 13:41:17 +05:30
f2 = ( ( f1 > > 3 ) * ( f1 > > 3 ) + ( f3 > > 3 ) * ( f3 > > 3 ) ) > > 9 ;
2010-04-15 17:39:11 -04:00
if ( ! f2 ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " Divide by 0 \n " ) ;
2010-04-15 17:39:11 -04:00
return false ;
}
/* mag mismatch, tx */
mag_tx = f1 * ( mag_a0_d0 - mag_a1_d0 ) + f3 * ( phs_a0_d0 - phs_a1_d0 ) ;
/* phs mismatch, tx */
phs_tx = f3 * ( - mag_a0_d0 + mag_a1_d0 ) + f1 * ( phs_a0_d0 - phs_a1_d0 ) ;
mag_tx = ( mag_tx / f2 ) ;
phs_tx = ( phs_tx / f2 ) ;
/* mag mismatch, rx */
mag_rx = mag_a0_d0 - ( cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx ) /
result_shift ;
/* phs mismatch, rx */
phs_rx = phs_a0_d0 + ( sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx ) /
result_shift ;
solved_eq [ 0 ] = mag_tx ;
solved_eq [ 1 ] = phs_tx ;
solved_eq [ 2 ] = mag_rx ;
solved_eq [ 3 ] = phs_rx ;
return true ;
}
static s32 ar9003_hw_find_mag_approx ( struct ath_hw * ah , s32 in_re , s32 in_im )
2010-04-15 17:39:09 -04:00
{
2010-04-15 17:39:11 -04:00
s32 abs_i = abs ( in_re ) ,
abs_q = abs ( in_im ) ,
max_abs , min_abs ;
if ( abs_i > abs_q ) {
max_abs = abs_i ;
min_abs = abs_q ;
} else {
max_abs = abs_q ;
min_abs = abs_i ;
}
return max_abs - ( max_abs / 32 ) + ( min_abs / 8 ) + ( min_abs / 4 ) ;
}
# define DELPT 32
static bool ar9003_hw_calc_iq_corr ( struct ath_hw * ah ,
s32 chain_idx ,
const s32 iq_res [ ] ,
s32 iqc_coeff [ ] )
{
s32 i2_m_q2_a0_d0 , i2_p_q2_a0_d0 , iq_corr_a0_d0 ,
i2_m_q2_a0_d1 , i2_p_q2_a0_d1 , iq_corr_a0_d1 ,
i2_m_q2_a1_d0 , i2_p_q2_a1_d0 , iq_corr_a1_d0 ,
i2_m_q2_a1_d1 , i2_p_q2_a1_d1 , iq_corr_a1_d1 ;
s32 mag_a0_d0 , mag_a1_d0 , mag_a0_d1 , mag_a1_d1 ,
phs_a0_d0 , phs_a1_d0 , phs_a0_d1 , phs_a1_d1 ,
sin_2phi_1 , cos_2phi_1 ,
sin_2phi_2 , cos_2phi_2 ;
s32 mag_tx , phs_tx , mag_rx , phs_rx ;
s32 solved_eq [ 4 ] , mag_corr_tx , phs_corr_tx , mag_corr_rx , phs_corr_rx ,
q_q_coff , q_i_coff ;
const s32 res_scale = 1 < < 15 ;
const s32 delpt_shift = 1 < < 8 ;
s32 mag1 , mag2 ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
i2_m_q2_a0_d0 = iq_res [ 0 ] & 0xfff ;
i2_p_q2_a0_d0 = ( iq_res [ 0 ] > > 12 ) & 0xfff ;
iq_corr_a0_d0 = ( ( iq_res [ 0 ] > > 24 ) & 0xff ) + ( ( iq_res [ 1 ] & 0xf ) < < 8 ) ;
if ( i2_m_q2_a0_d0 > 0x800 )
i2_m_q2_a0_d0 = - ( ( 0xfff - i2_m_q2_a0_d0 ) + 1 ) ;
if ( i2_p_q2_a0_d0 > 0x800 )
i2_p_q2_a0_d0 = - ( ( 0xfff - i2_p_q2_a0_d0 ) + 1 ) ;
if ( iq_corr_a0_d0 > 0x800 )
iq_corr_a0_d0 = - ( ( 0xfff - iq_corr_a0_d0 ) + 1 ) ;
i2_m_q2_a0_d1 = ( iq_res [ 1 ] > > 4 ) & 0xfff ;
i2_p_q2_a0_d1 = ( iq_res [ 2 ] & 0xfff ) ;
iq_corr_a0_d1 = ( iq_res [ 2 ] > > 12 ) & 0xfff ;
if ( i2_m_q2_a0_d1 > 0x800 )
i2_m_q2_a0_d1 = - ( ( 0xfff - i2_m_q2_a0_d1 ) + 1 ) ;
if ( iq_corr_a0_d1 > 0x800 )
iq_corr_a0_d1 = - ( ( 0xfff - iq_corr_a0_d1 ) + 1 ) ;
i2_m_q2_a1_d0 = ( ( iq_res [ 2 ] > > 24 ) & 0xff ) + ( ( iq_res [ 3 ] & 0xf ) < < 8 ) ;
i2_p_q2_a1_d0 = ( iq_res [ 3 ] > > 4 ) & 0xfff ;
iq_corr_a1_d0 = iq_res [ 4 ] & 0xfff ;
if ( i2_m_q2_a1_d0 > 0x800 )
i2_m_q2_a1_d0 = - ( ( 0xfff - i2_m_q2_a1_d0 ) + 1 ) ;
if ( i2_p_q2_a1_d0 > 0x800 )
i2_p_q2_a1_d0 = - ( ( 0xfff - i2_p_q2_a1_d0 ) + 1 ) ;
if ( iq_corr_a1_d0 > 0x800 )
iq_corr_a1_d0 = - ( ( 0xfff - iq_corr_a1_d0 ) + 1 ) ;
i2_m_q2_a1_d1 = ( iq_res [ 4 ] > > 12 ) & 0xfff ;
i2_p_q2_a1_d1 = ( ( iq_res [ 4 ] > > 24 ) & 0xff ) + ( ( iq_res [ 5 ] & 0xf ) < < 8 ) ;
iq_corr_a1_d1 = ( iq_res [ 5 ] > > 4 ) & 0xfff ;
if ( i2_m_q2_a1_d1 > 0x800 )
i2_m_q2_a1_d1 = - ( ( 0xfff - i2_m_q2_a1_d1 ) + 1 ) ;
if ( i2_p_q2_a1_d1 > 0x800 )
i2_p_q2_a1_d1 = - ( ( 0xfff - i2_p_q2_a1_d1 ) + 1 ) ;
if ( iq_corr_a1_d1 > 0x800 )
iq_corr_a1_d1 = - ( ( 0xfff - iq_corr_a1_d1 ) + 1 ) ;
if ( ( i2_p_q2_a0_d0 = = 0 ) | | ( i2_p_q2_a0_d1 = = 0 ) | |
( i2_p_q2_a1_d0 = = 0 ) | | ( i2_p_q2_a1_d1 = = 0 ) ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" Divide by 0: \n "
" a0_d0=%d \n "
" a0_d1=%d \n "
" a2_d0=%d \n "
" a1_d1=%d \n " ,
i2_p_q2_a0_d0 , i2_p_q2_a0_d1 ,
i2_p_q2_a1_d0 , i2_p_q2_a1_d1 ) ;
2010-04-15 17:39:11 -04:00
return false ;
}
2014-01-14 13:25:17 +05:30
if ( ( i2_p_q2_a0_d0 < 1024 ) | | ( i2_p_q2_a0_d0 > 2047 ) | |
( i2_p_q2_a1_d0 < 0 ) | | ( i2_p_q2_a1_d1 < 0 ) | |
( i2_p_q2_a0_d0 < = i2_m_q2_a0_d0 ) | |
( i2_p_q2_a0_d0 < = iq_corr_a0_d0 ) | |
( i2_p_q2_a0_d1 < = i2_m_q2_a0_d1 ) | |
( i2_p_q2_a0_d1 < = iq_corr_a0_d1 ) | |
( i2_p_q2_a1_d0 < = i2_m_q2_a1_d0 ) | |
( i2_p_q2_a1_d0 < = iq_corr_a1_d0 ) | |
( i2_p_q2_a1_d1 < = i2_m_q2_a1_d1 ) | |
( i2_p_q2_a1_d1 < = iq_corr_a1_d1 ) ) {
return false ;
}
2010-04-15 17:39:11 -04:00
mag_a0_d0 = ( i2_m_q2_a0_d0 * res_scale ) / i2_p_q2_a0_d0 ;
phs_a0_d0 = ( iq_corr_a0_d0 * res_scale ) / i2_p_q2_a0_d0 ;
mag_a0_d1 = ( i2_m_q2_a0_d1 * res_scale ) / i2_p_q2_a0_d1 ;
phs_a0_d1 = ( iq_corr_a0_d1 * res_scale ) / i2_p_q2_a0_d1 ;
mag_a1_d0 = ( i2_m_q2_a1_d0 * res_scale ) / i2_p_q2_a1_d0 ;
phs_a1_d0 = ( iq_corr_a1_d0 * res_scale ) / i2_p_q2_a1_d0 ;
mag_a1_d1 = ( i2_m_q2_a1_d1 * res_scale ) / i2_p_q2_a1_d1 ;
phs_a1_d1 = ( iq_corr_a1_d1 * res_scale ) / i2_p_q2_a1_d1 ;
/* w/o analog phase shift */
sin_2phi_1 = ( ( ( mag_a0_d0 - mag_a0_d1 ) * delpt_shift ) / DELPT ) ;
/* w/o analog phase shift */
cos_2phi_1 = ( ( ( phs_a0_d1 - phs_a0_d0 ) * delpt_shift ) / DELPT ) ;
/* w/ analog phase shift */
sin_2phi_2 = ( ( ( mag_a1_d0 - mag_a1_d1 ) * delpt_shift ) / DELPT ) ;
/* w/ analog phase shift */
cos_2phi_2 = ( ( ( phs_a1_d1 - phs_a1_d0 ) * delpt_shift ) / DELPT ) ;
/*
* force sin ^ 2 + cos ^ 2 = 1 ;
* find magnitude by approximation
*/
mag1 = ar9003_hw_find_mag_approx ( ah , cos_2phi_1 , sin_2phi_1 ) ;
mag2 = ar9003_hw_find_mag_approx ( ah , cos_2phi_2 , sin_2phi_2 ) ;
if ( ( mag1 = = 0 ) | | ( mag2 = = 0 ) ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " Divide by 0: mag1=%d, mag2=%d \n " ,
2010-12-02 19:12:37 -08:00
mag1 , mag2 ) ;
2010-04-15 17:39:11 -04:00
return false ;
}
/* normalization sin and cos by mag */
sin_2phi_1 = ( sin_2phi_1 * res_scale / mag1 ) ;
cos_2phi_1 = ( cos_2phi_1 * res_scale / mag1 ) ;
sin_2phi_2 = ( sin_2phi_2 * res_scale / mag2 ) ;
cos_2phi_2 = ( cos_2phi_2 * res_scale / mag2 ) ;
/* calculate IQ mismatch */
if ( ! ar9003_hw_solve_iq_cal ( ah ,
sin_2phi_1 , cos_2phi_1 ,
sin_2phi_2 , cos_2phi_2 ,
mag_a0_d0 , phs_a0_d0 ,
mag_a1_d0 ,
phs_a1_d0 , solved_eq ) ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
" Call to ar9003_hw_solve_iq_cal() failed \n " ) ;
2010-04-15 17:39:11 -04:00
return false ;
}
mag_tx = solved_eq [ 0 ] ;
phs_tx = solved_eq [ 1 ] ;
mag_rx = solved_eq [ 2 ] ;
phs_rx = solved_eq [ 3 ] ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" chain %d: mag mismatch=%d phase mismatch=%d \n " ,
chain_idx , mag_tx / res_scale , phs_tx / res_scale ) ;
2010-04-15 17:39:11 -04:00
if ( res_scale = = mag_tx ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" Divide by 0: mag_tx=%d, res_scale=%d \n " ,
mag_tx , res_scale ) ;
2010-04-15 17:39:11 -04:00
return false ;
}
/* calculate and quantize Tx IQ correction factor */
mag_corr_tx = ( mag_tx * res_scale ) / ( res_scale - mag_tx ) ;
phs_corr_tx = - phs_tx ;
q_q_coff = ( mag_corr_tx * 128 / res_scale ) ;
q_i_coff = ( phs_corr_tx * 256 / res_scale ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " tx chain %d: mag corr=%d phase corr=%d \n " ,
2010-12-02 19:12:37 -08:00
chain_idx , q_q_coff , q_i_coff ) ;
2010-04-15 17:39:11 -04:00
if ( q_i_coff < - 63 )
q_i_coff = - 63 ;
if ( q_i_coff > 63 )
q_i_coff = 63 ;
if ( q_q_coff < - 63 )
q_q_coff = - 63 ;
if ( q_q_coff > 63 )
q_q_coff = 63 ;
2014-02-07 10:29:53 +05:30
iqc_coeff [ 0 ] = ( q_q_coff * 128 ) + ( 0x7f & q_i_coff ) ;
2010-04-15 17:39:11 -04:00
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " tx chain %d: iq corr coeff=%x \n " ,
2010-12-02 19:12:37 -08:00
chain_idx , iqc_coeff [ 0 ] ) ;
2010-04-15 17:39:11 -04:00
if ( - mag_rx = = res_scale ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
2010-12-02 19:12:37 -08:00
" Divide by 0: mag_rx=%d, res_scale=%d \n " ,
mag_rx , res_scale ) ;
2010-04-15 17:39:11 -04:00
return false ;
}
/* calculate and quantize Rx IQ correction factors */
mag_corr_rx = ( - mag_rx * res_scale ) / ( res_scale + mag_rx ) ;
phs_corr_rx = - phs_rx ;
q_q_coff = ( mag_corr_rx * 128 / res_scale ) ;
q_i_coff = ( phs_corr_rx * 256 / res_scale ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " rx chain %d: mag corr=%d phase corr=%d \n " ,
2010-12-02 19:12:37 -08:00
chain_idx , q_q_coff , q_i_coff ) ;
2010-04-15 17:39:11 -04:00
if ( q_i_coff < - 63 )
q_i_coff = - 63 ;
if ( q_i_coff > 63 )
q_i_coff = 63 ;
if ( q_q_coff < - 63 )
q_q_coff = - 63 ;
if ( q_q_coff > 63 )
q_q_coff = 63 ;
2014-02-07 10:29:53 +05:30
iqc_coeff [ 1 ] = ( q_q_coff * 128 ) + ( 0x7f & q_i_coff ) ;
2010-04-15 17:39:11 -04:00
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " rx chain %d: iq corr coeff=%x \n " ,
2010-12-02 19:12:37 -08:00
chain_idx , iqc_coeff [ 1 ] ) ;
2010-04-15 17:39:11 -04:00
return true ;
}
2014-02-07 10:29:54 +05:30
static void ar9003_hw_detect_outlier ( int mp_coeff [ ] [ MAXIQCAL ] ,
int nmeasurement ,
2011-04-24 21:34:39 +05:30
int max_delta )
2010-12-06 04:27:56 -08:00
{
2011-04-24 21:34:39 +05:30
int mp_max = - 64 , max_idx = 0 ;
int mp_min = 63 , min_idx = 0 ;
2011-09-06 21:59:51 +05:30
int mp_avg = 0 , i , outlier_idx = 0 , mp_count = 0 ;
2011-04-24 21:34:39 +05:30
/* find min/max mismatch across all calibrated gains */
for ( i = 0 ; i < nmeasurement ; i + + ) {
2014-02-07 10:29:54 +05:30
if ( mp_coeff [ i ] [ 0 ] > mp_max ) {
mp_max = mp_coeff [ i ] [ 0 ] ;
2011-04-24 21:34:39 +05:30
max_idx = i ;
2014-02-07 10:29:54 +05:30
} else if ( mp_coeff [ i ] [ 0 ] < mp_min ) {
mp_min = mp_coeff [ i ] [ 0 ] ;
2011-04-24 21:34:39 +05:30
min_idx = i ;
}
}
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
/* find average (exclude max abs value) */
for ( i = 0 ; i < nmeasurement ; i + + ) {
2014-02-07 10:29:54 +05:30
if ( ( abs ( mp_coeff [ i ] [ 0 ] ) < abs ( mp_max ) ) | |
( abs ( mp_coeff [ i ] [ 0 ] ) < abs ( mp_min ) ) ) {
mp_avg + = mp_coeff [ i ] [ 0 ] ;
2011-09-06 21:59:51 +05:30
mp_count + + ;
}
2011-04-24 21:34:39 +05:30
}
2011-09-06 21:59:51 +05:30
/*
* finding mean magnitude / phase if possible , otherwise
* just use the last value as the mean
*/
if ( mp_count )
mp_avg / = mp_count ;
else
2014-02-07 10:29:54 +05:30
mp_avg = mp_coeff [ nmeasurement - 1 ] [ 0 ] ;
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
/* detect outlier */
if ( abs ( mp_max - mp_min ) > max_delta ) {
if ( abs ( mp_max - mp_avg ) > abs ( mp_min - mp_avg ) )
outlier_idx = max_idx ;
else
outlier_idx = min_idx ;
2011-09-15 19:02:25 +05:30
2014-02-07 10:29:54 +05:30
mp_coeff [ outlier_idx ] [ 0 ] = mp_avg ;
2011-04-24 21:34:39 +05:30
}
2010-12-06 04:27:56 -08:00
}
2014-02-07 10:29:51 +05:30
static void ar9003_hw_tx_iq_cal_outlier_detection ( struct ath_hw * ah ,
struct coeff * coeff ,
bool is_reusable )
2010-12-06 04:27:56 -08:00
{
int i , im , nmeasurement ;
2014-02-07 10:29:52 +05:30
int magnitude , phase ;
2010-12-06 04:27:56 -08:00
u32 tx_corr_coeff [ MAX_MEASUREMENT ] [ AR9300_MAX_CHAINS ] ;
2011-10-13 11:00:35 +05:30
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
2010-12-06 04:27:56 -08:00
memset ( tx_corr_coeff , 0 , sizeof ( tx_corr_coeff ) ) ;
for ( i = 0 ; i < MAX_MEASUREMENT / 2 ; i + + ) {
tx_corr_coeff [ i * 2 ] [ 0 ] = tx_corr_coeff [ ( i * 2 ) + 1 ] [ 0 ] =
AR_PHY_TX_IQCAL_CORR_COEFF_B0 ( i ) ;
if ( ! AR_SREV_9485 ( ah ) ) {
tx_corr_coeff [ i * 2 ] [ 1 ] =
tx_corr_coeff [ ( i * 2 ) + 1 ] [ 1 ] =
AR_PHY_TX_IQCAL_CORR_COEFF_B1 ( i ) ;
tx_corr_coeff [ i * 2 ] [ 2 ] =
tx_corr_coeff [ ( i * 2 ) + 1 ] [ 2 ] =
AR_PHY_TX_IQCAL_CORR_COEFF_B2 ( i ) ;
}
}
/* Load the average of 2 passes */
2012-06-04 16:28:14 +05:30
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
if ( ! ( ah - > txchainmask & ( 1 < < i ) ) )
continue ;
2011-04-24 21:34:39 +05:30
nmeasurement = REG_READ_FIELD ( ah ,
AR_PHY_TX_IQCAL_STATUS_B0 ,
AR_PHY_CALIBRATED_GAINS_0 ) ;
2010-12-06 04:27:56 -08:00
if ( nmeasurement > MAX_MEASUREMENT )
nmeasurement = MAX_MEASUREMENT ;
2014-02-07 10:29:55 +05:30
/*
* Skip normal outlier detection for AR9550 .
*/
if ( ! AR_SREV_9550 ( ah ) ) {
/* detect outlier only if nmeasurement > 1 */
if ( nmeasurement > 1 ) {
/* Detect magnitude outlier */
ar9003_hw_detect_outlier ( coeff - > mag_coeff [ i ] ,
nmeasurement ,
MAX_MAG_DELTA ) ;
/* Detect phase outlier */
ar9003_hw_detect_outlier ( coeff - > phs_coeff [ i ] ,
nmeasurement ,
MAX_PHS_DELTA ) ;
}
2011-04-24 21:34:39 +05:30
}
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
for ( im = 0 ; im < nmeasurement ; im + + ) {
2014-02-07 10:29:54 +05:30
magnitude = coeff - > mag_coeff [ i ] [ im ] [ 0 ] ;
phase = coeff - > phs_coeff [ i ] [ im ] [ 0 ] ;
2011-04-24 21:34:39 +05:30
2014-02-07 10:29:52 +05:30
coeff - > iqc_coeff [ 0 ] =
( phase & 0x7f ) | ( ( magnitude & 0x7f ) < < 7 ) ;
2010-12-06 04:27:56 -08:00
if ( ( im % 2 ) = = 0 )
REG_RMW_FIELD ( ah , tx_corr_coeff [ im ] [ i ] ,
AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE ,
coeff - > iqc_coeff [ 0 ] ) ;
else
REG_RMW_FIELD ( ah , tx_corr_coeff [ im ] [ i ] ,
AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE ,
coeff - > iqc_coeff [ 0 ] ) ;
2011-10-13 11:00:35 +05:30
if ( caldata )
caldata - > tx_corr_coeff [ im ] [ i ] =
coeff - > iqc_coeff [ 0 ] ;
2010-12-06 04:27:56 -08:00
}
2011-10-13 11:00:35 +05:30
if ( caldata )
caldata - > num_measures [ i ] = nmeasurement ;
2010-12-06 04:27:56 -08:00
}
REG_RMW_FIELD ( ah , AR_PHY_TX_IQCAL_CONTROL_3 ,
AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN , 0x1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_RX_IQCAL_CORR_B0 ,
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN , 0x1 ) ;
2011-10-13 11:00:36 +05:30
2013-09-11 16:36:31 +05:30
if ( caldata ) {
if ( is_reusable )
set_bit ( TXIQCAL_DONE , & caldata - > cal_flags ) ;
else
clear_bit ( TXIQCAL_DONE , & caldata - > cal_flags ) ;
}
2010-12-06 04:27:56 -08:00
return ;
}
2011-04-24 21:34:39 +05:30
static bool ar9003_hw_tx_iq_cal_run ( struct ath_hw * ah )
2010-12-15 07:30:50 -08:00
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
2010-12-06 04:27:56 -08:00
u8 tx_gain_forced ;
tx_gain_forced = REG_READ_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TXGAIN_FORCE ) ;
if ( tx_gain_forced )
REG_RMW_FIELD ( ah , AR_PHY_TX_FORCED_GAIN ,
AR_PHY_TXGAIN_FORCE , 0 ) ;
2011-04-24 21:34:39 +05:30
REG_RMW_FIELD ( ah , AR_PHY_TX_IQCAL_START ,
AR_PHY_TX_IQCAL_START_DO_CAL , 1 ) ;
if ( ! ath9k_hw_wait ( ah , AR_PHY_TX_IQCAL_START ,
AR_PHY_TX_IQCAL_START_DO_CAL , 0 ,
AH_WAIT_TIMEOUT ) ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " Tx IQ Cal is not completed \n " ) ;
2011-04-24 21:34:39 +05:30
return false ;
}
return true ;
2010-12-06 04:27:56 -08:00
}
2014-02-07 10:29:55 +05:30
static void __ar955x_tx_iq_cal_sort ( struct ath_hw * ah ,
struct coeff * coeff ,
int i , int nmeasurement )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
int im , ix , iy , temp ;
for ( im = 0 ; im < nmeasurement ; im + + ) {
for ( ix = 0 ; ix < MAXIQCAL - 1 ; ix + + ) {
for ( iy = ix + 1 ; iy < = MAXIQCAL - 1 ; iy + + ) {
if ( coeff - > mag_coeff [ i ] [ im ] [ iy ] <
coeff - > mag_coeff [ i ] [ im ] [ ix ] ) {
temp = coeff - > mag_coeff [ i ] [ im ] [ ix ] ;
coeff - > mag_coeff [ i ] [ im ] [ ix ] =
coeff - > mag_coeff [ i ] [ im ] [ iy ] ;
coeff - > mag_coeff [ i ] [ im ] [ iy ] = temp ;
}
if ( coeff - > phs_coeff [ i ] [ im ] [ iy ] <
coeff - > phs_coeff [ i ] [ im ] [ ix ] ) {
temp = coeff - > phs_coeff [ i ] [ im ] [ ix ] ;
coeff - > phs_coeff [ i ] [ im ] [ ix ] =
coeff - > phs_coeff [ i ] [ im ] [ iy ] ;
coeff - > phs_coeff [ i ] [ im ] [ iy ] = temp ;
}
}
}
coeff - > mag_coeff [ i ] [ im ] [ 0 ] = coeff - > mag_coeff [ i ] [ im ] [ MAXIQCAL / 2 ] ;
coeff - > phs_coeff [ i ] [ im ] [ 0 ] = coeff - > phs_coeff [ i ] [ im ] [ MAXIQCAL / 2 ] ;
ath_dbg ( common , CALIBRATE ,
" IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d \n " ,
i , im ,
coeff - > mag_coeff [ i ] [ im ] [ 0 ] ,
coeff - > phs_coeff [ i ] [ im ] [ 0 ] ) ;
}
}
static bool ar955x_tx_iq_cal_median ( struct ath_hw * ah ,
struct coeff * coeff ,
int iqcal_idx ,
int nmeasurement )
{
int i ;
if ( ( iqcal_idx + 1 ) ! = MAXIQCAL )
return false ;
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
__ar955x_tx_iq_cal_sort ( ah , coeff , i , nmeasurement ) ;
}
return true ;
}
2014-02-07 10:29:53 +05:30
static void ar9003_hw_tx_iq_cal_post_proc ( struct ath_hw * ah ,
int iqcal_idx ,
bool is_reusable )
2010-12-06 04:27:56 -08:00
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
const u32 txiqcal_status [ AR9300_MAX_CHAINS ] = {
2011-04-24 21:34:39 +05:30
AR_PHY_TX_IQCAL_STATUS_B0 ,
2010-12-06 04:27:56 -08:00
AR_PHY_TX_IQCAL_STATUS_B1 ,
AR_PHY_TX_IQCAL_STATUS_B2 ,
} ;
const u_int32_t chan_info_tab [ ] = {
AR_PHY_CHAN_INFO_TAB_0 ,
AR_PHY_CHAN_INFO_TAB_1 ,
AR_PHY_CHAN_INFO_TAB_2 ,
} ;
2014-02-07 10:29:55 +05:30
static struct coeff coeff ;
2010-12-06 04:27:56 -08:00
s32 iq_res [ 6 ] ;
2011-04-24 21:34:39 +05:30
int i , im , j ;
2014-02-07 10:29:55 +05:30
int nmeasurement = 0 ;
bool outlier_detect = true ;
2010-12-06 04:27:56 -08:00
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
2012-06-04 16:28:14 +05:30
if ( ! ( ah - > txchainmask & ( 1 < < i ) ) )
continue ;
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
nmeasurement = REG_READ_FIELD ( ah ,
AR_PHY_TX_IQCAL_STATUS_B0 ,
AR_PHY_CALIBRATED_GAINS_0 ) ;
if ( nmeasurement > MAX_MEASUREMENT )
nmeasurement = MAX_MEASUREMENT ;
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
for ( im = 0 ; im < nmeasurement ; im + + ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
" Doing Tx IQ Cal for chain %d \n " , i ) ;
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
if ( REG_READ ( ah , txiqcal_status [ i ] ) &
AR_PHY_TX_IQCAL_STATUS_FAILED ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
" Tx IQ Cal failed for chain %d \n " , i ) ;
2011-04-24 21:34:39 +05:30
goto tx_iqcal_fail ;
}
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
for ( j = 0 ; j < 3 ; j + + ) {
u32 idx = 2 * j , offset = 4 * ( 3 * im + j ) ;
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
REG_RMW_FIELD ( ah ,
2010-12-06 04:27:56 -08:00
AR_PHY_CHAN_INFO_MEMORY ,
AR_PHY_CHAN_INFO_TAB_S2_READ ,
0 ) ;
2011-04-24 21:34:39 +05:30
/* 32 bits */
iq_res [ idx ] = REG_READ ( ah ,
chan_info_tab [ i ] +
offset ) ;
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
REG_RMW_FIELD ( ah ,
2010-12-06 04:27:56 -08:00
AR_PHY_CHAN_INFO_MEMORY ,
AR_PHY_CHAN_INFO_TAB_S2_READ ,
1 ) ;
2011-04-24 21:34:39 +05:30
/* 16 bits */
iq_res [ idx + 1 ] = 0xffff & REG_READ ( ah ,
chan_info_tab [ i ] + offset ) ;
2010-12-06 04:27:56 -08:00
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
" IQ_RES[%d]=0x%x IQ_RES[%d]=0x%x \n " ,
2011-04-24 21:34:39 +05:30
idx , iq_res [ idx ] , idx + 1 ,
iq_res [ idx + 1 ] ) ;
}
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
if ( ! ar9003_hw_calc_iq_corr ( ah , i , iq_res ,
coeff . iqc_coeff ) ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE ,
" Failed in calculation of IQ correction \n " ) ;
2011-04-24 21:34:39 +05:30
goto tx_iqcal_fail ;
}
2010-12-06 04:27:56 -08:00
2014-02-07 10:29:54 +05:30
coeff . phs_coeff [ i ] [ im ] [ iqcal_idx ] =
2014-02-07 10:29:52 +05:30
coeff . iqc_coeff [ 0 ] & 0x7f ;
2014-02-07 10:29:54 +05:30
coeff . mag_coeff [ i ] [ im ] [ iqcal_idx ] =
2011-04-24 21:34:39 +05:30
( coeff . iqc_coeff [ 0 ] > > 7 ) & 0x7f ;
2010-12-06 04:27:56 -08:00
2014-02-07 10:29:54 +05:30
if ( coeff . mag_coeff [ i ] [ im ] [ iqcal_idx ] > 63 )
coeff . mag_coeff [ i ] [ im ] [ iqcal_idx ] - = 128 ;
if ( coeff . phs_coeff [ i ] [ im ] [ iqcal_idx ] > 63 )
coeff . phs_coeff [ i ] [ im ] [ iqcal_idx ] - = 128 ;
2010-12-06 04:27:56 -08:00
}
}
2014-02-07 10:29:55 +05:30
if ( AR_SREV_9550 ( ah ) )
outlier_detect = ar955x_tx_iq_cal_median ( ah , & coeff ,
iqcal_idx , nmeasurement ) ;
if ( outlier_detect )
ar9003_hw_tx_iq_cal_outlier_detection ( ah , & coeff , is_reusable ) ;
2010-12-06 04:27:56 -08:00
return ;
tx_iqcal_fail :
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CALIBRATE , " Tx IQ Cal failed \n " ) ;
2010-12-06 04:27:56 -08:00
return ;
}
2011-10-13 11:00:35 +05:30
static void ar9003_hw_tx_iq_cal_reload ( struct ath_hw * ah )
{
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
u32 tx_corr_coeff [ MAX_MEASUREMENT ] [ AR9300_MAX_CHAINS ] ;
int i , im ;
memset ( tx_corr_coeff , 0 , sizeof ( tx_corr_coeff ) ) ;
for ( i = 0 ; i < MAX_MEASUREMENT / 2 ; i + + ) {
tx_corr_coeff [ i * 2 ] [ 0 ] = tx_corr_coeff [ ( i * 2 ) + 1 ] [ 0 ] =
AR_PHY_TX_IQCAL_CORR_COEFF_B0 ( i ) ;
if ( ! AR_SREV_9485 ( ah ) ) {
tx_corr_coeff [ i * 2 ] [ 1 ] =
tx_corr_coeff [ ( i * 2 ) + 1 ] [ 1 ] =
AR_PHY_TX_IQCAL_CORR_COEFF_B1 ( i ) ;
tx_corr_coeff [ i * 2 ] [ 2 ] =
tx_corr_coeff [ ( i * 2 ) + 1 ] [ 2 ] =
AR_PHY_TX_IQCAL_CORR_COEFF_B2 ( i ) ;
}
}
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
if ( ! ( ah - > txchainmask & ( 1 < < i ) ) )
continue ;
for ( im = 0 ; im < caldata - > num_measures [ i ] ; im + + ) {
if ( ( im % 2 ) = = 0 )
REG_RMW_FIELD ( ah , tx_corr_coeff [ im ] [ i ] ,
AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE ,
caldata - > tx_corr_coeff [ im ] [ i ] ) ;
else
REG_RMW_FIELD ( ah , tx_corr_coeff [ im ] [ i ] ,
AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE ,
caldata - > tx_corr_coeff [ im ] [ i ] ) ;
}
}
REG_RMW_FIELD ( ah , AR_PHY_TX_IQCAL_CONTROL_3 ,
AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN , 0x1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_RX_IQCAL_CORR_B0 ,
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN , 0x1 ) ;
}
2012-11-09 14:51:30 +05:30
static void ar9003_hw_manual_peak_cal ( struct ath_hw * ah , u8 chain , bool is_2g )
{
2013-12-06 16:28:52 +05:30
int offset [ 8 ] = { 0 } , total = 0 , test ;
2015-01-28 17:54:25 +05:30
int agc_out , i , peak_detect_threshold ;
if ( AR_SREV_9550 ( ah ) | | AR_SREV_9531 ( ah ) )
peak_detect_threshold = 8 ;
else
peak_detect_threshold = 0 ;
2012-11-09 14:51:30 +05:30
2015-01-28 17:54:24 +05:30
/*
* Turn off LNA / SW .
*/
2012-11-09 14:51:30 +05:30
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_GAINSTAGES ( chain ) ,
AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE , 0x1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_GAINSTAGES ( chain ) ,
AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC , 0x0 ) ;
2015-01-28 17:54:24 +05:30
if ( AR_SREV_9003_PCOEM ( ah ) | | AR_SREV_9330_11 ( ah ) ) {
if ( is_2g )
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_GAINSTAGES ( chain ) ,
AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR , 0x0 ) ;
else
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_GAINSTAGES ( chain ) ,
AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR , 0x0 ) ;
}
/*
* Turn off RXON .
*/
2012-11-09 14:51:30 +05:30
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXTX2 ( chain ) ,
AR_PHY_65NM_RXTX2_RXON_OVR , 0x1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXTX2 ( chain ) ,
AR_PHY_65NM_RXTX2_RXON , 0x0 ) ;
2015-01-28 17:54:24 +05:30
/*
* Turn on AGC for cal .
*/
2012-11-09 14:51:30 +05:30
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE , 0x1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR , 0x1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR , 0x1 ) ;
2013-12-06 16:28:52 +05:30
2015-01-28 17:54:24 +05:30
if ( AR_SREV_9330_11 ( ah ) )
2012-11-09 14:51:30 +05:30
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
2013-12-06 16:28:52 +05:30
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR , 0x0 ) ;
2015-01-28 17:54:24 +05:30
2015-09-01 10:56:09 +08:00
if ( AR_SREV_9003_PCOEM ( ah ) | | AR_SREV_9550 ( ah ) | | AR_SREV_9531 ( ah ) | |
AR_SREV_9561 ( ah ) ) {
2013-12-06 16:28:52 +05:30
if ( is_2g )
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
2015-01-28 17:54:25 +05:30
AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR ,
peak_detect_threshold ) ;
2013-12-06 16:28:52 +05:30
else
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
2015-01-28 17:54:25 +05:30
AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR ,
peak_detect_threshold ) ;
2013-12-06 16:28:52 +05:30
}
2012-11-09 14:51:30 +05:30
for ( i = 6 ; i > 0 ; i - - ) {
offset [ i ] = BIT ( i - 1 ) ;
test = total + offset [ i ] ;
if ( is_2g )
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR ,
test ) ;
else
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR ,
test ) ;
udelay ( 100 ) ;
agc_out = REG_READ_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC_OUT ) ;
offset [ i ] = ( agc_out ) ? 0 : 1 ;
total + = ( offset [ i ] < < ( i - 1 ) ) ;
}
if ( is_2g )
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR , total ) ;
else
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR , total ) ;
2015-01-28 17:54:24 +05:30
/*
* Turn on LNA .
*/
2012-11-09 14:51:30 +05:30
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_GAINSTAGES ( chain ) ,
AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE , 0 ) ;
2015-01-28 17:54:24 +05:30
/*
* Turn off RXON .
*/
2012-11-09 14:51:30 +05:30
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXTX2 ( chain ) ,
AR_PHY_65NM_RXTX2_RXON_OVR , 0 ) ;
2015-01-28 17:54:24 +05:30
/*
* Turn off peak detect calibration .
*/
2012-11-09 14:51:30 +05:30
REG_RMW_FIELD ( ah , AR_PHY_65NM_RXRF_AGC ( chain ) ,
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR , 0 ) ;
}
2013-12-06 16:28:52 +05:30
static void ar9003_hw_do_pcoem_manual_peak_cal ( struct ath_hw * ah ,
struct ath9k_channel * chan ,
bool run_rtt_cal )
2013-01-07 14:43:33 +05:30
{
2013-09-11 16:36:32 +05:30
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
2013-01-07 14:43:33 +05:30
int i ;
2013-05-16 22:47:34 +05:30
if ( ! AR_SREV_9462 ( ah ) & & ! AR_SREV_9565 ( ah ) & & ! AR_SREV_9485 ( ah ) )
2013-01-07 14:43:33 +05:30
return ;
2013-09-11 16:36:32 +05:30
if ( ( ah - > caps . hw_caps & ATH9K_HW_CAP_RTT ) & & ! run_rtt_cal )
return ;
2013-01-07 14:43:33 +05:30
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
if ( ! ( ah - > rxchainmask & ( 1 < < i ) ) )
continue ;
ar9003_hw_manual_peak_cal ( ah , i , IS_CHAN_2GHZ ( chan ) ) ;
}
2013-09-11 16:36:32 +05:30
if ( caldata )
set_bit ( SW_PKDET_DONE , & caldata - > cal_flags ) ;
if ( ( ah - > caps . hw_caps & ATH9K_HW_CAP_RTT ) & & caldata ) {
if ( IS_CHAN_2GHZ ( chan ) ) {
caldata - > caldac [ 0 ] = REG_READ_FIELD ( ah ,
AR_PHY_65NM_RXRF_AGC ( 0 ) ,
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR ) ;
caldata - > caldac [ 1 ] = REG_READ_FIELD ( ah ,
AR_PHY_65NM_RXRF_AGC ( 1 ) ,
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR ) ;
} else {
caldata - > caldac [ 0 ] = REG_READ_FIELD ( ah ,
AR_PHY_65NM_RXRF_AGC ( 0 ) ,
AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR ) ;
caldata - > caldac [ 1 ] = REG_READ_FIELD ( ah ,
AR_PHY_65NM_RXRF_AGC ( 1 ) ,
AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR ) ;
}
}
2013-01-07 14:43:33 +05:30
}
static void ar9003_hw_cl_cal_post_proc ( struct ath_hw * ah , bool is_reusable )
{
u32 cl_idx [ AR9300_MAX_CHAINS ] = { AR_PHY_CL_TAB_0 ,
AR_PHY_CL_TAB_1 ,
AR_PHY_CL_TAB_2 } ;
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
bool txclcal_done = false ;
int i , j ;
if ( ! caldata | | ! ( ah - > enabled_cals & TX_CL_CAL ) )
return ;
txclcal_done = ! ! ( REG_READ ( ah , AR_PHY_AGC_CONTROL ) &
AR_PHY_AGC_CONTROL_CLC_SUCCESS ) ;
2013-09-11 16:36:31 +05:30
if ( test_bit ( TXCLCAL_DONE , & caldata - > cal_flags ) ) {
2013-01-07 14:43:33 +05:30
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
if ( ! ( ah - > txchainmask & ( 1 < < i ) ) )
continue ;
for ( j = 0 ; j < MAX_CL_TAB_ENTRY ; j + + )
REG_WRITE ( ah , CL_TAB_ENTRY ( cl_idx [ i ] ) ,
caldata - > tx_clcal [ i ] [ j ] ) ;
}
} else if ( is_reusable & & txclcal_done ) {
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
if ( ! ( ah - > txchainmask & ( 1 < < i ) ) )
continue ;
for ( j = 0 ; j < MAX_CL_TAB_ENTRY ; j + + )
caldata - > tx_clcal [ i ] [ j ] =
REG_READ ( ah , CL_TAB_ENTRY ( cl_idx [ i ] ) ) ;
}
2013-09-11 16:36:31 +05:30
set_bit ( TXCLCAL_DONE , & caldata - > cal_flags ) ;
2013-01-07 14:43:33 +05:30
}
}
2013-11-15 10:46:21 +05:30
static bool ar9003_hw_init_cal_pcoem ( struct ath_hw * ah ,
struct ath9k_channel * chan )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
bool txiqcal_done = false ;
bool is_reusable = true , status = true ;
2013-11-19 09:15:01 +05:30
bool run_rtt_cal = false , run_agc_cal ;
2013-11-15 10:46:21 +05:30
bool rtt = ! ! ( ah - > caps . hw_caps & ATH9K_HW_CAP_RTT ) ;
u32 rx_delay = 0 ;
u32 agc_ctrl = 0 , agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
AR_PHY_AGC_CONTROL_FLTR_CAL |
AR_PHY_AGC_CONTROL_PKDET_CAL ;
/* Use chip chainmask only for calibration */
ar9003_hw_set_chain_masks ( ah , ah - > caps . rx_chainmask , ah - > caps . tx_chainmask ) ;
if ( rtt ) {
if ( ! ar9003_hw_rtt_restore ( ah , chan ) )
run_rtt_cal = true ;
if ( run_rtt_cal )
ath_dbg ( common , CALIBRATE , " RTT calibration to be done \n " ) ;
}
run_agc_cal = run_rtt_cal ;
if ( run_rtt_cal ) {
ar9003_hw_rtt_enable ( ah ) ;
ar9003_hw_rtt_set_mask ( ah , 0x00 ) ;
ar9003_hw_rtt_clear_hist ( ah ) ;
}
if ( rtt ) {
if ( ! run_rtt_cal ) {
agc_ctrl = REG_READ ( ah , AR_PHY_AGC_CONTROL ) ;
agc_supp_cals & = agc_ctrl ;
agc_ctrl & = ~ ( AR_PHY_AGC_CONTROL_OFFSET_CAL |
AR_PHY_AGC_CONTROL_FLTR_CAL |
AR_PHY_AGC_CONTROL_PKDET_CAL ) ;
REG_WRITE ( ah , AR_PHY_AGC_CONTROL , agc_ctrl ) ;
} else {
if ( ah - > ah_flags & AH_FASTCC )
run_agc_cal = true ;
}
}
if ( ah - > enabled_cals & TX_CL_CAL ) {
if ( caldata & & test_bit ( TXCLCAL_DONE , & caldata - > cal_flags ) )
REG_CLR_BIT ( ah , AR_PHY_CL_CAL_CTL ,
AR_PHY_CL_CAL_ENABLE ) ;
else {
REG_SET_BIT ( ah , AR_PHY_CL_CAL_CTL ,
AR_PHY_CL_CAL_ENABLE ) ;
run_agc_cal = true ;
}
}
if ( ( IS_CHAN_HALF_RATE ( chan ) | | IS_CHAN_QUARTER_RATE ( chan ) ) | |
! ( ah - > enabled_cals & TX_IQ_CAL ) )
goto skip_tx_iqcal ;
/* Do Tx IQ Calibration */
REG_RMW_FIELD ( ah , AR_PHY_TX_IQCAL_CONTROL_1 ,
AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT ,
DELPT ) ;
/*
* For AR9485 or later chips , TxIQ cal runs as part of
* AGC calibration
*/
if ( ah - > enabled_cals & TX_IQ_ON_AGC_CAL ) {
if ( caldata & & ! test_bit ( TXIQCAL_DONE , & caldata - > cal_flags ) )
REG_SET_BIT ( ah , AR_PHY_TX_IQCAL_CONTROL_0 ,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL ) ;
else
REG_CLR_BIT ( ah , AR_PHY_TX_IQCAL_CONTROL_0 ,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL ) ;
txiqcal_done = run_agc_cal = true ;
}
skip_tx_iqcal :
if ( ath9k_hw_mci_is_enabled ( ah ) & & IS_CHAN_2GHZ ( chan ) & & run_agc_cal )
ar9003_mci_init_cal_req ( ah , & is_reusable ) ;
if ( REG_READ ( ah , AR_PHY_CL_CAL_CTL ) & AR_PHY_CL_CAL_ENABLE ) {
rx_delay = REG_READ ( ah , AR_PHY_RX_DELAY ) ;
/* Disable BB_active */
REG_WRITE ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_DIS ) ;
udelay ( 5 ) ;
REG_WRITE ( ah , AR_PHY_RX_DELAY , AR_PHY_RX_DELAY_DELAY ) ;
REG_WRITE ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_EN ) ;
}
if ( run_agc_cal | | ! ( ah - > ah_flags & AH_FASTCC ) ) {
/* Calibrate the AGC */
REG_WRITE ( ah , AR_PHY_AGC_CONTROL ,
REG_READ ( ah , AR_PHY_AGC_CONTROL ) |
AR_PHY_AGC_CONTROL_CAL ) ;
/* Poll for offset calibration complete */
status = ath9k_hw_wait ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_CAL ,
0 , AH_WAIT_TIMEOUT ) ;
2013-12-06 16:28:52 +05:30
ar9003_hw_do_pcoem_manual_peak_cal ( ah , chan , run_rtt_cal ) ;
2013-11-15 10:46:21 +05:30
}
if ( REG_READ ( ah , AR_PHY_CL_CAL_CTL ) & AR_PHY_CL_CAL_ENABLE ) {
REG_WRITE ( ah , AR_PHY_RX_DELAY , rx_delay ) ;
udelay ( 5 ) ;
}
if ( ath9k_hw_mci_is_enabled ( ah ) & & IS_CHAN_2GHZ ( chan ) & & run_agc_cal )
ar9003_mci_init_cal_done ( ah ) ;
if ( rtt & & ! run_rtt_cal ) {
agc_ctrl | = agc_supp_cals ;
REG_WRITE ( ah , AR_PHY_AGC_CONTROL , agc_ctrl ) ;
}
if ( ! status ) {
if ( run_rtt_cal )
ar9003_hw_rtt_disable ( ah ) ;
ath_dbg ( common , CALIBRATE ,
" offset calibration failed to complete in %d ms; noisy environment? \n " ,
AH_WAIT_TIMEOUT / 1000 ) ;
return false ;
}
if ( txiqcal_done )
2014-02-07 10:29:53 +05:30
ar9003_hw_tx_iq_cal_post_proc ( ah , 0 , is_reusable ) ;
2013-11-15 10:46:21 +05:30
else if ( caldata & & test_bit ( TXIQCAL_DONE , & caldata - > cal_flags ) )
ar9003_hw_tx_iq_cal_reload ( ah ) ;
ar9003_hw_cl_cal_post_proc ( ah , is_reusable ) ;
if ( run_rtt_cal & & caldata ) {
if ( is_reusable ) {
if ( ! ath9k_hw_rfbus_req ( ah ) ) {
ath_err ( ath9k_hw_common ( ah ) ,
" Could not stop baseband \n " ) ;
} else {
ar9003_hw_rtt_fill_hist ( ah ) ;
if ( test_bit ( SW_PKDET_DONE , & caldata - > cal_flags ) )
ar9003_hw_rtt_load_hist ( ah ) ;
}
ath9k_hw_rfbus_done ( ah ) ;
}
ar9003_hw_rtt_disable ( ah ) ;
}
/* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks ( ah , ah - > rxchainmask , ah - > txchainmask ) ;
/* Initialize list pointers */
ah - > cal_list = ah - > cal_list_last = ah - > cal_list_curr = NULL ;
INIT_CAL ( & ah - > iq_caldata ) ;
INSERT_CAL ( ah , & ah - > iq_caldata ) ;
ath_dbg ( common , CALIBRATE , " enabling IQ Calibration \n " ) ;
/* Initialize current pointer to first element in list */
ah - > cal_list_curr = ah - > cal_list ;
if ( ah - > cal_list_curr )
ath9k_hw_reset_calibration ( ah , ah - > cal_list_curr ) ;
if ( caldata )
caldata - > CalValid = 0 ;
return true ;
}
2014-02-07 10:29:53 +05:30
static bool do_ar9003_agc_cal ( struct ath_hw * ah )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
bool status ;
REG_WRITE ( ah , AR_PHY_AGC_CONTROL ,
REG_READ ( ah , AR_PHY_AGC_CONTROL ) |
AR_PHY_AGC_CONTROL_CAL ) ;
status = ath9k_hw_wait ( ah , AR_PHY_AGC_CONTROL ,
AR_PHY_AGC_CONTROL_CAL ,
0 , AH_WAIT_TIMEOUT ) ;
if ( ! status ) {
ath_dbg ( common , CALIBRATE ,
" offset calibration failed to complete in %d ms, "
" noisy environment? \n " ,
AH_WAIT_TIMEOUT / 1000 ) ;
return false ;
}
return true ;
}
2013-11-15 10:46:21 +05:30
static bool ar9003_hw_init_cal_soc ( struct ath_hw * ah ,
struct ath9k_channel * chan )
2010-04-15 17:39:11 -04:00
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
2011-10-13 11:00:35 +05:30
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
2013-01-07 14:43:33 +05:30
bool txiqcal_done = false ;
2014-02-07 10:29:49 +05:30
bool status = true ;
2013-11-15 10:50:58 +05:30
bool run_agc_cal = false , sep_iq_cal = false ;
2014-02-07 10:29:53 +05:30
int i = 0 ;
2011-10-13 11:00:37 +05:30
2013-03-15 14:53:31 +01:00
/* Use chip chainmask only for calibration */
2013-01-20 21:55:20 +01:00
ar9003_hw_set_chain_masks ( ah , ah - > caps . rx_chainmask , ah - > caps . tx_chainmask ) ;
2011-10-13 11:00:38 +05:30
if ( ah - > enabled_cals & TX_CL_CAL ) {
2013-11-15 13:05:18 +05:30
REG_SET_BIT ( ah , AR_PHY_CL_CAL_CTL , AR_PHY_CL_CAL_ENABLE ) ;
run_agc_cal = true ;
2011-10-13 11:00:37 +05:30
}
2010-04-15 17:39:11 -04:00
2013-11-15 11:05:38 +05:30
if ( IS_CHAN_HALF_RATE ( chan ) | | IS_CHAN_QUARTER_RATE ( chan ) )
2011-10-13 11:00:38 +05:30
goto skip_tx_iqcal ;
2010-05-19 16:45:50 -04:00
/* Do Tx IQ Calibration */
2011-04-24 21:34:39 +05:30
REG_RMW_FIELD ( ah , AR_PHY_TX_IQCAL_CONTROL_1 ,
AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT ,
DELPT ) ;
2010-12-06 04:27:56 -08:00
2011-04-24 21:34:39 +05:30
/*
* For AR9485 or later chips , TxIQ cal runs as part of
2013-11-15 14:49:32 +05:30
* AGC calibration . Specifically , AR9550 in SoC chips .
2011-04-24 21:34:39 +05:30
*/
2011-10-13 11:00:38 +05:30
if ( ah - > enabled_cals & TX_IQ_ON_AGC_CAL ) {
2014-02-07 10:29:50 +05:30
if ( REG_READ_FIELD ( ah , AR_PHY_TX_IQCAL_CONTROL_0 ,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL ) ) {
txiqcal_done = true ;
} else {
txiqcal_done = false ;
}
2011-10-13 11:00:41 +05:30
run_agc_cal = true ;
2013-11-15 14:49:32 +05:30
} else {
2013-01-07 13:53:47 +05:30
sep_iq_cal = true ;
2013-11-15 14:49:32 +05:30
run_agc_cal = true ;
2013-01-07 13:53:47 +05:30
}
2011-10-13 11:00:41 +05:30
2013-11-15 14:49:32 +05:30
/*
* In the SoC family , this will run for AR9300 , AR9331 and AR9340 .
*/
2013-01-07 13:53:47 +05:30
if ( sep_iq_cal ) {
txiqcal_done = ar9003_hw_tx_iq_cal_run ( ah ) ;
REG_WRITE ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_DIS ) ;
udelay ( 5 ) ;
REG_WRITE ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_EN ) ;
}
2010-05-19 16:45:50 -04:00
2014-01-02 10:06:21 +05:30
if ( AR_SREV_9550 ( ah ) & & IS_CHAN_2GHZ ( chan ) ) {
if ( ! ar9003_hw_dynamic_osdac_selection ( ah , txiqcal_done ) )
return false ;
}
2013-11-15 14:49:32 +05:30
skip_tx_iqcal :
2011-10-13 11:00:42 +05:30
if ( run_agc_cal | | ! ( ah - > ah_flags & AH_FASTCC ) ) {
2015-09-01 10:56:09 +08:00
if ( AR_SREV_9330_11 ( ah ) | | AR_SREV_9531 ( ah ) | | AR_SREV_9550 ( ah ) | |
AR_SREV_9561 ( ah ) ) {
2015-01-28 17:54:26 +05:30
for ( i = 0 ; i < AR9300_MAX_CHAINS ; i + + ) {
if ( ! ( ah - > rxchainmask & ( 1 < < i ) ) )
continue ;
ar9003_hw_manual_peak_cal ( ah , i ,
IS_CHAN_2GHZ ( chan ) ) ;
}
}
2013-12-06 16:28:52 +05:30
2014-02-07 10:29:53 +05:30
/*
* For non - AR9550 chips , we just trigger AGC calibration
* in the HW , poll for completion and then process
* the results .
*
* For AR955x , we run it multiple times and use
* median IQ correction .
*/
if ( ! AR_SREV_9550 ( ah ) ) {
status = do_ar9003_agc_cal ( ah ) ;
if ( ! status )
return false ;
2011-11-30 10:41:26 +05:30
2014-02-07 10:29:53 +05:30
if ( txiqcal_done )
ar9003_hw_tx_iq_cal_post_proc ( ah , 0 , false ) ;
} else {
if ( ! txiqcal_done ) {
status = do_ar9003_agc_cal ( ah ) ;
if ( ! status )
return false ;
} else {
for ( i = 0 ; i < MAXIQCAL ; i + + ) {
status = do_ar9003_agc_cal ( ah ) ;
if ( ! status )
return false ;
ar9003_hw_tx_iq_cal_post_proc ( ah , i , false ) ;
}
}
}
2010-04-15 17:39:11 -04:00
}
2013-03-15 14:53:31 +01:00
/* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks ( ah , ah - > rxchainmask , ah - > txchainmask ) ;
2010-04-15 17:39:11 -04:00
/* Initialize list pointers */
ah - > cal_list = ah - > cal_list_last = ah - > cal_list_curr = NULL ;
2013-01-03 12:21:21 +05:30
INIT_CAL ( & ah - > iq_caldata ) ;
INSERT_CAL ( ah , & ah - > iq_caldata ) ;
ath_dbg ( common , CALIBRATE , " enabling IQ Calibration \n " ) ;
2010-04-15 17:39:11 -04:00
/* Initialize current pointer to first element in list */
ah - > cal_list_curr = ah - > cal_list ;
if ( ah - > cal_list_curr )
ath9k_hw_reset_calibration ( ah , ah - > cal_list_curr ) ;
2011-10-13 11:00:35 +05:30
if ( caldata )
caldata - > CalValid = 0 ;
2010-04-15 17:39:11 -04:00
return true ;
2010-04-15 17:39:09 -04:00
}
2010-04-15 17:39:00 -04:00
void ar9003_hw_attach_calib_ops ( struct ath_hw * ah )
{
struct ath_hw_private_ops * priv_ops = ath9k_hw_private_ops ( ah ) ;
struct ath_hw_ops * ops = ath9k_hw_ops ( ah ) ;
2013-11-15 10:46:21 +05:30
if ( AR_SREV_9485 ( ah ) | | AR_SREV_9462 ( ah ) | | AR_SREV_9565 ( ah ) )
priv_ops - > init_cal = ar9003_hw_init_cal_pcoem ;
else
priv_ops - > init_cal = ar9003_hw_init_cal_soc ;
2010-04-15 17:39:00 -04:00
priv_ops - > init_cal_settings = ar9003_hw_init_cal_settings ;
priv_ops - > setup_calibration = ar9003_hw_setup_calibration ;
ops - > calibrate = ar9003_hw_calibrate ;
}