2008-10-29 10:16:30 +05:30
/*
2011-05-17 13:36:18 +05:30
* Copyright ( c ) 2008 - 2011 Atheros Communications Inc .
2008-10-29 10:16:30 +05:30
*
* 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 .
*/
2009-09-14 00:55:09 -07:00
# include "hw.h"
2016-07-10 01:09:55 +02:00
# include <linux/ath9k_platform.h>
2008-10-29 10:16:30 +05:30
2010-06-01 15:14:06 +05:30
void ath9k_hw_analog_shift_regwrite ( struct ath_hw * ah , u32 reg , u32 val )
{
REG_WRITE ( ah , reg , val ) ;
if ( ah - > config . analog_shiftreg )
udelay ( 100 ) ;
}
2009-08-07 09:45:15 +05:30
void ath9k_hw_analog_shift_rmw ( struct ath_hw * ah , u32 reg , u32 mask ,
u32 shift , u32 val )
2008-10-29 10:16:30 +05:30
{
2015-03-22 19:29:59 +01:00
REG_RMW ( ah , reg , ( ( val < < shift ) & mask ) , mask ) ;
2008-10-29 10:16:30 +05:30
2009-02-09 13:27:26 +05:30
if ( ah - > config . analog_shiftreg )
2008-10-29 10:16:30 +05:30
udelay ( 100 ) ;
}
2009-08-07 09:45:15 +05:30
int16_t ath9k_hw_interpolate ( u16 target , u16 srcLeft , u16 srcRight ,
int16_t targetLeft , int16_t targetRight )
2008-10-29 10:16:30 +05:30
{
int16_t rv ;
if ( srcRight = = srcLeft ) {
rv = targetLeft ;
} else {
rv = ( int16_t ) ( ( ( target - srcLeft ) * targetRight +
( srcRight - target ) * targetLeft ) /
( srcRight - srcLeft ) ) ;
}
return rv ;
}
2009-08-07 09:45:15 +05:30
bool ath9k_hw_get_lower_upper_index ( u8 target , u8 * pList , u16 listSize ,
u16 * indexL , u16 * indexR )
2008-10-29 10:16:30 +05:30
{
u16 i ;
if ( target < = pList [ 0 ] ) {
* indexL = * indexR = 0 ;
return true ;
}
if ( target > = pList [ listSize - 1 ] ) {
* indexL = * indexR = ( u16 ) ( listSize - 1 ) ;
return true ;
}
for ( i = 0 ; i < listSize - 1 ; i + + ) {
if ( pList [ i ] = = target ) {
* indexL = * indexR = i ;
return true ;
}
if ( target < pList [ i + 1 ] ) {
* indexL = i ;
* indexR = ( u16 ) ( i + 1 ) ;
return false ;
}
}
return false ;
}
2011-01-04 13:17:28 +05:30
void ath9k_hw_usb_gen_fill_eeprom ( struct ath_hw * ah , u16 * eep_data ,
int eep_start_loc , int size )
{
int i = 0 , j , addr ;
u32 addrdata [ 8 ] ;
u32 data [ 8 ] ;
for ( addr = 0 ; addr < size ; addr + + ) {
addrdata [ i ] = AR5416_EEPROM_OFFSET +
( ( addr + eep_start_loc ) < < AR5416_EEPROM_S ) ;
i + + ;
if ( i = = 8 ) {
REG_READ_MULTI ( ah , addrdata , data , i ) ;
for ( j = 0 ; j < i ; j + + ) {
* eep_data = data [ j ] ;
eep_data + + ;
}
i = 0 ;
}
}
if ( i ! = 0 ) {
REG_READ_MULTI ( ah , addrdata , data , i ) ;
for ( j = 0 ; j < i ; j + + ) {
* eep_data = data [ j ] ;
eep_data + + ;
}
}
}
2016-07-10 01:09:55 +02:00
static bool ath9k_hw_nvram_read_array ( u16 * blob , size_t blob_size ,
off_t offset , u16 * data )
2012-12-10 15:30:28 +01:00
{
2017-04-06 08:12:20 +03:00
if ( offset > = blob_size )
2012-12-10 15:30:28 +01:00
return false ;
2016-07-10 01:09:55 +02:00
* data = blob [ offset ] ;
2012-12-10 15:30:28 +01:00
return true ;
}
2016-07-10 01:09:55 +02:00
static bool ath9k_hw_nvram_read_pdata ( struct ath9k_platform_data * pdata ,
off_t offset , u16 * data )
{
return ath9k_hw_nvram_read_array ( pdata - > eeprom_data ,
ARRAY_SIZE ( pdata - > eeprom_data ) ,
offset , data ) ;
}
static bool ath9k_hw_nvram_read_firmware ( const struct firmware * eeprom_blob ,
off_t offset , u16 * data )
{
return ath9k_hw_nvram_read_array ( ( u16 * ) eeprom_blob - > data ,
eeprom_blob - > size / sizeof ( u16 ) ,
offset , data ) ;
}
2012-12-10 15:30:27 +01:00
bool ath9k_hw_nvram_read ( struct ath_hw * ah , u32 off , u16 * data )
2008-10-29 10:16:30 +05:30
{
2012-12-10 15:30:27 +01:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2016-07-10 01:09:55 +02:00
struct ath9k_platform_data * pdata = ah - > dev - > platform_data ;
2012-12-10 15:30:25 +01:00
bool ret ;
2012-12-10 15:30:28 +01:00
if ( ah - > eeprom_blob )
2016-07-10 01:09:55 +02:00
ret = ath9k_hw_nvram_read_firmware ( ah - > eeprom_blob , off , data ) ;
2017-05-09 08:04:30 -05:00
else if ( pdata & & ! pdata - > use_eeprom )
2016-07-10 01:09:55 +02:00
ret = ath9k_hw_nvram_read_pdata ( pdata , off , data ) ;
2012-12-10 15:30:28 +01:00
else
ret = common - > bus_ops - > eeprom_read ( common , off , data ) ;
2012-12-10 15:30:25 +01:00
if ( ! ret )
2012-12-10 15:30:26 +01:00
ath_dbg ( common , EEPROM ,
" unable to read eeprom region at offset %u \n " , off ) ;
2012-12-10 15:30:25 +01:00
return ret ;
2008-10-29 10:16:30 +05:30
}
2015-10-31 13:57:32 +01:00
int ath9k_hw_nvram_swap_data ( struct ath_hw * ah , bool * swap_needed , int size )
{
u16 magic ;
u16 * eepdata ;
int i ;
2016-12-05 13:27:36 +02:00
bool needs_byteswap = false ;
2015-10-31 13:57:32 +01:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
if ( ! ath9k_hw_nvram_read ( ah , AR5416_EEPROM_MAGIC_OFFSET , & magic ) ) {
ath_err ( common , " Reading Magic # failed \n " ) ;
return - EIO ;
}
2016-01-21 16:34:08 +01:00
if ( swab16 ( magic ) = = AR5416_EEPROM_MAGIC ) {
2016-12-05 13:27:36 +02:00
needs_byteswap = true ;
ath_dbg ( common , EEPROM ,
" EEPROM needs byte-swapping to correct endianness. \n " ) ;
} else if ( magic ! = AR5416_EEPROM_MAGIC ) {
if ( ath9k_hw_use_flash ( ah ) ) {
ath_dbg ( common , EEPROM ,
" Ignoring invalid EEPROM magic (0x%04x). \n " ,
magic ) ;
} else {
ath_err ( common ,
" Invalid EEPROM magic (0x%04x). \n " , magic ) ;
return - EINVAL ;
}
}
if ( needs_byteswap ) {
2015-10-31 13:57:32 +01:00
if ( ah - > ah_flags & AH_NO_EEP_SWAP ) {
ath_info ( common ,
" Ignoring endianness difference in EEPROM magic bytes. \n " ) ;
} else {
2016-12-05 13:27:36 +02:00
eepdata = ( u16 * ) ( & ah - > eeprom ) ;
2016-01-21 16:34:08 +01:00
2016-12-05 13:27:36 +02:00
for ( i = 0 ; i < size ; i + + )
eepdata [ i ] = swab16 ( eepdata [ i ] ) ;
}
2015-10-31 13:57:32 +01:00
}
2016-12-05 13:27:37 +02:00
if ( ah - > eep_ops - > get_eepmisc ( ah ) & AR5416_EEPMISC_BIG_ENDIAN ) {
* swap_needed = true ;
ath_dbg ( common , EEPROM ,
" Big Endian EEPROM detected according to EEPMISC register. \n " ) ;
} else {
* swap_needed = false ;
2015-10-31 13:57:32 +01:00
}
return 0 ;
}
bool ath9k_hw_nvram_validate_checksum ( struct ath_hw * ah , int size )
{
u32 i , sum = 0 ;
u16 * eepdata = ( u16 * ) ( & ah - > eeprom ) ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
for ( i = 0 ; i < size ; i + + )
sum ^ = eepdata [ i ] ;
if ( sum ! = 0xffff ) {
ath_err ( common , " Bad EEPROM checksum 0x%x \n " , sum ) ;
return false ;
}
return true ;
}
bool ath9k_hw_nvram_check_version ( struct ath_hw * ah , int version , int minrev )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
if ( ah - > eep_ops - > get_eeprom_ver ( ah ) ! = version | |
ah - > eep_ops - > get_eeprom_rev ( ah ) < minrev ) {
ath_err ( common , " Bad EEPROM VER 0x%04x or REV 0x%04x \n " ,
ah - > eep_ops - > get_eeprom_ver ( ah ) ,
ah - > eep_ops - > get_eeprom_rev ( ah ) ) ;
2015-12-19 13:59:19 +03:00
return false ;
2015-10-31 13:57:32 +01:00
}
return true ;
}
2009-08-07 09:45:15 +05:30
void ath9k_hw_fill_vpd_table ( u8 pwrMin , u8 pwrMax , u8 * pPwrList ,
u8 * pVpdList , u16 numIntercepts ,
u8 * pRetVpdList )
2009-02-09 13:27:24 +05:30
{
u16 i , k ;
u8 currPwr = pwrMin ;
u16 idxL = 0 , idxR = 0 ;
for ( i = 0 ; i < = ( pwrMax - pwrMin ) / 2 ; i + + ) {
ath9k_hw_get_lower_upper_index ( currPwr , pPwrList ,
numIntercepts , & ( idxL ) ,
& ( idxR ) ) ;
if ( idxR < 1 )
idxR = 1 ;
if ( idxL = = numIntercepts - 1 )
idxL = ( u16 ) ( numIntercepts - 2 ) ;
if ( pPwrList [ idxL ] = = pPwrList [ idxR ] )
k = pVpdList [ idxL ] ;
else
k = ( u16 ) ( ( ( currPwr - pPwrList [ idxL ] ) * pVpdList [ idxR ] +
( pPwrList [ idxR ] - currPwr ) * pVpdList [ idxL ] ) /
( pPwrList [ idxR ] - pPwrList [ idxL ] ) ) ;
pRetVpdList [ i ] = ( u8 ) k ;
currPwr + = 2 ;
}
}
2009-08-07 09:45:15 +05:30
void ath9k_hw_get_legacy_target_powers ( struct ath_hw * ah ,
struct ath9k_channel * chan ,
struct cal_target_power_leg * powInfo ,
u16 numChannels ,
struct cal_target_power_leg * pNewPower ,
u16 numRates , bool isExtTarget )
2009-02-09 13:27:24 +05:30
{
struct chan_centers centers ;
u16 clo , chi ;
int i ;
int matchIndex = - 1 , lowIndex = - 1 ;
u16 freq ;
ath9k_hw_get_channel_centers ( ah , chan , & centers ) ;
freq = ( isExtTarget ) ? centers . ext_center : centers . ctl_center ;
if ( freq < = ath9k_hw_fbin2freq ( powInfo [ 0 ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ) {
matchIndex = 0 ;
} else {
for ( i = 0 ; ( i < numChannels ) & &
( powInfo [ i ] . bChannel ! = AR5416_BCHAN_UNUSED ) ; i + + ) {
if ( freq = = ath9k_hw_fbin2freq ( powInfo [ i ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ) {
matchIndex = i ;
break ;
2009-08-07 23:50:00 +02:00
} else if ( freq < ath9k_hw_fbin2freq ( powInfo [ i ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) & & i > 0 & &
freq > ath9k_hw_fbin2freq ( powInfo [ i - 1 ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ) {
2009-02-09 13:27:24 +05:30
lowIndex = i - 1 ;
break ;
}
}
if ( ( matchIndex = = - 1 ) & & ( lowIndex = = - 1 ) )
matchIndex = i - 1 ;
}
if ( matchIndex ! = - 1 ) {
* pNewPower = powInfo [ matchIndex ] ;
} else {
clo = ath9k_hw_fbin2freq ( powInfo [ lowIndex ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ;
chi = ath9k_hw_fbin2freq ( powInfo [ lowIndex + 1 ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ;
for ( i = 0 ; i < numRates ; i + + ) {
pNewPower - > tPow2x [ i ] =
( u8 ) ath9k_hw_interpolate ( freq , clo , chi ,
powInfo [ lowIndex ] . tPow2x [ i ] ,
powInfo [ lowIndex + 1 ] . tPow2x [ i ] ) ;
}
}
}
2009-08-07 09:45:15 +05:30
void ath9k_hw_get_target_powers ( struct ath_hw * ah ,
struct ath9k_channel * chan ,
struct cal_target_power_ht * powInfo ,
u16 numChannels ,
struct cal_target_power_ht * pNewPower ,
u16 numRates , bool isHt40Target )
2009-02-09 13:27:24 +05:30
{
struct chan_centers centers ;
u16 clo , chi ;
int i ;
int matchIndex = - 1 , lowIndex = - 1 ;
u16 freq ;
ath9k_hw_get_channel_centers ( ah , chan , & centers ) ;
freq = isHt40Target ? centers . synth_center : centers . ctl_center ;
if ( freq < = ath9k_hw_fbin2freq ( powInfo [ 0 ] . bChannel , IS_CHAN_2GHZ ( chan ) ) ) {
matchIndex = 0 ;
} else {
for ( i = 0 ; ( i < numChannels ) & &
( powInfo [ i ] . bChannel ! = AR5416_BCHAN_UNUSED ) ; i + + ) {
if ( freq = = ath9k_hw_fbin2freq ( powInfo [ i ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ) {
matchIndex = i ;
break ;
} else
2009-08-07 23:50:00 +02:00
if ( freq < ath9k_hw_fbin2freq ( powInfo [ i ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) & & i > 0 & &
freq > ath9k_hw_fbin2freq ( powInfo [ i - 1 ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ) {
2009-02-09 13:27:24 +05:30
lowIndex = i - 1 ;
break ;
}
}
if ( ( matchIndex = = - 1 ) & & ( lowIndex = = - 1 ) )
matchIndex = i - 1 ;
}
if ( matchIndex ! = - 1 ) {
* pNewPower = powInfo [ matchIndex ] ;
} else {
clo = ath9k_hw_fbin2freq ( powInfo [ lowIndex ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ;
chi = ath9k_hw_fbin2freq ( powInfo [ lowIndex + 1 ] . bChannel ,
IS_CHAN_2GHZ ( chan ) ) ;
for ( i = 0 ; i < numRates ; i + + ) {
pNewPower - > tPow2x [ i ] = ( u8 ) ath9k_hw_interpolate ( freq ,
clo , chi ,
powInfo [ lowIndex ] . tPow2x [ i ] ,
powInfo [ lowIndex + 1 ] . tPow2x [ i ] ) ;
}
}
}
2009-08-07 09:45:15 +05:30
u16 ath9k_hw_get_max_edge_power ( u16 freq , struct cal_ctl_edges * pRdEdgesPower ,
bool is2GHz , int num_band_edges )
2009-02-09 13:27:24 +05:30
{
2010-12-12 00:51:08 +01:00
u16 twiceMaxEdgePower = MAX_RATE_POWER ;
2009-02-09 13:27:24 +05:30
int i ;
for ( i = 0 ; ( i < num_band_edges ) & &
( pRdEdgesPower [ i ] . bChannel ! = AR5416_BCHAN_UNUSED ) ; i + + ) {
if ( freq = = ath9k_hw_fbin2freq ( pRdEdgesPower [ i ] . bChannel , is2GHz ) ) {
2010-12-01 19:07:46 +01:00
twiceMaxEdgePower = CTL_EDGE_TPOWER ( pRdEdgesPower [ i ] . ctl ) ;
2009-02-09 13:27:24 +05:30
break ;
} else if ( ( i > 0 ) & &
( freq < ath9k_hw_fbin2freq ( pRdEdgesPower [ i ] . bChannel ,
is2GHz ) ) ) {
if ( ath9k_hw_fbin2freq ( pRdEdgesPower [ i - 1 ] . bChannel ,
is2GHz ) < freq & &
2010-12-01 19:07:46 +01:00
CTL_EDGE_FLAGS ( pRdEdgesPower [ i - 1 ] . ctl ) ) {
2009-02-09 13:27:24 +05:30
twiceMaxEdgePower =
2010-12-01 19:07:46 +01:00
CTL_EDGE_TPOWER ( pRdEdgesPower [ i - 1 ] . ctl ) ;
2009-02-09 13:27:24 +05:30
}
break ;
}
}
return twiceMaxEdgePower ;
}
2012-04-14 22:01:58 +02:00
u16 ath9k_hw_get_scaled_power ( struct ath_hw * ah , u16 power_limit ,
u8 antenna_reduction )
{
2012-04-14 22:01:59 +02:00
u16 reduction = antenna_reduction ;
2012-04-14 22:01:58 +02:00
/*
* Reduce scaled Power by number of chains active
* to get the per chain tx power level .
*/
switch ( ar5416_get_ntxchains ( ah - > txchainmask ) ) {
case 1 :
break ;
case 2 :
2012-04-16 22:22:49 +02:00
reduction + = POWER_CORRECTION_FOR_TWO_CHAIN ;
2012-04-14 22:01:58 +02:00
break ;
case 3 :
2012-04-16 22:22:49 +02:00
reduction + = POWER_CORRECTION_FOR_THREE_CHAIN ;
2012-04-14 22:01:58 +02:00
break ;
}
2012-04-14 22:01:59 +02:00
if ( power_limit > reduction )
power_limit - = reduction ;
else
power_limit = 0 ;
2012-04-14 22:01:58 +02:00
2012-04-14 22:01:59 +02:00
return power_limit ;
2012-04-14 22:01:58 +02:00
}
2010-06-01 15:14:07 +05:30
void ath9k_hw_update_regulatory_maxpower ( struct ath_hw * ah )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
struct ath_regulatory * regulatory = ath9k_hw_regulatory ( ah ) ;
switch ( ar5416_get_ntxchains ( ah - > txchainmask ) ) {
case 1 :
break ;
case 2 :
2012-04-16 22:22:49 +02:00
regulatory - > max_power_level + = POWER_CORRECTION_FOR_TWO_CHAIN ;
2010-06-01 15:14:07 +05:30
break ;
case 3 :
2012-04-16 22:22:49 +02:00
regulatory - > max_power_level + = POWER_CORRECTION_FOR_THREE_CHAIN ;
2010-06-01 15:14:07 +05:30
break ;
default :
2011-12-15 14:55:53 -08:00
ath_dbg ( common , EEPROM , " Invalid chainmask configuration \n " ) ;
2010-06-01 15:14:07 +05:30
break ;
}
}
2010-12-12 00:51:09 +01:00
void ath9k_hw_get_gain_boundaries_pdadcs ( struct ath_hw * ah ,
struct ath9k_channel * chan ,
void * pRawDataSet ,
u8 * bChans , u16 availPiers ,
u16 tPdGainOverlap ,
u16 * pPdGainBoundaries , u8 * pPDADCValues ,
u16 numXpdGains )
{
int i , j , k ;
int16_t ss ;
u16 idxL = 0 , idxR = 0 , numPiers ;
static u8 vpdTableL [ AR5416_NUM_PD_GAINS ]
[ AR5416_MAX_PWR_RANGE_IN_HALF_DB ] ;
static u8 vpdTableR [ AR5416_NUM_PD_GAINS ]
[ AR5416_MAX_PWR_RANGE_IN_HALF_DB ] ;
static u8 vpdTableI [ AR5416_NUM_PD_GAINS ]
[ AR5416_MAX_PWR_RANGE_IN_HALF_DB ] ;
u8 * pVpdL , * pVpdR , * pPwrL , * pPwrR ;
u8 minPwrT4 [ AR5416_NUM_PD_GAINS ] ;
u8 maxPwrT4 [ AR5416_NUM_PD_GAINS ] ;
int16_t vpdStep ;
int16_t tmpVal ;
u16 sizeCurrVpdTable , maxIndex , tgtIndex ;
bool match ;
int16_t minDelta = 0 ;
struct chan_centers centers ;
int pdgain_boundary_default ;
struct cal_data_per_freq * data_def = pRawDataSet ;
struct cal_data_per_freq_4k * data_4k = pRawDataSet ;
2010-12-12 00:51:10 +01:00
struct cal_data_per_freq_ar9287 * data_9287 = pRawDataSet ;
2010-12-12 00:51:09 +01:00
bool eeprom_4k = AR_SREV_9285 ( ah ) | | AR_SREV_9271 ( ah ) ;
2010-12-12 00:51:10 +01:00
int intercepts ;
if ( AR_SREV_9287 ( ah ) )
intercepts = AR9287_PD_GAIN_ICEPTS ;
else
intercepts = AR5416_PD_GAIN_ICEPTS ;
2010-12-12 00:51:09 +01:00
memset ( & minPwrT4 , 0 , AR5416_NUM_PD_GAINS ) ;
ath9k_hw_get_channel_centers ( ah , chan , & centers ) ;
for ( numPiers = 0 ; numPiers < availPiers ; numPiers + + ) {
if ( bChans [ numPiers ] = = AR5416_BCHAN_UNUSED )
break ;
}
match = ath9k_hw_get_lower_upper_index ( ( u8 ) FREQ2FBIN ( centers . synth_center ,
IS_CHAN_2GHZ ( chan ) ) ,
bChans , numPiers , & idxL , & idxR ) ;
if ( match ) {
2010-12-12 00:51:10 +01:00
if ( AR_SREV_9287 ( ah ) ) {
for ( i = 0 ; i < numXpdGains ; i + + ) {
minPwrT4 [ i ] = data_9287 [ idxL ] . pwrPdg [ i ] [ 0 ] ;
2016-03-14 15:18:36 +01:00
maxPwrT4 [ i ] = data_9287 [ idxL ] . pwrPdg [ i ] [ intercepts - 1 ] ;
2010-12-12 00:51:10 +01:00
ath9k_hw_fill_vpd_table ( minPwrT4 [ i ] , maxPwrT4 [ i ] ,
data_9287 [ idxL ] . pwrPdg [ i ] ,
data_9287 [ idxL ] . vpdPdg [ i ] ,
intercepts ,
vpdTableI [ i ] ) ;
}
} else if ( eeprom_4k ) {
2010-12-12 00:51:09 +01:00
for ( i = 0 ; i < numXpdGains ; i + + ) {
minPwrT4 [ i ] = data_4k [ idxL ] . pwrPdg [ i ] [ 0 ] ;
2016-03-14 15:18:36 +01:00
maxPwrT4 [ i ] = data_4k [ idxL ] . pwrPdg [ i ] [ intercepts - 1 ] ;
2010-12-12 00:51:09 +01:00
ath9k_hw_fill_vpd_table ( minPwrT4 [ i ] , maxPwrT4 [ i ] ,
data_4k [ idxL ] . pwrPdg [ i ] ,
data_4k [ idxL ] . vpdPdg [ i ] ,
2010-12-12 00:51:10 +01:00
intercepts ,
2010-12-12 00:51:09 +01:00
vpdTableI [ i ] ) ;
}
} else {
for ( i = 0 ; i < numXpdGains ; i + + ) {
minPwrT4 [ i ] = data_def [ idxL ] . pwrPdg [ i ] [ 0 ] ;
2016-03-14 15:18:36 +01:00
maxPwrT4 [ i ] = data_def [ idxL ] . pwrPdg [ i ] [ intercepts - 1 ] ;
2010-12-12 00:51:09 +01:00
ath9k_hw_fill_vpd_table ( minPwrT4 [ i ] , maxPwrT4 [ i ] ,
data_def [ idxL ] . pwrPdg [ i ] ,
data_def [ idxL ] . vpdPdg [ i ] ,
2010-12-12 00:51:10 +01:00
intercepts ,
2010-12-12 00:51:09 +01:00
vpdTableI [ i ] ) ;
}
}
} else {
for ( i = 0 ; i < numXpdGains ; i + + ) {
2010-12-12 00:51:10 +01:00
if ( AR_SREV_9287 ( ah ) ) {
pVpdL = data_9287 [ idxL ] . vpdPdg [ i ] ;
pPwrL = data_9287 [ idxL ] . pwrPdg [ i ] ;
pVpdR = data_9287 [ idxR ] . vpdPdg [ i ] ;
pPwrR = data_9287 [ idxR ] . pwrPdg [ i ] ;
} else if ( eeprom_4k ) {
2010-12-12 00:51:09 +01:00
pVpdL = data_4k [ idxL ] . vpdPdg [ i ] ;
pPwrL = data_4k [ idxL ] . pwrPdg [ i ] ;
pVpdR = data_4k [ idxR ] . vpdPdg [ i ] ;
pPwrR = data_4k [ idxR ] . pwrPdg [ i ] ;
} else {
pVpdL = data_def [ idxL ] . vpdPdg [ i ] ;
pPwrL = data_def [ idxL ] . pwrPdg [ i ] ;
pVpdR = data_def [ idxR ] . vpdPdg [ i ] ;
pPwrR = data_def [ idxR ] . pwrPdg [ i ] ;
}
minPwrT4 [ i ] = max ( pPwrL [ 0 ] , pPwrR [ 0 ] ) ;
maxPwrT4 [ i ] =
2010-12-12 00:51:10 +01:00
min ( pPwrL [ intercepts - 1 ] ,
pPwrR [ intercepts - 1 ] ) ;
2010-12-12 00:51:09 +01:00
ath9k_hw_fill_vpd_table ( minPwrT4 [ i ] , maxPwrT4 [ i ] ,
pPwrL , pVpdL ,
2010-12-12 00:51:10 +01:00
intercepts ,
2010-12-12 00:51:09 +01:00
vpdTableL [ i ] ) ;
ath9k_hw_fill_vpd_table ( minPwrT4 [ i ] , maxPwrT4 [ i ] ,
pPwrR , pVpdR ,
2010-12-12 00:51:10 +01:00
intercepts ,
2010-12-12 00:51:09 +01:00
vpdTableR [ i ] ) ;
for ( j = 0 ; j < = ( maxPwrT4 [ i ] - minPwrT4 [ i ] ) / 2 ; j + + ) {
vpdTableI [ i ] [ j ] =
( u8 ) ( ath9k_hw_interpolate ( ( u16 )
FREQ2FBIN ( centers .
synth_center ,
IS_CHAN_2GHZ
( chan ) ) ,
bChans [ idxL ] , bChans [ idxR ] ,
vpdTableL [ i ] [ j ] , vpdTableR [ i ] [ j ] ) ) ;
}
}
}
k = 0 ;
for ( i = 0 ; i < numXpdGains ; i + + ) {
if ( i = = ( numXpdGains - 1 ) )
pPdGainBoundaries [ i ] =
( u16 ) ( maxPwrT4 [ i ] / 2 ) ;
else
pPdGainBoundaries [ i ] =
( u16 ) ( ( maxPwrT4 [ i ] + minPwrT4 [ i + 1 ] ) / 4 ) ;
pPdGainBoundaries [ i ] =
min ( ( u16 ) MAX_RATE_POWER , pPdGainBoundaries [ i ] ) ;
2011-09-15 14:25:35 +02:00
minDelta = 0 ;
2010-12-12 00:51:09 +01:00
if ( i = = 0 ) {
if ( AR_SREV_9280_20_OR_LATER ( ah ) )
ss = ( int16_t ) ( 0 - ( minPwrT4 [ i ] / 2 ) ) ;
else
ss = 0 ;
} else {
ss = ( int16_t ) ( ( pPdGainBoundaries [ i - 1 ] -
( minPwrT4 [ i ] / 2 ) ) -
tPdGainOverlap + 1 + minDelta ) ;
}
vpdStep = ( int16_t ) ( vpdTableI [ i ] [ 1 ] - vpdTableI [ i ] [ 0 ] ) ;
vpdStep = ( int16_t ) ( ( vpdStep < 1 ) ? 1 : vpdStep ) ;
while ( ( ss < 0 ) & & ( k < ( AR5416_NUM_PDADC_VALUES - 1 ) ) ) {
tmpVal = ( int16_t ) ( vpdTableI [ i ] [ 0 ] + ss * vpdStep ) ;
pPDADCValues [ k + + ] = ( u8 ) ( ( tmpVal < 0 ) ? 0 : tmpVal ) ;
ss + + ;
}
sizeCurrVpdTable = ( u8 ) ( ( maxPwrT4 [ i ] - minPwrT4 [ i ] ) / 2 + 1 ) ;
tgtIndex = ( u8 ) ( pPdGainBoundaries [ i ] + tPdGainOverlap -
( minPwrT4 [ i ] / 2 ) ) ;
maxIndex = ( tgtIndex < sizeCurrVpdTable ) ?
tgtIndex : sizeCurrVpdTable ;
while ( ( ss < maxIndex ) & & ( k < ( AR5416_NUM_PDADC_VALUES - 1 ) ) ) {
pPDADCValues [ k + + ] = vpdTableI [ i ] [ ss + + ] ;
}
vpdStep = ( int16_t ) ( vpdTableI [ i ] [ sizeCurrVpdTable - 1 ] -
vpdTableI [ i ] [ sizeCurrVpdTable - 2 ] ) ;
vpdStep = ( int16_t ) ( ( vpdStep < 1 ) ? 1 : vpdStep ) ;
if ( tgtIndex > = maxIndex ) {
while ( ( ss < = tgtIndex ) & &
( k < ( AR5416_NUM_PDADC_VALUES - 1 ) ) ) {
tmpVal = ( int16_t ) ( ( vpdTableI [ i ] [ sizeCurrVpdTable - 1 ] +
( ss - maxIndex + 1 ) * vpdStep ) ) ;
pPDADCValues [ k + + ] = ( u8 ) ( ( tmpVal > 255 ) ?
255 : tmpVal ) ;
ss + + ;
}
}
}
if ( eeprom_4k )
pdgain_boundary_default = 58 ;
else
pdgain_boundary_default = pPdGainBoundaries [ i - 1 ] ;
while ( i < AR5416_PD_GAINS_IN_MASK ) {
pPdGainBoundaries [ i ] = pdgain_boundary_default ;
i + + ;
}
while ( k < AR5416_NUM_PDADC_VALUES ) {
pPDADCValues [ k ] = pPDADCValues [ k - 1 ] ;
k + + ;
}
}
2009-08-03 12:24:46 -07:00
int ath9k_hw_eeprom_init ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
int status ;
2009-08-07 09:45:11 +05:30
2010-04-15 17:39:14 -04:00
if ( AR_SREV_9300_20_OR_LATER ( ah ) )
ah - > eep_ops = & eep_ar9300_ops ;
else if ( AR_SREV_9287 ( ah ) ) {
2010-04-15 17:39:12 -04:00
ah - > eep_ops = & eep_ar9287_ops ;
2009-08-03 23:14:12 -04:00
} else if ( AR_SREV_9285 ( ah ) | | AR_SREV_9271 ( ah ) ) {
2009-02-09 13:27:24 +05:30
ah - > eep_ops = & eep_4k_ops ;
} else {
ah - > eep_ops = & eep_def_ops ;
}
2008-12-08 19:43:48 +05:30
2009-02-09 13:27:24 +05:30
if ( ! ah - > eep_ops - > fill_eeprom ( ah ) )
2008-10-29 10:16:30 +05:30
return - EIO ;
2009-02-09 13:27:24 +05:30
status = ah - > eep_ops - > check_eeprom ( ah ) ;
2008-10-29 10:16:30 +05:30
return status ;
}