2008-08-04 00:16:41 -07:00
/*
* 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 <linux/io.h>
# include <asm/unaligned.h>
2009-02-09 13:26:54 +05:30
# include "ath9k.h"
2008-08-04 00:16:41 -07:00
# include "initvals.h"
2009-01-10 17:07:09 +05:30
static int btcoex_enable ;
module_param ( btcoex_enable , bool , 0 ) ;
MODULE_PARM_DESC ( btcoex_enable , " Enable Bluetooth coexistence support " ) ;
2008-12-23 15:58:48 -08:00
# define ATH9K_CLOCK_RATE_CCK 22
# define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
# define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_set_reset_reg ( struct ath_hw * ah , u32 type ) ;
static void ath9k_hw_set_regs ( struct ath_hw * ah , struct ath9k_channel * chan ,
2008-10-29 10:16:30 +05:30
enum ath9k_ht_macmode macmode ) ;
2009-02-09 13:27:12 +05:30
static u32 ath9k_hw_ini_fixup ( struct ath_hw * ah ,
2008-12-08 19:43:48 +05:30
struct ar5416_eeprom_def * pEepData ,
2008-10-29 10:16:30 +05:30
u32 reg , u32 value ) ;
2009-02-09 13:27:12 +05:30
static void ath9k_hw_9280_spur_mitigate ( struct ath_hw * ah , struct ath9k_channel * chan ) ;
static void ath9k_hw_spur_mitigate ( struct ath_hw * ah , struct ath9k_channel * chan ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
/********************/
/* Helper Functions */
/********************/
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
static u32 ath9k_hw_mac_usec ( struct ath_hw * ah , u32 clks )
2008-10-29 10:16:30 +05:30
{
2008-12-23 15:58:48 -08:00
struct ieee80211_conf * conf = & ah - > ah_sc - > hw - > conf ;
2009-02-09 13:27:12 +05:30
2008-12-23 15:58:48 -08:00
if ( ! ah - > ah_curchan ) /* should really check for CCK instead */
return clks / ATH9K_CLOCK_RATE_CCK ;
if ( conf - > channel - > band = = IEEE80211_BAND_2GHZ )
return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM ;
2009-02-09 13:27:12 +05:30
2008-12-23 15:58:48 -08:00
return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM ;
2008-10-29 10:16:30 +05:30
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
static u32 ath9k_hw_mac_to_usec ( struct ath_hw * ah , u32 clks )
2008-10-29 10:16:30 +05:30
{
2008-12-23 15:58:48 -08:00
struct ieee80211_conf * conf = & ah - > ah_sc - > hw - > conf ;
2009-02-09 13:27:12 +05:30
2008-12-23 15:58:48 -08:00
if ( conf_is_ht40 ( conf ) )
2008-10-29 10:16:30 +05:30
return ath9k_hw_mac_usec ( ah , clks ) / 2 ;
else
return ath9k_hw_mac_usec ( ah , clks ) ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
static u32 ath9k_hw_mac_clks ( struct ath_hw * ah , u32 usecs )
2008-10-29 10:16:30 +05:30
{
2008-12-23 15:58:48 -08:00
struct ieee80211_conf * conf = & ah - > ah_sc - > hw - > conf ;
2009-02-09 13:27:12 +05:30
2008-12-23 15:58:48 -08:00
if ( ! ah - > ah_curchan ) /* should really check for CCK instead */
return usecs * ATH9K_CLOCK_RATE_CCK ;
if ( conf - > channel - > band = = IEEE80211_BAND_2GHZ )
return usecs * ATH9K_CLOCK_RATE_2GHZ_OFDM ;
return usecs * ATH9K_CLOCK_RATE_5GHZ_OFDM ;
2008-10-29 10:16:30 +05:30
}
2009-02-09 13:27:12 +05:30
static u32 ath9k_hw_mac_to_clks ( struct ath_hw * ah , u32 usecs )
2008-10-29 10:16:30 +05:30
{
2008-12-23 15:58:48 -08:00
struct ieee80211_conf * conf = & ah - > ah_sc - > hw - > conf ;
2009-02-09 13:27:12 +05:30
2008-12-23 15:58:48 -08:00
if ( conf_is_ht40 ( conf ) )
2008-10-29 10:16:30 +05:30
return ath9k_hw_mac_clks ( ah , usecs ) * 2 ;
else
return ath9k_hw_mac_clks ( ah , usecs ) ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
bool ath9k_hw_wait ( struct ath_hw * ah , u32 reg , u32 mask , u32 val )
2008-08-04 00:16:41 -07:00
{
int i ;
for ( i = 0 ; i < ( AH_TIMEOUT / AH_TIME_QUANTUM ) ; i + + ) {
if ( ( REG_READ ( ah , reg ) & mask ) = = val )
return true ;
udelay ( AH_TIME_QUANTUM ) ;
}
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_REG_IO ,
" timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x \n " ,
reg , REG_READ ( ah , reg ) , mask , val ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
}
u32 ath9k_hw_reverse_bits ( u32 val , u32 n )
{
u32 retval ;
int i ;
for ( i = 0 , retval = 0 ; i < n ; i + + ) {
retval = ( retval < < 1 ) | ( val & 1 ) ;
val > > = 1 ;
}
return retval ;
}
2009-02-09 13:27:12 +05:30
bool ath9k_get_channel_edges ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
u16 flags , u16 * low ,
u16 * high )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > ah_caps ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( flags & CHANNEL_5GHZ ) {
* low = pCap - > low_5ghz_chan ;
* high = pCap - > high_5ghz_chan ;
return true ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
if ( ( flags & CHANNEL_2GHZ ) ) {
* low = pCap - > low_2ghz_chan ;
* high = pCap - > high_2ghz_chan ;
return true ;
}
return false ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
u16 ath9k_hw_computetxtime ( struct ath_hw * ah ,
2008-11-18 09:07:53 +05:30
struct ath_rate_table * rates ,
2008-10-29 10:16:30 +05:30
u32 frameLen , u16 rateix ,
bool shortPreamble )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 bitsPerSymbol , numBits , numSymbols , phyTime , txTime ;
u32 kbps ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:07:53 +05:30
kbps = rates - > info [ rateix ] . ratekbps ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( kbps = = 0 )
return 0 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
switch ( rates - > info [ rateix ] . phy ) {
2008-11-18 09:08:13 +05:30
case WLAN_RC_PHY_CCK :
2008-10-29 10:16:30 +05:30
phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS ;
2008-11-18 09:07:53 +05:30
if ( shortPreamble & & rates - > info [ rateix ] . short_preamble )
2008-10-29 10:16:30 +05:30
phyTime > > = 1 ;
numBits = frameLen < < 3 ;
txTime = CCK_SIFS_TIME + phyTime + ( ( numBits * 1000 ) / kbps ) ;
break ;
2008-11-18 09:08:13 +05:30
case WLAN_RC_PHY_OFDM :
2008-10-29 10:16:30 +05:30
if ( ah - > ah_curchan & & IS_CHAN_QUARTER_RATE ( ah - > ah_curchan ) ) {
bitsPerSymbol = ( kbps * OFDM_SYMBOL_TIME_QUARTER ) / 1000 ;
numBits = OFDM_PLCP_BITS + ( frameLen < < 3 ) ;
numSymbols = DIV_ROUND_UP ( numBits , bitsPerSymbol ) ;
txTime = OFDM_SIFS_TIME_QUARTER
+ OFDM_PREAMBLE_TIME_QUARTER
+ ( numSymbols * OFDM_SYMBOL_TIME_QUARTER ) ;
} else if ( ah - > ah_curchan & &
IS_CHAN_HALF_RATE ( ah - > ah_curchan ) ) {
bitsPerSymbol = ( kbps * OFDM_SYMBOL_TIME_HALF ) / 1000 ;
numBits = OFDM_PLCP_BITS + ( frameLen < < 3 ) ;
numSymbols = DIV_ROUND_UP ( numBits , bitsPerSymbol ) ;
txTime = OFDM_SIFS_TIME_HALF +
OFDM_PREAMBLE_TIME_HALF
+ ( numSymbols * OFDM_SYMBOL_TIME_HALF ) ;
} else {
bitsPerSymbol = ( kbps * OFDM_SYMBOL_TIME ) / 1000 ;
numBits = OFDM_PLCP_BITS + ( frameLen < < 3 ) ;
numSymbols = DIV_ROUND_UP ( numBits , bitsPerSymbol ) ;
txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
+ ( numSymbols * OFDM_SYMBOL_TIME ) ;
}
break ;
default :
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_REG_IO ,
" Unknown phy %u (rate ix %u) \n " ,
2008-10-29 10:16:30 +05:30
rates - > info [ rateix ] . phy , rateix ) ;
txTime = 0 ;
break ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return txTime ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
void ath9k_hw_get_channel_centers ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan ,
struct chan_centers * centers )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
int8_t extoff ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ! IS_CHAN_HT40 ( chan ) ) {
centers - > ctl_center = centers - > ext_center =
centers - > synth_center = chan - > channel ;
return ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
if ( ( chan - > chanmode = = CHANNEL_A_HT40PLUS ) | |
( chan - > chanmode = = CHANNEL_G_HT40PLUS ) ) {
centers - > synth_center =
chan - > channel + HT40_CHANNEL_CENTER_SHIFT ;
extoff = 1 ;
} else {
centers - > synth_center =
chan - > channel - HT40_CHANNEL_CENTER_SHIFT ;
extoff = - 1 ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
centers - > ctl_center =
centers - > synth_center - ( extoff * HT40_CHANNEL_CENTER_SHIFT ) ;
centers - > ext_center =
centers - > synth_center + ( extoff *
2009-02-09 13:27:12 +05:30
( ( ah - > ah_extprotspacing = = ATH9K_HT_EXTPROTSPACING_20 ) ?
2008-10-29 10:16:30 +05:30
HT40_CHANNEL_CENTER_SHIFT : 15 ) ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
/******************/
/* Chip Revisions */
/******************/
2009-02-09 13:27:12 +05:30
static void ath9k_hw_read_revisions ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 val ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
val = REG_READ ( ah , AR_SREV ) & AR_SREV_ID ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( val = = 0xFF ) {
val = REG_READ ( ah , AR_SREV ) ;
2009-02-09 13:27:06 +05:30
ah - > hw_version . macVersion =
( val & AR_SREV_VERSION2 ) > > AR_SREV_TYPE2_S ;
ah - > hw_version . macRev = MS ( val , AR_SREV_REVISION2 ) ;
2008-10-29 10:16:30 +05:30
ah - > ah_isPciExpress = ( val & AR_SREV_TYPE2_HOST_MODE ) ? 0 : 1 ;
} else {
if ( ! AR_SREV_9100 ( ah ) )
2009-02-09 13:27:06 +05:30
ah - > hw_version . macVersion = MS ( val , AR_SREV_VERSION ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:06 +05:30
ah - > hw_version . macRev = val & AR_SREV_REVISION ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:06 +05:30
if ( ah - > hw_version . macVersion = = AR_SREV_VERSION_5416_PCIE )
2008-10-29 10:16:30 +05:30
ah - > ah_isPciExpress = true ;
}
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static int ath9k_hw_get_radiorev ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 val ;
int i ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PHY ( 0x36 ) , 0x00007058 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
for ( i = 0 ; i < 8 ; i + + )
REG_WRITE ( ah , AR_PHY ( 0x20 ) , 0x00010000 ) ;
val = ( REG_READ ( ah , AR_PHY ( 256 ) ) > > 24 ) & 0xff ;
val = ( ( val & 0xf0 ) > > 4 ) | ( ( val & 0x0f ) < < 4 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return ath9k_hw_reverse_bits ( val , 8 ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
/************************************/
/* HW Attach, Detach, Init Routines */
/************************************/
2009-02-09 13:27:12 +05:30
static void ath9k_hw_disablepcie ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2009-01-29 11:37:35 +05:30
if ( AR_SREV_9100 ( ah ) )
2008-10-29 10:16:30 +05:30
return ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PCIE_SERDES , 0x9248fc00 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x24924924 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x28000029 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x57160824 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x25980579 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x00000000 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x1aaabe40 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xbe105554 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x000e1007 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PCIE_SERDES2 , 0x00000000 ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_chip_test ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 regAddr [ 2 ] = { AR_STA_ID0 , AR_PHY_BASE + ( 8 < < 2 ) } ;
u32 regHold [ 2 ] ;
u32 patternData [ 4 ] = { 0x55555555 ,
0xaaaaaaaa ,
0x66666666 ,
0x99999999 } ;
int i , j ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
for ( i = 0 ; i < 2 ; i + + ) {
u32 addr = regAddr [ i ] ;
u32 wrData , rdData ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
regHold [ i ] = REG_READ ( ah , addr ) ;
for ( j = 0 ; j < 0x100 ; j + + ) {
wrData = ( j < < 16 ) | j ;
REG_WRITE ( ah , addr , wrData ) ;
rdData = REG_READ ( ah , addr ) ;
if ( rdData ! = wrData ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_REG_IO ,
2008-11-28 22:18:05 +05:30
" address test failed "
2008-10-29 10:16:30 +05:30
" addr: 0x%08x - wr:0x%08x != rd:0x%08x \n " ,
2008-11-28 22:18:05 +05:30
addr , wrData , rdData ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
}
for ( j = 0 ; j < 4 ; j + + ) {
wrData = patternData [ j ] ;
REG_WRITE ( ah , addr , wrData ) ;
rdData = REG_READ ( ah , addr ) ;
if ( wrData ! = rdData ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_REG_IO ,
2008-11-28 22:18:05 +05:30
" address test failed "
2008-10-29 10:16:30 +05:30
" addr: 0x%08x - wr:0x%08x != rd:0x%08x \n " ,
2008-11-28 22:18:05 +05:30
addr , wrData , rdData ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , regAddr [ i ] , regHold [ i ] ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
udelay ( 100 ) ;
2009-02-09 13:27:12 +05:30
2008-08-04 00:16:41 -07:00
return true ;
}
2008-10-29 10:16:30 +05:30
static const char * ath9k_hw_devname ( u16 devid )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
switch ( devid ) {
case AR5416_DEVID_PCI :
return " Atheros 5416 " ;
2008-11-06 22:26:49 +01:00
case AR5416_DEVID_PCIE :
return " Atheros 5418 " ;
2008-10-29 10:16:30 +05:30
case AR9160_DEVID_PCI :
return " Atheros 9160 " ;
2009-01-14 20:17:12 +01:00
case AR5416_AR9100_DEVID :
return " Atheros 9100 " ;
2008-10-29 10:16:30 +05:30
case AR9280_DEVID_PCI :
case AR9280_DEVID_PCIE :
return " Atheros 9280 " ;
2008-12-08 19:43:48 +05:30
case AR9285_DEVID_PCIE :
return " Atheros 9285 " ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
return NULL ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
static void ath9k_hw_set_defaults ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
int i ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
ah - > ah_config . dma_beacon_response_time = 2 ;
ah - > ah_config . sw_beacon_response_time = 10 ;
ah - > ah_config . additional_swba_backoff = 0 ;
ah - > ah_config . ack_6mb = 0x0 ;
ah - > ah_config . cwm_ignore_extcca = 0 ;
ah - > ah_config . pcie_powersave_enable = 0 ;
ah - > ah_config . pcie_l1skp_enable = 0 ;
ah - > ah_config . pcie_clock_req = 0 ;
ah - > ah_config . pcie_power_reset = 0x100 ;
ah - > ah_config . pcie_restore = 0 ;
ah - > ah_config . pcie_waen = 0 ;
ah - > ah_config . analog_shiftreg = 1 ;
ah - > ah_config . ht_enable = 1 ;
ah - > ah_config . ofdm_trig_low = 200 ;
ah - > ah_config . ofdm_trig_high = 500 ;
ah - > ah_config . cck_trig_high = 200 ;
ah - > ah_config . cck_trig_low = 100 ;
ah - > ah_config . enable_ani = 1 ;
ah - > ah_config . noise_immunity_level = 4 ;
ah - > ah_config . ofdm_weaksignal_det = 1 ;
ah - > ah_config . cck_weaksignal_thr = 0 ;
ah - > ah_config . spur_immunity_level = 2 ;
ah - > ah_config . firstep_level = 0 ;
ah - > ah_config . rssi_thr_high = 40 ;
ah - > ah_config . rssi_thr_low = 7 ;
ah - > ah_config . diversity_control = 0 ;
ah - > ah_config . antenna_switch_swap = 0 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
for ( i = 0 ; i < AR_EEPROM_MODAL_SPURS ; i + + ) {
ah - > ah_config . spurchans [ i ] [ 0 ] = AR_NO_SPUR ;
ah - > ah_config . spurchans [ i ] [ 1 ] = AR_NO_SPUR ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
ah - > ah_config . intr_mitigation = 1 ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static struct ath_hw * ath9k_hw_newstate ( u16 devid , struct ath_softc * sc ,
int * status )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
struct ath_hw * ah ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
ah = kzalloc ( sizeof ( struct ath_hw ) , GFP_KERNEL ) ;
if ( ah = = NULL ) {
2008-08-04 00:16:41 -07:00
DPRINTF ( sc , ATH_DBG_FATAL ,
2008-11-28 22:18:05 +05:30
" Cannot allocate memory for state block \n " ) ;
2008-08-04 00:16:41 -07:00
* status = - ENOMEM ;
return NULL ;
}
ah - > ah_sc = sc ;
2009-02-09 13:27:06 +05:30
ah - > hw_version . magic = AR5416_MAGIC ;
2009-02-09 13:27:08 +05:30
ah - > regulatory . country_code = CTRY_DEFAULT ;
2009-02-09 13:27:06 +05:30
ah - > hw_version . devid = devid ;
ah - > hw_version . subvendorid = 0 ;
2008-08-04 00:16:41 -07:00
ah - > ah_flags = 0 ;
if ( ( devid = = AR5416_AR9100_DEVID ) )
2009-02-09 13:27:06 +05:30
ah - > hw_version . macVersion = AR_SREV_VERSION_9100 ;
2008-08-04 00:16:41 -07:00
if ( ! AR_SREV_9100 ( ah ) )
ah - > ah_flags = AH_USE_EEPROM ;
2009-02-09 13:27:08 +05:30
ah - > regulatory . power_limit = MAX_RATE_POWER ;
ah - > regulatory . tp_scale = ATH9K_TP_SCALE_MAX ;
2009-02-09 13:27:12 +05:30
ah - > ah_atimWindow = 0 ;
ah - > ah_diversityControl = ah - > ah_config . diversity_control ;
ah - > ah_antennaSwitchSwap =
2008-08-07 10:52:38 +05:30
ah - > ah_config . antenna_switch_swap ;
2009-02-09 13:27:12 +05:30
ah - > ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE ;
ah - > ah_beaconInterval = 100 ;
ah - > ah_enable32kHzClock = DONT_USE_32KHZ ;
ah - > ah_slottime = ( u32 ) - 1 ;
ah - > ah_acktimeout = ( u32 ) - 1 ;
ah - > ah_ctstimeout = ( u32 ) - 1 ;
ah - > ah_globaltxtimeout = ( u32 ) - 1 ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
ah - > ah_gBeaconRate = 0 ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
return ah ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static int ath9k_hw_rfattach ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
bool rfStatus = false ;
int ecode = 0 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
rfStatus = ath9k_hw_init_rf ( ah , & ecode ) ;
if ( ! rfStatus ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" RF setup failed, status %u \n " , ecode ) ;
2008-10-29 10:16:30 +05:30
return ecode ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static int ath9k_hw_rf_claim ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 val ;
REG_WRITE ( ah , AR_PHY ( 0 ) , 0x00000007 ) ;
val = ath9k_hw_get_radiorev ( ah ) ;
switch ( val & AR_RADIO_SREV_MAJOR ) {
case 0 :
val = AR_RAD5133_SREV_MAJOR ;
break ;
case AR_RAD5133_SREV_MAJOR :
case AR_RAD5122_SREV_MAJOR :
case AR_RAD2133_SREV_MAJOR :
case AR_RAD2122_SREV_MAJOR :
break ;
2008-08-04 00:16:41 -07:00
default :
2008-10-29 10:16:30 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_CHANNEL ,
2008-11-28 22:18:05 +05:30
" 5G Radio Chip Rev 0x%02X is not "
2008-10-29 10:16:30 +05:30
" supported by this driver \n " ,
2009-02-09 13:27:06 +05:30
ah - > hw_version . analog5GhzRev ) ;
2008-10-29 10:16:30 +05:30
return - EOPNOTSUPP ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:06 +05:30
ah - > hw_version . analog5GhzRev = val ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static int ath9k_hw_init_macaddr ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
u32 sum ;
int i ;
u16 eeval ;
sum = 0 ;
for ( i = 0 ; i < 3 ; i + + ) {
2008-10-29 10:16:30 +05:30
eeval = ath9k_hw_get_eeprom ( ah , AR_EEPROM_MAC ( i ) ) ;
2008-08-04 00:16:41 -07:00
sum + = eeval ;
2009-02-09 13:27:10 +05:30
ah - > macaddr [ 2 * i ] = eeval > > 8 ;
ah - > macaddr [ 2 * i + 1 ] = eeval & 0xff ;
2008-08-04 00:16:41 -07:00
}
if ( sum = = 0 | | sum = = 0xffff * 3 ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_EEPROM ,
2008-11-28 22:18:05 +05:30
" mac address read failed: %pM \n " ,
2009-02-09 13:27:10 +05:30
ah - > macaddr ) ;
2008-08-04 00:16:41 -07:00
return - EADDRNOTAVAIL ;
}
return 0 ;
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_init_rxgain_ini ( struct ath_hw * ah )
2008-11-13 17:58:41 +05:30
{
u32 rxgain_type ;
if ( ath9k_hw_get_eeprom ( ah , EEP_MINOR_REV ) > = AR5416_EEP_MINOR_VER_17 ) {
rxgain_type = ath9k_hw_get_eeprom ( ah , EEP_RXGAIN_TYPE ) ;
if ( rxgain_type = = AR5416_EEP_RXGAIN_13DB_BACKOFF )
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModesRxGain ,
2008-11-13 17:58:41 +05:30
ar9280Modes_backoff_13db_rxgain_9280_2 ,
ARRAY_SIZE ( ar9280Modes_backoff_13db_rxgain_9280_2 ) , 6 ) ;
else if ( rxgain_type = = AR5416_EEP_RXGAIN_23DB_BACKOFF )
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModesRxGain ,
2008-11-13 17:58:41 +05:30
ar9280Modes_backoff_23db_rxgain_9280_2 ,
ARRAY_SIZE ( ar9280Modes_backoff_23db_rxgain_9280_2 ) , 6 ) ;
else
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModesRxGain ,
2008-11-13 17:58:41 +05:30
ar9280Modes_original_rxgain_9280_2 ,
ARRAY_SIZE ( ar9280Modes_original_rxgain_9280_2 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
} else {
INIT_INI_ARRAY ( & ah - > ah_iniModesRxGain ,
2008-11-13 17:58:41 +05:30
ar9280Modes_original_rxgain_9280_2 ,
ARRAY_SIZE ( ar9280Modes_original_rxgain_9280_2 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
}
2008-11-13 17:58:41 +05:30
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_init_txgain_ini ( struct ath_hw * ah )
2008-11-13 17:58:41 +05:30
{
u32 txgain_type ;
if ( ath9k_hw_get_eeprom ( ah , EEP_MINOR_REV ) > = AR5416_EEP_MINOR_VER_19 ) {
txgain_type = ath9k_hw_get_eeprom ( ah , EEP_TXGAIN_TYPE ) ;
if ( txgain_type = = AR5416_EEP_TXGAIN_HIGH_POWER )
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModesTxGain ,
2008-11-13 17:58:41 +05:30
ar9280Modes_high_power_tx_gain_9280_2 ,
ARRAY_SIZE ( ar9280Modes_high_power_tx_gain_9280_2 ) , 6 ) ;
else
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModesTxGain ,
2008-11-13 17:58:41 +05:30
ar9280Modes_original_tx_gain_9280_2 ,
ARRAY_SIZE ( ar9280Modes_original_tx_gain_9280_2 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
} else {
INIT_INI_ARRAY ( & ah - > ah_iniModesTxGain ,
2008-11-13 17:58:41 +05:30
ar9280Modes_original_tx_gain_9280_2 ,
ARRAY_SIZE ( ar9280Modes_original_tx_gain_9280_2 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
}
2008-11-13 17:58:41 +05:30
}
2009-02-09 13:27:12 +05:30
static int ath9k_hw_post_attach ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
int ecode ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ! ath9k_hw_chip_test ( ah ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_REG_IO ,
2008-11-28 22:18:05 +05:30
" hardware self-test failed \n " ) ;
2008-10-29 10:16:30 +05:30
return - ENODEV ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
ecode = ath9k_hw_rf_claim ( ah ) ;
if ( ecode ! = 0 )
2008-08-04 00:16:41 -07:00
return ecode ;
2008-10-29 10:16:30 +05:30
ecode = ath9k_hw_eeprom_attach ( ah ) ;
if ( ecode ! = 0 )
return ecode ;
ecode = ath9k_hw_rfattach ( ah ) ;
if ( ecode ! = 0 )
return ecode ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ! AR_SREV_9100 ( ah ) ) {
ath9k_hw_ani_setup ( ah ) ;
ath9k_hw_ani_attach ( ah ) ;
2008-08-04 00:16:41 -07:00
}
return 0 ;
}
2009-02-09 13:27:12 +05:30
static struct ath_hw * ath9k_hw_do_attach ( u16 devid , struct ath_softc * sc ,
int * status )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
struct ath_hw * ah ;
2008-10-29 10:16:30 +05:30
int ecode ;
2008-12-07 21:43:10 +05:30
u32 i , j ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
ah = ath9k_hw_newstate ( devid , sc , status ) ;
if ( ah = = NULL )
2008-10-29 10:16:30 +05:30
return NULL ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
ath9k_hw_set_defaults ( ah ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ah - > ah_config . intr_mitigation ! = 0 )
2009-02-09 13:27:12 +05:30
ah - > ah_intrMitigation = true ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ! ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_POWER_ON ) ) {
2009-02-09 13:27:12 +05:30
DPRINTF ( sc , ATH_DBG_RESET , " Couldn't reset chip \n " ) ;
2008-10-29 10:16:30 +05:30
ecode = - EIO ;
goto bad ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ! ath9k_hw_setpower ( ah , ATH9K_PM_AWAKE ) ) {
2009-02-09 13:27:12 +05:30
DPRINTF ( sc , ATH_DBG_RESET , " Couldn't wakeup chip \n " ) ;
2008-10-29 10:16:30 +05:30
ecode = - EIO ;
goto bad ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ah - > ah_config . serialize_regmode = = SER_REG_MODE_AUTO ) {
2009-02-09 13:27:06 +05:30
if ( ah - > hw_version . macVersion = = AR_SREV_VERSION_5416_PCI ) {
2008-10-29 10:16:30 +05:30
ah - > ah_config . serialize_regmode =
SER_REG_MODE_ON ;
2008-08-04 00:16:41 -07:00
} else {
2008-10-29 10:16:30 +05:30
ah - > ah_config . serialize_regmode =
SER_REG_MODE_OFF ;
2008-08-04 00:16:41 -07:00
}
}
2009-02-09 13:27:12 +05:30
DPRINTF ( sc , ATH_DBG_RESET , " serialize_regmode is %d \n " ,
2008-11-28 22:18:05 +05:30
ah - > ah_config . serialize_regmode ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:06 +05:30
if ( ( ah - > hw_version . macVersion ! = AR_SREV_VERSION_5416_PCI ) & &
( ah - > hw_version . macVersion ! = AR_SREV_VERSION_5416_PCIE ) & &
( ah - > hw_version . macVersion ! = AR_SREV_VERSION_9160 ) & &
2008-12-08 19:43:48 +05:30
( ! AR_SREV_9100 ( ah ) ) & & ( ! AR_SREV_9280 ( ah ) ) & & ( ! AR_SREV_9285 ( ah ) ) ) {
2009-02-09 13:27:12 +05:30
DPRINTF ( sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" Mac Chip Rev 0x%02x.%x is not supported by "
2009-02-09 13:27:06 +05:30
" this driver \n " , ah - > hw_version . macVersion ,
ah - > hw_version . macRev ) ;
2008-10-29 10:16:30 +05:30
ecode = - EOPNOTSUPP ;
goto bad ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9100 ( ah ) ) {
2009-02-09 13:27:12 +05:30
ah - > ah_iqCalData . calData = & iq_cal_multi_sample ;
ah - > ah_suppCals = IQ_MISMATCH_CAL ;
2008-10-29 10:16:30 +05:30
ah - > ah_isPciExpress = false ;
}
2009-02-09 13:27:06 +05:30
ah - > hw_version . phyRev = REG_READ ( ah , AR_PHY_CHIP_ID ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9160_10_OR_LATER ( ah ) ) {
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
ah - > ah_iqCalData . calData = & iq_cal_single_sample ;
ah - > ah_adcGainCalData . calData =
2008-10-29 10:16:30 +05:30
& adc_gain_cal_single_sample ;
2009-02-09 13:27:12 +05:30
ah - > ah_adcDcCalData . calData =
2008-10-29 10:16:30 +05:30
& adc_dc_cal_single_sample ;
2009-02-09 13:27:12 +05:30
ah - > ah_adcDcCalInitData . calData =
2008-10-29 10:16:30 +05:30
& adc_init_dc_cal ;
} else {
2009-02-09 13:27:12 +05:30
ah - > ah_iqCalData . calData = & iq_cal_multi_sample ;
ah - > ah_adcGainCalData . calData =
2008-10-29 10:16:30 +05:30
& adc_gain_cal_multi_sample ;
2009-02-09 13:27:12 +05:30
ah - > ah_adcDcCalData . calData =
2008-10-29 10:16:30 +05:30
& adc_dc_cal_multi_sample ;
2009-02-09 13:27:12 +05:30
ah - > ah_adcDcCalInitData . calData =
2008-10-29 10:16:30 +05:30
& adc_init_dc_cal ;
}
2009-02-09 13:27:12 +05:30
ah - > ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL ;
2008-10-29 10:16:30 +05:30
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9160 ( ah ) ) {
ah - > ah_config . enable_ani = 1 ;
2009-02-09 13:27:12 +05:30
ah - > ah_ani_function = ( ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
2008-10-29 10:16:30 +05:30
ATH9K_ANI_FIRSTEP_LEVEL ) ;
} else {
2009-02-09 13:27:12 +05:30
ah - > ah_ani_function = ATH9K_ANI_ALL ;
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
ah - > ah_ani_function & = ~ ATH9K_ANI_NOISE_IMMUNITY_LEVEL ;
2008-10-29 10:16:30 +05:30
}
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
DPRINTF ( sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" This Mac Chip Rev 0x%02x.%x is \n " ,
2009-02-09 13:27:06 +05:30
ah - > hw_version . macVersion , ah - > hw_version . macRev ) ;
2008-08-04 00:16:41 -07:00
2008-12-08 19:43:48 +05:30
if ( AR_SREV_9285_12_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModes , ar9285Modes_9285_1_2 ,
2008-12-08 19:43:48 +05:30
ARRAY_SIZE ( ar9285Modes_9285_1_2 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniCommon , ar9285Common_9285_1_2 ,
2008-12-08 19:43:48 +05:30
ARRAY_SIZE ( ar9285Common_9285_1_2 ) , 2 ) ;
if ( ah - > ah_config . pcie_clock_req ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniPcieSerdes ,
2008-12-08 19:43:48 +05:30
ar9285PciePhy_clkreq_off_L1_9285_1_2 ,
ARRAY_SIZE ( ar9285PciePhy_clkreq_off_L1_9285_1_2 ) , 2 ) ;
} else {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniPcieSerdes ,
2008-12-08 19:43:48 +05:30
ar9285PciePhy_clkreq_always_on_L1_9285_1_2 ,
ARRAY_SIZE ( ar9285PciePhy_clkreq_always_on_L1_9285_1_2 ) ,
2 ) ;
}
} else if ( AR_SREV_9285_10_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModes , ar9285Modes_9285 ,
2008-12-08 19:43:48 +05:30
ARRAY_SIZE ( ar9285Modes_9285 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniCommon , ar9285Common_9285 ,
2008-12-08 19:43:48 +05:30
ARRAY_SIZE ( ar9285Common_9285 ) , 2 ) ;
if ( ah - > ah_config . pcie_clock_req ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniPcieSerdes ,
2008-12-08 19:43:48 +05:30
ar9285PciePhy_clkreq_off_L1_9285 ,
ARRAY_SIZE ( ar9285PciePhy_clkreq_off_L1_9285 ) , 2 ) ;
} else {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniPcieSerdes ,
2008-12-08 19:43:48 +05:30
ar9285PciePhy_clkreq_always_on_L1_9285 ,
ARRAY_SIZE ( ar9285PciePhy_clkreq_always_on_L1_9285 ) , 2 ) ;
}
} else if ( AR_SREV_9280_20_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModes , ar9280Modes_9280_2 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar9280Modes_9280_2 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniCommon , ar9280Common_9280_2 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar9280Common_9280_2 ) , 2 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ah - > ah_config . pcie_clock_req ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniPcieSerdes ,
2008-10-29 10:16:30 +05:30
ar9280PciePhy_clkreq_off_L1_9280 ,
ARRAY_SIZE ( ar9280PciePhy_clkreq_off_L1_9280 ) , 2 ) ;
} else {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniPcieSerdes ,
2008-10-29 10:16:30 +05:30
ar9280PciePhy_clkreq_always_on_L1_9280 ,
ARRAY_SIZE ( ar9280PciePhy_clkreq_always_on_L1_9280 ) , 2 ) ;
}
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModesAdditional ,
2008-10-29 10:16:30 +05:30
ar9280Modes_fast_clock_9280_2 ,
ARRAY_SIZE ( ar9280Modes_fast_clock_9280_2 ) , 3 ) ;
} else if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModes , ar9280Modes_9280 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar9280Modes_9280 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniCommon , ar9280Common_9280 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar9280Common_9280 ) , 2 ) ;
} else if ( AR_SREV_9160_10_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModes , ar5416Modes_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Modes_9160 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniCommon , ar5416Common_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Common_9160 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank0 , ar5416Bank0_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank0_9160 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBB_RfGain , ar5416BB_RfGain_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416BB_RfGain_9160 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank1 , ar5416Bank1_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank1_9160 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank2 , ar5416Bank2_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank2_9160 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank3 , ar5416Bank3_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank3_9160 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank6 , ar5416Bank6_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6_9160 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank6TPC , ar5416Bank6TPC_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6TPC_9160 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank7 , ar5416Bank7_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank7_9160 ) , 2 ) ;
if ( AR_SREV_9160_11 ( ah ) ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniAddac ,
2008-10-29 10:16:30 +05:30
ar5416Addac_91601_1 ,
ARRAY_SIZE ( ar5416Addac_91601_1 ) , 2 ) ;
} else {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniAddac , ar5416Addac_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Addac_9160 ) , 2 ) ;
}
} else if ( AR_SREV_9100_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModes , ar5416Modes_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Modes_9100 ) , 6 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniCommon , ar5416Common_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Common_9100 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank0 , ar5416Bank0_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank0_9100 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBB_RfGain , ar5416BB_RfGain_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416BB_RfGain_9100 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank1 , ar5416Bank1_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank1_9100 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank2 , ar5416Bank2_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank2_9100 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank3 , ar5416Bank3_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank3_9100 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank6 , ar5416Bank6_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6_9100 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank6TPC , ar5416Bank6TPC_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6TPC_9100 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank7 , ar5416Bank7_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank7_9100 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniAddac , ar5416Addac_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Addac_9100 ) , 2 ) ;
} else {
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniModes , ar5416Modes ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Modes ) , 6 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniCommon , ar5416Common ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Common ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank0 , ar5416Bank0 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank0 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBB_RfGain , ar5416BB_RfGain ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416BB_RfGain ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank1 , ar5416Bank1 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank1 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank2 , ar5416Bank2 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank2 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank3 , ar5416Bank3 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank3 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank6 , ar5416Bank6 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6 ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank6TPC , ar5416Bank6TPC ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6TPC ) , 3 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniBank7 , ar5416Bank7 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank7 ) , 2 ) ;
2009-02-09 13:27:12 +05:30
INIT_INI_ARRAY ( & ah - > ah_iniAddac , ar5416Addac ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Addac ) , 2 ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
if ( ah - > ah_isPciExpress )
ath9k_hw_configpcipowersave ( ah , 0 ) ;
else
ath9k_hw_disablepcie ( ah ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
ecode = ath9k_hw_post_attach ( ah ) ;
if ( ecode ! = 0 )
goto bad ;
2008-08-04 00:16:41 -07:00
2008-11-13 17:58:41 +05:30
/* rxgain table */
2008-12-08 19:43:48 +05:30
if ( AR_SREV_9280_20 ( ah ) )
2008-11-13 17:58:41 +05:30
ath9k_hw_init_rxgain_ini ( ah ) ;
/* txgain table */
2008-12-08 19:43:48 +05:30
if ( AR_SREV_9280_20 ( ah ) )
2008-11-13 17:58:41 +05:30
ath9k_hw_init_txgain_ini ( ah ) ;
2009-02-09 13:27:06 +05:30
if ( ah - > hw_version . devid = = AR9280_DEVID_PCI ) {
2009-02-09 13:27:12 +05:30
for ( i = 0 ; i < ah - > ah_iniModes . ia_rows ; i + + ) {
u32 reg = INI_RA ( & ah - > ah_iniModes , i , 0 ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
for ( j = 1 ; j < ah - > ah_iniModes . ia_columns ; j + + ) {
u32 val = INI_RA ( & ah - > ah_iniModes , i , j ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
INI_RA ( & ah - > ah_iniModes , i , j ) =
2008-12-08 19:43:48 +05:30
ath9k_hw_ini_fixup ( ah ,
2009-02-09 13:27:12 +05:30
& ah - > ah_eeprom . def ,
2008-10-29 10:16:30 +05:30
reg , val ) ;
}
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
}
2008-12-07 21:43:10 +05:30
2008-10-29 10:16:30 +05:30
if ( ! ath9k_hw_fill_cap_info ( ah ) ) {
2009-02-09 13:27:12 +05:30
DPRINTF ( sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" failed ath9k_hw_fill_cap_info \n " ) ;
2008-10-29 10:16:30 +05:30
ecode = - EINVAL ;
goto bad ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
ecode = ath9k_hw_init_macaddr ( ah ) ;
if ( ecode ! = 0 ) {
2009-02-09 13:27:12 +05:30
DPRINTF ( sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" failed initializing mac address \n " ) ;
2008-10-29 10:16:30 +05:30
goto bad ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9285 ( ah ) )
ah - > ah_txTrigLevel = ( AR_FTRIG_256B > > AR_FTRIG_S ) ;
else
ah - > ah_txTrigLevel = ( AR_FTRIG_512B > > AR_FTRIG_S ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
ath9k_init_nfcal_hist_buffer ( ah ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return ah ;
bad :
2009-02-09 13:27:12 +05:30
if ( ah )
ath9k_hw_detach ( ah ) ;
2008-10-29 10:16:30 +05:30
if ( status )
* status = ecode ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return NULL ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_init_bb ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 synthDelay ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
synthDelay = REG_READ ( ah , AR_PHY_RX_DELAY ) & AR_PHY_RX_DELAY_DELAY ;
2008-11-18 09:09:54 +05:30
if ( IS_CHAN_B ( chan ) )
2008-10-29 10:16:30 +05:30
synthDelay = ( 4 * synthDelay ) / 22 ;
else
synthDelay / = 10 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_EN ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
udelay ( synthDelay + BASE_ACTIVATE_DELAY ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_init_qos ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_MIC_QOS_CONTROL , 0x100aa ) ;
REG_WRITE ( ah , AR_MIC_QOS_SELECT , 0x3210 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_QOS_NO_ACK ,
SM ( 2 , AR_QOS_NO_ACK_TWO_BIT ) |
SM ( 5 , AR_QOS_NO_ACK_BIT_OFF ) |
SM ( 0 , AR_QOS_NO_ACK_BYTE_OFF ) ) ;
REG_WRITE ( ah , AR_TXOP_X , AR_TXOP_X_VAL ) ;
REG_WRITE ( ah , AR_TXOP_0_3 , 0xFFFFFFFF ) ;
REG_WRITE ( ah , AR_TXOP_4_7 , 0xFFFFFFFF ) ;
REG_WRITE ( ah , AR_TXOP_8_11 , 0xFFFFFFFF ) ;
REG_WRITE ( ah , AR_TXOP_12_15 , 0xFFFFFFFF ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_init_pll ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 pll ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9100 ( ah ) ) {
if ( chan & & IS_CHAN_5GHZ ( chan ) )
pll = 0x1450 ;
2008-08-04 00:16:41 -07:00
else
2008-10-29 10:16:30 +05:30
pll = 0x1458 ;
} else {
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
pll = SM ( 0x5 , AR_RTC_9160_PLL_REFDIV ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( chan & & IS_CHAN_HALF_RATE ( chan ) )
pll | = SM ( 0x1 , AR_RTC_9160_PLL_CLKSEL ) ;
else if ( chan & & IS_CHAN_QUARTER_RATE ( chan ) )
pll | = SM ( 0x2 , AR_RTC_9160_PLL_CLKSEL ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( chan & & IS_CHAN_5GHZ ( chan ) ) {
pll | = SM ( 0x28 , AR_RTC_9160_PLL_DIV ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9280_20 ( ah ) ) {
if ( ( ( chan - > channel % 20 ) = = 0 )
| | ( ( chan - > channel % 10 ) = = 0 ) )
pll = 0x2850 ;
else
pll = 0x142c ;
}
} else {
pll | = SM ( 0x2c , AR_RTC_9160_PLL_DIV ) ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
} else if ( AR_SREV_9160_10_OR_LATER ( ah ) ) {
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
pll = SM ( 0x5 , AR_RTC_9160_PLL_REFDIV ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( chan & & IS_CHAN_HALF_RATE ( chan ) )
pll | = SM ( 0x1 , AR_RTC_9160_PLL_CLKSEL ) ;
else if ( chan & & IS_CHAN_QUARTER_RATE ( chan ) )
pll | = SM ( 0x2 , AR_RTC_9160_PLL_CLKSEL ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( chan & & IS_CHAN_5GHZ ( chan ) )
pll | = SM ( 0x50 , AR_RTC_9160_PLL_DIV ) ;
else
pll | = SM ( 0x58 , AR_RTC_9160_PLL_DIV ) ;
} else {
pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( chan & & IS_CHAN_HALF_RATE ( chan ) )
pll | = SM ( 0x1 , AR_RTC_PLL_CLKSEL ) ;
else if ( chan & & IS_CHAN_QUARTER_RATE ( chan ) )
pll | = SM ( 0x2 , AR_RTC_PLL_CLKSEL ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( chan & & IS_CHAN_5GHZ ( chan ) )
pll | = SM ( 0xa , AR_RTC_PLL_DIV ) ;
else
pll | = SM ( 0xb , AR_RTC_PLL_DIV ) ;
}
}
2009-01-14 20:17:09 +01:00
REG_WRITE ( ah , AR_RTC_PLL_CONTROL , pll ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
udelay ( RTC_PLL_SETTLE_DELAY ) ;
REG_WRITE ( ah , AR_RTC_SLEEP_CLK , AR_RTC_FORCE_DERIVED_CLK ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_init_chain_masks ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
int rx_chainmask , tx_chainmask ;
2009-02-09 13:27:12 +05:30
rx_chainmask = ah - > ah_rxchainmask ;
tx_chainmask = ah - > ah_txchainmask ;
2008-08-04 00:16:41 -07:00
switch ( rx_chainmask ) {
case 0x5 :
REG_SET_BIT ( ah , AR_PHY_ANALOG_SWAP ,
AR_PHY_SWAP_ALT_CHAIN ) ;
case 0x3 :
2009-02-09 13:27:06 +05:30
if ( ( ( ah ) - > hw_version . macVersion < = AR_SREV_VERSION_9160 ) ) {
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_PHY_RX_CHAINMASK , 0x7 ) ;
REG_WRITE ( ah , AR_PHY_CAL_CHAINMASK , 0x7 ) ;
break ;
}
case 0x1 :
case 0x2 :
case 0x7 :
REG_WRITE ( ah , AR_PHY_RX_CHAINMASK , rx_chainmask ) ;
REG_WRITE ( ah , AR_PHY_CAL_CHAINMASK , rx_chainmask ) ;
break ;
default :
break ;
}
REG_WRITE ( ah , AR_SELFGEN_MASK , tx_chainmask ) ;
if ( tx_chainmask = = 0x5 ) {
REG_SET_BIT ( ah , AR_PHY_ANALOG_SWAP ,
AR_PHY_SWAP_ALT_CHAIN ) ;
}
if ( AR_SREV_9100 ( ah ) )
REG_WRITE ( ah , AR_PHY_ANALOG_SWAP ,
REG_READ ( ah , AR_PHY_ANALOG_SWAP ) | 0x00000001 ) ;
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_init_interrupt_masks ( struct ath_hw * ah ,
2008-12-01 13:38:55 -08:00
enum nl80211_iftype opmode )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
ah - > ah_maskReg = AR_IMR_TXERR |
2008-10-29 10:16:30 +05:30
AR_IMR_TXURN |
AR_IMR_RXERR |
AR_IMR_RXORN |
AR_IMR_BCNMISC ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
if ( ah - > ah_intrMitigation )
ah - > ah_maskReg | = AR_IMR_RXINTM | AR_IMR_RXMINTR ;
2008-08-04 00:16:41 -07:00
else
2009-02-09 13:27:12 +05:30
ah - > ah_maskReg | = AR_IMR_RXOK ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
ah - > ah_maskReg | = AR_IMR_TXOK ;
2008-08-04 00:16:41 -07:00
2008-12-01 13:38:55 -08:00
if ( opmode = = NL80211_IFTYPE_AP )
2009-02-09 13:27:12 +05:30
ah - > ah_maskReg | = AR_IMR_MIB ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
REG_WRITE ( ah , AR_IMR , ah - > ah_maskReg ) ;
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_IMR_S2 , REG_READ ( ah , AR_IMR_S2 ) | AR_IMR_S2_GTT ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ! AR_SREV_9100 ( ah ) ) {
REG_WRITE ( ah , AR_INTR_SYNC_CAUSE , 0xFFFFFFFF ) ;
REG_WRITE ( ah , AR_INTR_SYNC_ENABLE , AR_INTR_SYNC_DEFAULT ) ;
REG_WRITE ( ah , AR_INTR_SYNC_MASK , 0 ) ;
}
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_set_ack_timeout ( struct ath_hw * ah , u32 us )
2008-08-04 00:16:41 -07:00
{
if ( us > ath9k_hw_mac_to_usec ( ah , MS ( 0xffffffff , AR_TIME_OUT_ACK ) ) ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET , " bad ack timeout %u \n " , us ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_acktimeout = ( u32 ) - 1 ;
2008-08-04 00:16:41 -07:00
return false ;
} else {
REG_RMW_FIELD ( ah , AR_TIME_OUT ,
AR_TIME_OUT_ACK , ath9k_hw_mac_to_clks ( ah , us ) ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_acktimeout = us ;
2008-08-04 00:16:41 -07:00
return true ;
}
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_set_cts_timeout ( struct ath_hw * ah , u32 us )
2008-08-04 00:16:41 -07:00
{
if ( us > ath9k_hw_mac_to_usec ( ah , MS ( 0xffffffff , AR_TIME_OUT_CTS ) ) ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET , " bad cts timeout %u \n " , us ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_ctstimeout = ( u32 ) - 1 ;
2008-08-04 00:16:41 -07:00
return false ;
} else {
REG_RMW_FIELD ( ah , AR_TIME_OUT ,
AR_TIME_OUT_CTS , ath9k_hw_mac_to_clks ( ah , us ) ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_ctstimeout = us ;
2008-08-04 00:16:41 -07:00
return true ;
}
}
2008-10-29 10:16:30 +05:30
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_set_global_txtimeout ( struct ath_hw * ah , u32 tu )
2008-08-04 00:16:41 -07:00
{
if ( tu > 0xFFFF ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_XMIT ,
2008-11-28 22:18:05 +05:30
" bad global tx timeout %u \n " , tu ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_globaltxtimeout = ( u32 ) - 1 ;
2008-08-04 00:16:41 -07:00
return false ;
} else {
REG_RMW_FIELD ( ah , AR_GTXTO , AR_GTXTO_TIMEOUT_LIMIT , tu ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_globaltxtimeout = tu ;
2008-08-04 00:16:41 -07:00
return true ;
}
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_init_user_settings ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET , " ah->ah_miscMode 0x%x \n " ,
ah - > ah_miscMode ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
if ( ah - > ah_miscMode ! = 0 )
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PCU_MISC ,
2009-02-09 13:27:12 +05:30
REG_READ ( ah , AR_PCU_MISC ) | ah - > ah_miscMode ) ;
if ( ah - > ah_slottime ! = ( u32 ) - 1 )
ath9k_hw_setslottime ( ah , ah - > ah_slottime ) ;
if ( ah - > ah_acktimeout ! = ( u32 ) - 1 )
ath9k_hw_set_ack_timeout ( ah , ah - > ah_acktimeout ) ;
if ( ah - > ah_ctstimeout ! = ( u32 ) - 1 )
ath9k_hw_set_cts_timeout ( ah , ah - > ah_ctstimeout ) ;
if ( ah - > ah_globaltxtimeout ! = ( u32 ) - 1 )
ath9k_hw_set_global_txtimeout ( ah , ah - > ah_globaltxtimeout ) ;
2008-10-29 10:16:30 +05:30
}
const char * ath9k_hw_probe ( u16 vendorid , u16 devid )
{
return vendorid = = ATHEROS_VENDOR_ID ?
ath9k_hw_devname ( devid ) : NULL ;
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_detach ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
if ( ! AR_SREV_9100 ( ah ) )
ath9k_hw_ani_detach ( ah ) ;
ath9k_hw_rfdetach ( ah ) ;
ath9k_hw_setpower ( ah , ATH9K_PM_FULL_SLEEP ) ;
kfree ( ah ) ;
}
2009-02-09 13:27:12 +05:30
struct ath_hw * ath9k_hw_attach ( u16 devid , struct ath_softc * sc , int * error )
2008-10-29 10:16:30 +05:30
{
2009-02-09 13:27:12 +05:30
struct ath_hw * ah = NULL ;
2008-10-29 10:16:30 +05:30
switch ( devid ) {
case AR5416_DEVID_PCI :
case AR5416_DEVID_PCIE :
2009-01-14 20:17:12 +01:00
case AR5416_AR9100_DEVID :
2008-10-29 10:16:30 +05:30
case AR9160_DEVID_PCI :
case AR9280_DEVID_PCI :
case AR9280_DEVID_PCIE :
2008-12-08 19:43:48 +05:30
case AR9285_DEVID_PCIE :
2009-02-09 13:27:12 +05:30
ah = ath9k_hw_do_attach ( devid , sc , error ) ;
2008-10-29 10:16:30 +05:30
break ;
default :
* error = - ENXIO ;
break ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
return ah ;
}
/*******/
/* INI */
/*******/
2009-02-09 13:27:12 +05:30
static void ath9k_hw_override_ini ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan )
{
2008-12-08 19:43:50 +05:30
/*
* Set the RX_ABORT and RX_DIS and clear if off only after
* RXE is set for MAC . This prevents frames with corrupted
* descriptor status .
*/
REG_SET_BIT ( ah , AR_DIAG_SW , ( AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT ) ) ;
2008-10-29 10:16:30 +05:30
if ( ! AR_SREV_5416_V20_OR_LATER ( ah ) | |
AR_SREV_9280_10_OR_LATER ( ah ) )
return ;
REG_WRITE ( ah , 0x9800 + ( 651 < < 2 ) , 0x11 ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static u32 ath9k_hw_def_ini_fixup ( struct ath_hw * ah ,
2008-12-08 19:43:48 +05:30
struct ar5416_eeprom_def * pEepData ,
2008-10-29 10:16:30 +05:30
u32 reg , u32 value )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
struct base_eep_header * pBase = & ( pEepData - > baseEepHeader ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:06 +05:30
switch ( ah - > hw_version . devid ) {
2008-10-29 10:16:30 +05:30
case AR9280_DEVID_PCI :
if ( reg = = 0x7894 ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_ANY ,
" ini VAL: %x EEPROM: %x \n " , value ,
( pBase - > version & 0xff ) ) ;
if ( ( pBase - > version & 0xff ) > 0x0a ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_ANY ,
" PWDCLKIND: %d \n " ,
pBase - > pwdclkind ) ;
value & = ~ AR_AN_TOP2_PWDCLKIND ;
value | = AR_AN_TOP2_PWDCLKIND &
( pBase - > pwdclkind < < AR_AN_TOP2_PWDCLKIND_S ) ;
} else {
DPRINTF ( ah - > ah_sc , ATH_DBG_ANY ,
" PWDCLKIND Earlier Rev \n " ) ;
}
DPRINTF ( ah - > ah_sc , ATH_DBG_ANY ,
" final ini VAL: %x \n " , value ) ;
}
break ;
}
return value ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static u32 ath9k_hw_ini_fixup ( struct ath_hw * ah ,
2008-12-08 19:43:48 +05:30
struct ar5416_eeprom_def * pEepData ,
u32 reg , u32 value )
{
2009-02-09 13:27:12 +05:30
if ( ah - > ah_eep_map = = EEP_MAP_4KBITS )
2008-12-08 19:43:48 +05:30
return value ;
else
return ath9k_hw_def_ini_fixup ( ah , pEepData , reg , value ) ;
}
2009-02-09 13:27:12 +05:30
static int ath9k_hw_process_ini ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan ,
enum ath9k_ht_macmode macmode )
2008-08-04 00:16:41 -07:00
{
int i , regWrites = 0 ;
2009-01-22 15:16:48 -08:00
struct ieee80211_channel * channel = chan - > chan ;
2008-08-04 00:16:41 -07:00
u32 modesIndex , freqIndex ;
int status ;
switch ( chan - > chanmode ) {
case CHANNEL_A :
case CHANNEL_A_HT20 :
modesIndex = 1 ;
freqIndex = 1 ;
break ;
case CHANNEL_A_HT40PLUS :
case CHANNEL_A_HT40MINUS :
modesIndex = 2 ;
freqIndex = 1 ;
break ;
case CHANNEL_G :
case CHANNEL_G_HT20 :
case CHANNEL_B :
modesIndex = 4 ;
freqIndex = 2 ;
break ;
case CHANNEL_G_HT40PLUS :
case CHANNEL_G_HT40MINUS :
modesIndex = 3 ;
freqIndex = 2 ;
break ;
default :
return - EINVAL ;
}
REG_WRITE ( ah , AR_PHY ( 0 ) , 0x00000007 ) ;
REG_WRITE ( ah , AR_PHY_ADC_SERIAL_CTL , AR_PHY_SEL_EXTERNAL_RADIO ) ;
ath9k_hw_set_addac ( ah , chan ) ;
if ( AR_SREV_5416_V22_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
REG_WRITE_ARRAY ( & ah - > ah_iniAddac , 1 , regWrites ) ;
2008-08-04 00:16:41 -07:00
} else {
struct ar5416IniArray temp ;
u32 addacSize =
2009-02-09 13:27:12 +05:30
sizeof ( u32 ) * ah - > ah_iniAddac . ia_rows *
ah - > ah_iniAddac . ia_columns ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
memcpy ( ah - > ah_addac5416_21 ,
ah - > ah_iniAddac . ia_array , addacSize ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
( ah - > ah_addac5416_21 ) [ 31 * ah - > ah_iniAddac . ia_columns + 1 ] = 0 ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
temp . ia_array = ah - > ah_addac5416_21 ;
temp . ia_columns = ah - > ah_iniAddac . ia_columns ;
temp . ia_rows = ah - > ah_iniAddac . ia_rows ;
2008-08-04 00:16:41 -07:00
REG_WRITE_ARRAY ( & temp , 1 , regWrites ) ;
}
2008-10-29 10:16:30 +05:30
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_PHY_ADC_SERIAL_CTL , AR_PHY_SEL_INTERNAL_ADDAC ) ;
2009-02-09 13:27:12 +05:30
for ( i = 0 ; i < ah - > ah_iniModes . ia_rows ; i + + ) {
u32 reg = INI_RA ( & ah - > ah_iniModes , i , 0 ) ;
u32 val = INI_RA ( & ah - > ah_iniModes , i , modesIndex ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , reg , val ) ;
if ( reg > = 0x7800 & & reg < 0x78a0
2008-08-07 10:52:38 +05:30
& & ah - > ah_config . analog_shiftreg ) {
2008-08-04 00:16:41 -07:00
udelay ( 100 ) ;
}
DO_DELAY ( regWrites ) ;
}
2008-12-08 19:43:48 +05:30
if ( AR_SREV_9280 ( ah ) )
2009-02-09 13:27:12 +05:30
REG_WRITE_ARRAY ( & ah - > ah_iniModesRxGain , modesIndex , regWrites ) ;
2008-11-13 17:58:41 +05:30
2008-12-08 19:43:48 +05:30
if ( AR_SREV_9280 ( ah ) )
2009-02-09 13:27:12 +05:30
REG_WRITE_ARRAY ( & ah - > ah_iniModesTxGain , modesIndex , regWrites ) ;
2008-11-13 17:58:41 +05:30
2009-02-09 13:27:12 +05:30
for ( i = 0 ; i < ah - > ah_iniCommon . ia_rows ; i + + ) {
u32 reg = INI_RA ( & ah - > ah_iniCommon , i , 0 ) ;
u32 val = INI_RA ( & ah - > ah_iniCommon , i , 1 ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , reg , val ) ;
if ( reg > = 0x7800 & & reg < 0x78a0
2008-08-07 10:52:38 +05:30
& & ah - > ah_config . analog_shiftreg ) {
2008-08-04 00:16:41 -07:00
udelay ( 100 ) ;
}
DO_DELAY ( regWrites ) ;
}
ath9k_hw_write_regs ( ah , modesIndex , freqIndex , regWrites ) ;
if ( AR_SREV_9280_20 ( ah ) & & IS_CHAN_A_5MHZ_SPACED ( chan ) ) {
2009-02-09 13:27:12 +05:30
REG_WRITE_ARRAY ( & ah - > ah_iniModesAdditional , modesIndex ,
2008-08-04 00:16:41 -07:00
regWrites ) ;
}
ath9k_hw_override_ini ( ah , chan ) ;
ath9k_hw_set_regs ( ah , chan , macmode ) ;
ath9k_hw_init_chain_masks ( ah ) ;
2008-10-29 10:16:30 +05:30
status = ath9k_hw_set_txpower ( ah , chan ,
2008-08-04 00:16:41 -07:00
ath9k_regd_get_ctl ( ah , chan ) ,
2009-01-22 15:16:48 -08:00
channel - > max_antenna_gain * 2 ,
channel - > max_power * 2 ,
2008-08-04 00:16:41 -07:00
min ( ( u32 ) MAX_RATE_POWER ,
2009-02-09 13:27:08 +05:30
( u32 ) ah - > regulatory . power_limit ) ) ;
2008-08-04 00:16:41 -07:00
if ( status ! = 0 ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_POWER_MGMT ,
2008-11-28 22:18:05 +05:30
" error init'ing transmit power \n " ) ;
2008-08-04 00:16:41 -07:00
return - EIO ;
}
if ( ! ath9k_hw_set_rf_regs ( ah , chan , freqIndex ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_REG_IO ,
2008-11-28 22:18:05 +05:30
" ar5416SetRfRegs failed \n " ) ;
2008-08-04 00:16:41 -07:00
return - EIO ;
}
return 0 ;
}
2008-10-29 10:16:30 +05:30
/****************************************/
/* Reset and Channel Switching Routines */
/****************************************/
2009-02-09 13:27:12 +05:30
static void ath9k_hw_set_rfmode ( struct ath_hw * ah , struct ath9k_channel * chan )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 rfMode = 0 ;
if ( chan = = NULL )
return ;
rfMode | = ( IS_CHAN_B ( chan ) | | IS_CHAN_G ( chan ) )
? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM ;
if ( ! AR_SREV_9280_10_OR_LATER ( ah ) )
rfMode | = ( IS_CHAN_5GHZ ( chan ) ) ?
AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ ;
if ( AR_SREV_9280_20 ( ah ) & & IS_CHAN_A_5MHZ_SPACED ( chan ) )
rfMode | = ( AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE ) ;
REG_WRITE ( ah , AR_PHY_MODE , rfMode ) ;
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_mark_phy_inactive ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
REG_WRITE ( ah , AR_PHY_ACTIVE , AR_PHY_ACTIVE_DIS ) ;
}
2009-02-09 13:27:12 +05:30
static inline void ath9k_hw_set_dma ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
u32 regval ;
regval = REG_READ ( ah , AR_AHB_MODE ) ;
REG_WRITE ( ah , AR_AHB_MODE , regval | AR_AHB_PREFETCH_RD_EN ) ;
regval = REG_READ ( ah , AR_TXCFG ) & ~ AR_TXCFG_DMASZ_MASK ;
REG_WRITE ( ah , AR_TXCFG , regval | AR_TXCFG_DMASZ_128B ) ;
REG_RMW_FIELD ( ah , AR_TXCFG , AR_FTRIG , ah - > ah_txTrigLevel ) ;
regval = REG_READ ( ah , AR_RXCFG ) & ~ AR_RXCFG_DMASZ_MASK ;
REG_WRITE ( ah , AR_RXCFG , regval | AR_RXCFG_DMASZ_128B ) ;
REG_WRITE ( ah , AR_RXFIFO_CFG , 0x200 ) ;
if ( AR_SREV_9285 ( ah ) ) {
REG_WRITE ( ah , AR_PCU_TXBUF_CTRL ,
AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE ) ;
} else {
REG_WRITE ( ah , AR_PCU_TXBUF_CTRL ,
AR_PCU_TXBUF_CTRL_USABLE_SIZE ) ;
}
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_set_operating_mode ( struct ath_hw * ah , int opmode )
2008-10-29 10:16:30 +05:30
{
u32 val ;
val = REG_READ ( ah , AR_STA_ID1 ) ;
val & = ~ ( AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC ) ;
switch ( opmode ) {
2008-12-01 13:38:55 -08:00
case NL80211_IFTYPE_AP :
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_STA_ID1 , val | AR_STA_ID1_STA_AP
| AR_STA_ID1_KSRCH_MODE ) ;
REG_CLR_BIT ( ah , AR_CFG , AR_CFG_AP_ADHOC_INDICATION ) ;
2008-08-04 00:16:41 -07:00
break ;
2008-12-01 13:38:55 -08:00
case NL80211_IFTYPE_ADHOC :
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_STA_ID1 , val | AR_STA_ID1_ADHOC
| AR_STA_ID1_KSRCH_MODE ) ;
REG_SET_BIT ( ah , AR_CFG , AR_CFG_AP_ADHOC_INDICATION ) ;
2008-08-04 00:16:41 -07:00
break ;
2008-12-01 13:38:55 -08:00
case NL80211_IFTYPE_STATION :
case NL80211_IFTYPE_MONITOR :
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_STA_ID1 , val | AR_STA_ID1_KSRCH_MODE ) ;
2008-08-04 00:16:41 -07:00
break ;
2008-10-29 10:16:30 +05:30
}
}
2009-02-09 13:27:12 +05:30
static inline void ath9k_hw_get_delta_slope_vals ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
u32 coef_scaled ,
u32 * coef_mantissa ,
u32 * coef_exponent )
{
u32 coef_exp , coef_man ;
for ( coef_exp = 31 ; coef_exp > 0 ; coef_exp - - )
if ( ( coef_scaled > > coef_exp ) & 0x1 )
break ;
coef_exp = 14 - ( coef_exp - COEF_SCALE_S ) ;
coef_man = coef_scaled + ( 1 < < ( COEF_SCALE_S - coef_exp - 1 ) ) ;
* coef_mantissa = coef_man > > ( COEF_SCALE_S - coef_exp ) ;
* coef_exponent = coef_exp - 16 ;
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_set_delta_slope ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan )
{
u32 coef_scaled , ds_coef_exp , ds_coef_man ;
u32 clockMhzScaled = 0x64000000 ;
struct chan_centers centers ;
if ( IS_CHAN_HALF_RATE ( chan ) )
clockMhzScaled = clockMhzScaled > > 1 ;
else if ( IS_CHAN_QUARTER_RATE ( chan ) )
clockMhzScaled = clockMhzScaled > > 2 ;
ath9k_hw_get_channel_centers ( ah , chan , & centers ) ;
coef_scaled = clockMhzScaled / centers . synth_center ;
ath9k_hw_get_delta_slope_vals ( ah , coef_scaled , & ds_coef_man ,
& ds_coef_exp ) ;
REG_RMW_FIELD ( ah , AR_PHY_TIMING3 ,
AR_PHY_TIMING3_DSC_MAN , ds_coef_man ) ;
REG_RMW_FIELD ( ah , AR_PHY_TIMING3 ,
AR_PHY_TIMING3_DSC_EXP , ds_coef_exp ) ;
coef_scaled = ( 9 * coef_scaled ) / 10 ;
ath9k_hw_get_delta_slope_vals ( ah , coef_scaled , & ds_coef_man ,
& ds_coef_exp ) ;
REG_RMW_FIELD ( ah , AR_PHY_HALFGI ,
AR_PHY_HALFGI_DSC_MAN , ds_coef_man ) ;
REG_RMW_FIELD ( ah , AR_PHY_HALFGI ,
AR_PHY_HALFGI_DSC_EXP , ds_coef_exp ) ;
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_set_reset ( struct ath_hw * ah , int type )
2008-10-29 10:16:30 +05:30
{
u32 rst_flags ;
u32 tmpReg ;
REG_WRITE ( ah , AR_RTC_FORCE_WAKE , AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT ) ;
if ( AR_SREV_9100 ( ah ) ) {
rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET ;
} else {
tmpReg = REG_READ ( ah , AR_INTR_SYNC_CAUSE ) ;
if ( tmpReg &
( AR_INTR_SYNC_LOCAL_TIMEOUT |
AR_INTR_SYNC_RADM_CPL_TIMEOUT ) ) {
REG_WRITE ( ah , AR_INTR_SYNC_ENABLE , 0 ) ;
REG_WRITE ( ah , AR_RC , AR_RC_AHB | AR_RC_HOSTIF ) ;
} else {
REG_WRITE ( ah , AR_RC , AR_RC_AHB ) ;
}
rst_flags = AR_RTC_RC_MAC_WARM ;
if ( type = = ATH9K_RESET_COLD )
rst_flags | = AR_RTC_RC_MAC_COLD ;
}
2009-01-14 20:17:09 +01:00
REG_WRITE ( ah , AR_RTC_RC , rst_flags ) ;
2008-10-29 10:16:30 +05:30
udelay ( 50 ) ;
2009-01-14 20:17:09 +01:00
REG_WRITE ( ah , AR_RTC_RC , 0 ) ;
if ( ! ath9k_hw_wait ( ah , AR_RTC_RC , AR_RTC_RC_M , 0 ) ) {
2008-10-29 10:16:30 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" RTC stuck in MAC reset \n " ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
if ( ! AR_SREV_9100 ( ah ) )
REG_WRITE ( ah , AR_RC , 0 ) ;
ath9k_hw_init_pll ( ah , NULL ) ;
if ( AR_SREV_9100 ( ah ) )
udelay ( 50 ) ;
return true ;
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_set_reset_power_on ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
REG_WRITE ( ah , AR_RTC_FORCE_WAKE , AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT ) ;
2009-01-14 20:17:09 +01:00
REG_WRITE ( ah , AR_RTC_RESET , 0 ) ;
REG_WRITE ( ah , AR_RTC_RESET , 1 ) ;
2008-10-29 10:16:30 +05:30
if ( ! ath9k_hw_wait ( ah ,
AR_RTC_STATUS ,
AR_RTC_STATUS_M ,
AR_RTC_STATUS_ON ) ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET , " RTC not waking up \n " ) ;
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
ath9k_hw_read_revisions ( ah ) ;
return ath9k_hw_set_reset ( ah , ATH9K_RESET_WARM ) ;
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_set_reset_reg ( struct ath_hw * ah , u32 type )
2008-10-29 10:16:30 +05:30
{
REG_WRITE ( ah , AR_RTC_FORCE_WAKE ,
AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT ) ;
switch ( type ) {
case ATH9K_RESET_POWER_ON :
return ath9k_hw_set_reset_power_on ( ah ) ;
break ;
case ATH9K_RESET_WARM :
case ATH9K_RESET_COLD :
return ath9k_hw_set_reset ( ah , type ) ;
break ;
default :
return false ;
}
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_set_regs ( struct ath_hw * ah , struct ath9k_channel * chan ,
2008-10-29 10:16:30 +05:30
enum ath9k_ht_macmode macmode )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 phymode ;
2008-12-08 19:43:48 +05:30
u32 enableDacFifo = 0 ;
2008-08-04 00:16:41 -07:00
2008-12-08 19:43:48 +05:30
if ( AR_SREV_9285_10_OR_LATER ( ah ) )
enableDacFifo = ( REG_READ ( ah , AR_PHY_TURBO ) &
AR_PHY_FC_ENABLE_DAC_FIFO ) ;
2008-10-29 10:16:30 +05:30
phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
2008-12-08 19:43:48 +05:30
| AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo ;
2008-10-29 10:16:30 +05:30
if ( IS_CHAN_HT40 ( chan ) ) {
phymode | = AR_PHY_FC_DYN2040_EN ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ( chan - > chanmode = = CHANNEL_A_HT40PLUS ) | |
( chan - > chanmode = = CHANNEL_G_HT40PLUS ) )
phymode | = AR_PHY_FC_DYN2040_PRI_CH ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
if ( ah - > ah_extprotspacing = = ATH9K_HT_EXTPROTSPACING_25 )
2008-10-29 10:16:30 +05:30
phymode | = AR_PHY_FC_DYN2040_EXT_CH ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PHY_TURBO , phymode ) ;
ath9k_hw_set11nmac2040 ( ah , macmode ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_GTXTO , 25 < < AR_GTXTO_TIMEOUT_LIMIT_S ) ;
REG_WRITE ( ah , AR_CST , 0xF < < AR_CST_TIMEOUT_LIMIT_S ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_chip_reset ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
if ( ! ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_WARM ) )
return false ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ! ath9k_hw_setpower ( ah , ATH9K_PM_AWAKE ) )
return false ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
ah - > ah_chipFullSleep = false ;
2008-10-29 10:16:30 +05:30
ath9k_hw_init_pll ( ah , chan ) ;
ath9k_hw_set_rfmode ( ah , chan ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return true ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_channel_change ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan ,
enum ath9k_ht_macmode macmode )
2008-08-04 00:16:41 -07:00
{
2009-01-22 15:16:48 -08:00
struct ieee80211_channel * channel = chan - > chan ;
2008-08-04 00:16:41 -07:00
u32 synthDelay , qnum ;
for ( qnum = 0 ; qnum < AR_NUM_QCU ; qnum + + ) {
if ( ath9k_hw_numtxpending ( ah , qnum ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_QUEUE ,
2008-11-28 22:18:05 +05:30
" Transmit frames pending on queue %d \n " , qnum ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
}
REG_WRITE ( ah , AR_PHY_RFBUS_REQ , AR_PHY_RFBUS_REQ_EN ) ;
if ( ! ath9k_hw_wait ( ah , AR_PHY_RFBUS_GRANT , AR_PHY_RFBUS_GRANT_EN ,
AR_PHY_RFBUS_GRANT_EN ) ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_REG_IO ,
" Could not kill baseband RX \n " ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
ath9k_hw_set_regs ( ah , chan , macmode ) ;
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
if ( ! ( ath9k_hw_ar9280_set_channel ( ah , chan ) ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_CHANNEL ,
2008-11-28 22:18:05 +05:30
" failed to set channel \n " ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
} else {
if ( ! ( ath9k_hw_set_channel ( ah , chan ) ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_CHANNEL ,
2008-11-28 22:18:05 +05:30
" failed to set channel \n " ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
}
2008-10-29 10:16:30 +05:30
if ( ath9k_hw_set_txpower ( ah , chan ,
2008-08-04 00:16:41 -07:00
ath9k_regd_get_ctl ( ah , chan ) ,
2009-01-22 15:16:48 -08:00
channel - > max_antenna_gain * 2 ,
channel - > max_power * 2 ,
2008-08-04 00:16:41 -07:00
min ( ( u32 ) MAX_RATE_POWER ,
2009-02-09 13:27:08 +05:30
( u32 ) ah - > regulatory . power_limit ) ) ! = 0 ) {
2008-08-04 00:16:41 -07:00
DPRINTF ( ah - > ah_sc , ATH_DBG_EEPROM ,
2008-11-28 22:18:05 +05:30
" error init'ing transmit power \n " ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
synthDelay = REG_READ ( ah , AR_PHY_RX_DELAY ) & AR_PHY_RX_DELAY_DELAY ;
2008-11-18 09:09:54 +05:30
if ( IS_CHAN_B ( chan ) )
2008-08-04 00:16:41 -07:00
synthDelay = ( 4 * synthDelay ) / 22 ;
else
synthDelay / = 10 ;
udelay ( synthDelay + BASE_ACTIVATE_DELAY ) ;
REG_WRITE ( ah , AR_PHY_RFBUS_REQ , 0 ) ;
2008-10-29 10:16:30 +05:30
if ( IS_CHAN_OFDM ( chan ) | | IS_CHAN_HT ( chan ) )
ath9k_hw_set_delta_slope ( ah , chan ) ;
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
ath9k_hw_9280_spur_mitigate ( ah , chan ) ;
else
ath9k_hw_spur_mitigate ( ah , chan ) ;
if ( ! chan - > oneTimeCalsDone )
chan - > oneTimeCalsDone = true ;
return true ;
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_9280_spur_mitigate ( struct ath_hw * ah , struct ath9k_channel * chan )
2008-10-29 10:16:30 +05:30
{
int bb_spur = AR_NO_SPUR ;
int freq ;
int bin , cur_bin ;
int bb_spur_off , spur_subchannel_sd ;
int spur_freq_sd ;
int spur_delta_phase ;
int denominator ;
int upper , lower , cur_vit_mask ;
int tmp , newVal ;
int i ;
int pilot_mask_reg [ 4 ] = { AR_PHY_TIMING7 , AR_PHY_TIMING8 ,
AR_PHY_PILOT_MASK_01_30 , AR_PHY_PILOT_MASK_31_60
} ;
int chan_mask_reg [ 4 ] = { AR_PHY_TIMING9 , AR_PHY_TIMING10 ,
AR_PHY_CHANNEL_MASK_01_30 , AR_PHY_CHANNEL_MASK_31_60
} ;
int inc [ 4 ] = { 0 , 100 , 0 , 0 } ;
struct chan_centers centers ;
int8_t mask_m [ 123 ] ;
int8_t mask_p [ 123 ] ;
int8_t mask_amt ;
int tmp_mask ;
int cur_bb_spur ;
bool is2GHz = IS_CHAN_2GHZ ( chan ) ;
memset ( & mask_m , 0 , sizeof ( int8_t ) * 123 ) ;
memset ( & mask_p , 0 , sizeof ( int8_t ) * 123 ) ;
ath9k_hw_get_channel_centers ( ah , chan , & centers ) ;
freq = centers . synth_center ;
ah - > ah_config . spurmode = SPUR_ENABLE_EEPROM ;
for ( i = 0 ; i < AR_EEPROM_MODAL_SPURS ; i + + ) {
cur_bb_spur = ath9k_hw_eeprom_get_spur_chan ( ah , i , is2GHz ) ;
if ( is2GHz )
cur_bb_spur = ( cur_bb_spur / 10 ) + AR_BASE_FREQ_2GHZ ;
else
cur_bb_spur = ( cur_bb_spur / 10 ) + AR_BASE_FREQ_5GHZ ;
if ( AR_NO_SPUR = = cur_bb_spur )
break ;
cur_bb_spur = cur_bb_spur - freq ;
if ( IS_CHAN_HT40 ( chan ) ) {
if ( ( cur_bb_spur > - AR_SPUR_FEEQ_BOUND_HT40 ) & &
( cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40 ) ) {
bb_spur = cur_bb_spur ;
break ;
}
} else if ( ( cur_bb_spur > - AR_SPUR_FEEQ_BOUND_HT20 ) & &
( cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20 ) ) {
bb_spur = cur_bb_spur ;
break ;
}
}
if ( AR_NO_SPUR = = bb_spur ) {
REG_CLR_BIT ( ah , AR_PHY_FORCE_CLKEN_CCK ,
AR_PHY_FORCE_CLKEN_CCK_MRC_MUX ) ;
return ;
} else {
REG_CLR_BIT ( ah , AR_PHY_FORCE_CLKEN_CCK ,
AR_PHY_FORCE_CLKEN_CCK_MRC_MUX ) ;
}
bin = bb_spur * 320 ;
tmp = REG_READ ( ah , AR_PHY_TIMING_CTRL4 ( 0 ) ) ;
newVal = tmp | ( AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK ) ;
REG_WRITE ( ah , AR_PHY_TIMING_CTRL4 ( 0 ) , newVal ) ;
newVal = ( AR_PHY_SPUR_REG_MASK_RATE_CNTL |
AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
AR_PHY_SPUR_REG_MASK_RATE_SELECT |
AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
SM ( SPUR_RSSI_THRESH , AR_PHY_SPUR_REG_SPUR_RSSI_THRESH ) ) ;
REG_WRITE ( ah , AR_PHY_SPUR_REG , newVal ) ;
if ( IS_CHAN_HT40 ( chan ) ) {
if ( bb_spur < 0 ) {
spur_subchannel_sd = 1 ;
bb_spur_off = bb_spur + 10 ;
} else {
spur_subchannel_sd = 0 ;
bb_spur_off = bb_spur - 10 ;
}
} else {
spur_subchannel_sd = 0 ;
bb_spur_off = bb_spur ;
}
if ( IS_CHAN_HT40 ( chan ) )
spur_delta_phase =
( ( bb_spur * 262144 ) /
10 ) & AR_PHY_TIMING11_SPUR_DELTA_PHASE ;
else
spur_delta_phase =
( ( bb_spur * 524288 ) /
10 ) & AR_PHY_TIMING11_SPUR_DELTA_PHASE ;
denominator = IS_CHAN_2GHZ ( chan ) ? 44 : 40 ;
spur_freq_sd = ( ( bb_spur_off * 2048 ) / denominator ) & 0x3ff ;
newVal = ( AR_PHY_TIMING11_USE_SPUR_IN_AGC |
SM ( spur_freq_sd , AR_PHY_TIMING11_SPUR_FREQ_SD ) |
SM ( spur_delta_phase , AR_PHY_TIMING11_SPUR_DELTA_PHASE ) ) ;
REG_WRITE ( ah , AR_PHY_TIMING11 , newVal ) ;
newVal = spur_subchannel_sd < < AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S ;
REG_WRITE ( ah , AR_PHY_SFCORR_EXT , newVal ) ;
cur_bin = - 6000 ;
upper = bin + 100 ;
lower = bin - 100 ;
for ( i = 0 ; i < 4 ; i + + ) {
int pilot_mask = 0 ;
int chan_mask = 0 ;
int bp = 0 ;
for ( bp = 0 ; bp < 30 ; bp + + ) {
if ( ( cur_bin > lower ) & & ( cur_bin < upper ) ) {
pilot_mask = pilot_mask | 0x1 < < bp ;
chan_mask = chan_mask | 0x1 < < bp ;
}
cur_bin + = 100 ;
}
cur_bin + = inc [ i ] ;
REG_WRITE ( ah , pilot_mask_reg [ i ] , pilot_mask ) ;
REG_WRITE ( ah , chan_mask_reg [ i ] , chan_mask ) ;
}
cur_vit_mask = 6100 ;
upper = bin + 120 ;
lower = bin - 120 ;
for ( i = 0 ; i < 123 ; i + + ) {
if ( ( cur_vit_mask > lower ) & & ( cur_vit_mask < upper ) ) {
/* workaround for gcc bug #37014 */
2008-12-23 15:58:51 -08:00
volatile int tmp_v = abs ( cur_vit_mask - bin ) ;
2008-10-29 10:16:30 +05:30
2008-12-23 15:58:51 -08:00
if ( tmp_v < 75 )
2008-10-29 10:16:30 +05:30
mask_amt = 1 ;
else
mask_amt = 0 ;
if ( cur_vit_mask < 0 )
mask_m [ abs ( cur_vit_mask / 100 ) ] = mask_amt ;
else
mask_p [ cur_vit_mask / 100 ] = mask_amt ;
}
cur_vit_mask - = 100 ;
}
tmp_mask = ( mask_m [ 46 ] < < 30 ) | ( mask_m [ 47 ] < < 28 )
| ( mask_m [ 48 ] < < 26 ) | ( mask_m [ 49 ] < < 24 )
| ( mask_m [ 50 ] < < 22 ) | ( mask_m [ 51 ] < < 20 )
| ( mask_m [ 52 ] < < 18 ) | ( mask_m [ 53 ] < < 16 )
| ( mask_m [ 54 ] < < 14 ) | ( mask_m [ 55 ] < < 12 )
| ( mask_m [ 56 ] < < 10 ) | ( mask_m [ 57 ] < < 8 )
| ( mask_m [ 58 ] < < 6 ) | ( mask_m [ 59 ] < < 4 )
| ( mask_m [ 60 ] < < 2 ) | ( mask_m [ 61 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK_1 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_VIT_MASK2_M_46_61 , tmp_mask ) ;
tmp_mask = ( mask_m [ 31 ] < < 28 )
| ( mask_m [ 32 ] < < 26 ) | ( mask_m [ 33 ] < < 24 )
| ( mask_m [ 34 ] < < 22 ) | ( mask_m [ 35 ] < < 20 )
| ( mask_m [ 36 ] < < 18 ) | ( mask_m [ 37 ] < < 16 )
| ( mask_m [ 48 ] < < 14 ) | ( mask_m [ 39 ] < < 12 )
| ( mask_m [ 40 ] < < 10 ) | ( mask_m [ 41 ] < < 8 )
| ( mask_m [ 42 ] < < 6 ) | ( mask_m [ 43 ] < < 4 )
| ( mask_m [ 44 ] < < 2 ) | ( mask_m [ 45 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK_2 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_M_31_45 , tmp_mask ) ;
tmp_mask = ( mask_m [ 16 ] < < 30 ) | ( mask_m [ 16 ] < < 28 )
| ( mask_m [ 18 ] < < 26 ) | ( mask_m [ 18 ] < < 24 )
| ( mask_m [ 20 ] < < 22 ) | ( mask_m [ 20 ] < < 20 )
| ( mask_m [ 22 ] < < 18 ) | ( mask_m [ 22 ] < < 16 )
| ( mask_m [ 24 ] < < 14 ) | ( mask_m [ 24 ] < < 12 )
| ( mask_m [ 25 ] < < 10 ) | ( mask_m [ 26 ] < < 8 )
| ( mask_m [ 27 ] < < 6 ) | ( mask_m [ 28 ] < < 4 )
| ( mask_m [ 29 ] < < 2 ) | ( mask_m [ 30 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK_3 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_M_16_30 , tmp_mask ) ;
tmp_mask = ( mask_m [ 0 ] < < 30 ) | ( mask_m [ 1 ] < < 28 )
| ( mask_m [ 2 ] < < 26 ) | ( mask_m [ 3 ] < < 24 )
| ( mask_m [ 4 ] < < 22 ) | ( mask_m [ 5 ] < < 20 )
| ( mask_m [ 6 ] < < 18 ) | ( mask_m [ 7 ] < < 16 )
| ( mask_m [ 8 ] < < 14 ) | ( mask_m [ 9 ] < < 12 )
| ( mask_m [ 10 ] < < 10 ) | ( mask_m [ 11 ] < < 8 )
| ( mask_m [ 12 ] < < 6 ) | ( mask_m [ 13 ] < < 4 )
| ( mask_m [ 14 ] < < 2 ) | ( mask_m [ 15 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_MASK_CTL , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_M_00_15 , tmp_mask ) ;
tmp_mask = ( mask_p [ 15 ] < < 28 )
| ( mask_p [ 14 ] < < 26 ) | ( mask_p [ 13 ] < < 24 )
| ( mask_p [ 12 ] < < 22 ) | ( mask_p [ 11 ] < < 20 )
| ( mask_p [ 10 ] < < 18 ) | ( mask_p [ 9 ] < < 16 )
| ( mask_p [ 8 ] < < 14 ) | ( mask_p [ 7 ] < < 12 )
| ( mask_p [ 6 ] < < 10 ) | ( mask_p [ 5 ] < < 8 )
| ( mask_p [ 4 ] < < 6 ) | ( mask_p [ 3 ] < < 4 )
| ( mask_p [ 2 ] < < 2 ) | ( mask_p [ 1 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK2_1 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_P_15_01 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_p [ 30 ] < < 28 )
| ( mask_p [ 29 ] < < 26 ) | ( mask_p [ 28 ] < < 24 )
| ( mask_p [ 27 ] < < 22 ) | ( mask_p [ 26 ] < < 20 )
| ( mask_p [ 25 ] < < 18 ) | ( mask_p [ 24 ] < < 16 )
| ( mask_p [ 23 ] < < 14 ) | ( mask_p [ 22 ] < < 12 )
| ( mask_p [ 21 ] < < 10 ) | ( mask_p [ 20 ] < < 8 )
| ( mask_p [ 19 ] < < 6 ) | ( mask_p [ 18 ] < < 4 )
| ( mask_p [ 17 ] < < 2 ) | ( mask_p [ 16 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK2_2 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_P_30_16 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_p [ 45 ] < < 28 )
| ( mask_p [ 44 ] < < 26 ) | ( mask_p [ 43 ] < < 24 )
| ( mask_p [ 42 ] < < 22 ) | ( mask_p [ 41 ] < < 20 )
| ( mask_p [ 40 ] < < 18 ) | ( mask_p [ 39 ] < < 16 )
| ( mask_p [ 38 ] < < 14 ) | ( mask_p [ 37 ] < < 12 )
| ( mask_p [ 36 ] < < 10 ) | ( mask_p [ 35 ] < < 8 )
| ( mask_p [ 34 ] < < 6 ) | ( mask_p [ 33 ] < < 4 )
| ( mask_p [ 32 ] < < 2 ) | ( mask_p [ 31 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK2_3 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_P_45_31 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_p [ 61 ] < < 30 ) | ( mask_p [ 60 ] < < 28 )
| ( mask_p [ 59 ] < < 26 ) | ( mask_p [ 58 ] < < 24 )
| ( mask_p [ 57 ] < < 22 ) | ( mask_p [ 56 ] < < 20 )
| ( mask_p [ 55 ] < < 18 ) | ( mask_p [ 54 ] < < 16 )
| ( mask_p [ 53 ] < < 14 ) | ( mask_p [ 52 ] < < 12 )
| ( mask_p [ 51 ] < < 10 ) | ( mask_p [ 50 ] < < 8 )
| ( mask_p [ 49 ] < < 6 ) | ( mask_p [ 48 ] < < 4 )
| ( mask_p [ 47 ] < < 2 ) | ( mask_p [ 46 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK2_4 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_P_61_45 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static void ath9k_hw_spur_mitigate ( struct ath_hw * ah , struct ath9k_channel * chan )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
int bb_spur = AR_NO_SPUR ;
int bin , cur_bin ;
int spur_freq_sd ;
int spur_delta_phase ;
int denominator ;
int upper , lower , cur_vit_mask ;
int tmp , new ;
int i ;
int pilot_mask_reg [ 4 ] = { AR_PHY_TIMING7 , AR_PHY_TIMING8 ,
AR_PHY_PILOT_MASK_01_30 , AR_PHY_PILOT_MASK_31_60
} ;
int chan_mask_reg [ 4 ] = { AR_PHY_TIMING9 , AR_PHY_TIMING10 ,
AR_PHY_CHANNEL_MASK_01_30 , AR_PHY_CHANNEL_MASK_31_60
} ;
int inc [ 4 ] = { 0 , 100 , 0 , 0 } ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
int8_t mask_m [ 123 ] ;
int8_t mask_p [ 123 ] ;
int8_t mask_amt ;
int tmp_mask ;
int cur_bb_spur ;
bool is2GHz = IS_CHAN_2GHZ ( chan ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
memset ( & mask_m , 0 , sizeof ( int8_t ) * 123 ) ;
memset ( & mask_p , 0 , sizeof ( int8_t ) * 123 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
for ( i = 0 ; i < AR_EEPROM_MODAL_SPURS ; i + + ) {
cur_bb_spur = ath9k_hw_eeprom_get_spur_chan ( ah , i , is2GHz ) ;
if ( AR_NO_SPUR = = cur_bb_spur )
break ;
cur_bb_spur = cur_bb_spur - ( chan - > channel * 10 ) ;
if ( ( cur_bb_spur > - 95 ) & & ( cur_bb_spur < 95 ) ) {
bb_spur = cur_bb_spur ;
break ;
}
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_NO_SPUR = = bb_spur )
return ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
bin = bb_spur * 32 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp = REG_READ ( ah , AR_PHY_TIMING_CTRL4 ( 0 ) ) ;
new = tmp | ( AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PHY_TIMING_CTRL4 ( 0 ) , new ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
new = ( AR_PHY_SPUR_REG_MASK_RATE_CNTL |
AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
AR_PHY_SPUR_REG_MASK_RATE_SELECT |
AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
SM ( SPUR_RSSI_THRESH , AR_PHY_SPUR_REG_SPUR_RSSI_THRESH ) ) ;
REG_WRITE ( ah , AR_PHY_SPUR_REG , new ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
spur_delta_phase = ( ( bb_spur * 524288 ) / 100 ) &
AR_PHY_TIMING11_SPUR_DELTA_PHASE ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
denominator = IS_CHAN_2GHZ ( chan ) ? 440 : 400 ;
spur_freq_sd = ( ( bb_spur * 2048 ) / denominator ) & 0x3ff ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
new = ( AR_PHY_TIMING11_USE_SPUR_IN_AGC |
SM ( spur_freq_sd , AR_PHY_TIMING11_SPUR_FREQ_SD ) |
SM ( spur_delta_phase , AR_PHY_TIMING11_SPUR_DELTA_PHASE ) ) ;
REG_WRITE ( ah , AR_PHY_TIMING11 , new ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
cur_bin = - 6000 ;
upper = bin + 100 ;
lower = bin - 100 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
for ( i = 0 ; i < 4 ; i + + ) {
int pilot_mask = 0 ;
int chan_mask = 0 ;
int bp = 0 ;
for ( bp = 0 ; bp < 30 ; bp + + ) {
if ( ( cur_bin > lower ) & & ( cur_bin < upper ) ) {
pilot_mask = pilot_mask | 0x1 < < bp ;
chan_mask = chan_mask | 0x1 < < bp ;
}
cur_bin + = 100 ;
}
cur_bin + = inc [ i ] ;
REG_WRITE ( ah , pilot_mask_reg [ i ] , pilot_mask ) ;
REG_WRITE ( ah , chan_mask_reg [ i ] , chan_mask ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
cur_vit_mask = 6100 ;
upper = bin + 120 ;
lower = bin - 120 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
for ( i = 0 ; i < 123 ; i + + ) {
if ( ( cur_vit_mask > lower ) & & ( cur_vit_mask < upper ) ) {
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
/* workaround for gcc bug #37014 */
2008-12-23 15:58:51 -08:00
volatile int tmp_v = abs ( cur_vit_mask - bin ) ;
2008-08-04 00:16:41 -07:00
2008-12-23 15:58:51 -08:00
if ( tmp_v < 75 )
2008-10-29 10:16:30 +05:30
mask_amt = 1 ;
else
mask_amt = 0 ;
if ( cur_vit_mask < 0 )
mask_m [ abs ( cur_vit_mask / 100 ) ] = mask_amt ;
else
mask_p [ cur_vit_mask / 100 ] = mask_amt ;
}
cur_vit_mask - = 100 ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_m [ 46 ] < < 30 ) | ( mask_m [ 47 ] < < 28 )
| ( mask_m [ 48 ] < < 26 ) | ( mask_m [ 49 ] < < 24 )
| ( mask_m [ 50 ] < < 22 ) | ( mask_m [ 51 ] < < 20 )
| ( mask_m [ 52 ] < < 18 ) | ( mask_m [ 53 ] < < 16 )
| ( mask_m [ 54 ] < < 14 ) | ( mask_m [ 55 ] < < 12 )
| ( mask_m [ 56 ] < < 10 ) | ( mask_m [ 57 ] < < 8 )
| ( mask_m [ 58 ] < < 6 ) | ( mask_m [ 59 ] < < 4 )
| ( mask_m [ 60 ] < < 2 ) | ( mask_m [ 61 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK_1 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_VIT_MASK2_M_46_61 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_m [ 31 ] < < 28 )
| ( mask_m [ 32 ] < < 26 ) | ( mask_m [ 33 ] < < 24 )
| ( mask_m [ 34 ] < < 22 ) | ( mask_m [ 35 ] < < 20 )
| ( mask_m [ 36 ] < < 18 ) | ( mask_m [ 37 ] < < 16 )
| ( mask_m [ 48 ] < < 14 ) | ( mask_m [ 39 ] < < 12 )
| ( mask_m [ 40 ] < < 10 ) | ( mask_m [ 41 ] < < 8 )
| ( mask_m [ 42 ] < < 6 ) | ( mask_m [ 43 ] < < 4 )
| ( mask_m [ 44 ] < < 2 ) | ( mask_m [ 45 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK_2 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_M_31_45 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_m [ 16 ] < < 30 ) | ( mask_m [ 16 ] < < 28 )
| ( mask_m [ 18 ] < < 26 ) | ( mask_m [ 18 ] < < 24 )
| ( mask_m [ 20 ] < < 22 ) | ( mask_m [ 20 ] < < 20 )
| ( mask_m [ 22 ] < < 18 ) | ( mask_m [ 22 ] < < 16 )
| ( mask_m [ 24 ] < < 14 ) | ( mask_m [ 24 ] < < 12 )
| ( mask_m [ 25 ] < < 10 ) | ( mask_m [ 26 ] < < 8 )
| ( mask_m [ 27 ] < < 6 ) | ( mask_m [ 28 ] < < 4 )
| ( mask_m [ 29 ] < < 2 ) | ( mask_m [ 30 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK_3 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_M_16_30 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_m [ 0 ] < < 30 ) | ( mask_m [ 1 ] < < 28 )
| ( mask_m [ 2 ] < < 26 ) | ( mask_m [ 3 ] < < 24 )
| ( mask_m [ 4 ] < < 22 ) | ( mask_m [ 5 ] < < 20 )
| ( mask_m [ 6 ] < < 18 ) | ( mask_m [ 7 ] < < 16 )
| ( mask_m [ 8 ] < < 14 ) | ( mask_m [ 9 ] < < 12 )
| ( mask_m [ 10 ] < < 10 ) | ( mask_m [ 11 ] < < 8 )
| ( mask_m [ 12 ] < < 6 ) | ( mask_m [ 13 ] < < 4 )
| ( mask_m [ 14 ] < < 2 ) | ( mask_m [ 15 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_MASK_CTL , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_M_00_15 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_p [ 15 ] < < 28 )
| ( mask_p [ 14 ] < < 26 ) | ( mask_p [ 13 ] < < 24 )
| ( mask_p [ 12 ] < < 22 ) | ( mask_p [ 11 ] < < 20 )
| ( mask_p [ 10 ] < < 18 ) | ( mask_p [ 9 ] < < 16 )
| ( mask_p [ 8 ] < < 14 ) | ( mask_p [ 7 ] < < 12 )
| ( mask_p [ 6 ] < < 10 ) | ( mask_p [ 5 ] < < 8 )
| ( mask_p [ 4 ] < < 6 ) | ( mask_p [ 3 ] < < 4 )
| ( mask_p [ 2 ] < < 2 ) | ( mask_p [ 1 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK2_1 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_P_15_01 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_p [ 30 ] < < 28 )
| ( mask_p [ 29 ] < < 26 ) | ( mask_p [ 28 ] < < 24 )
| ( mask_p [ 27 ] < < 22 ) | ( mask_p [ 26 ] < < 20 )
| ( mask_p [ 25 ] < < 18 ) | ( mask_p [ 24 ] < < 16 )
| ( mask_p [ 23 ] < < 14 ) | ( mask_p [ 22 ] < < 12 )
| ( mask_p [ 21 ] < < 10 ) | ( mask_p [ 20 ] < < 8 )
| ( mask_p [ 19 ] < < 6 ) | ( mask_p [ 18 ] < < 4 )
| ( mask_p [ 17 ] < < 2 ) | ( mask_p [ 16 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK2_2 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_P_30_16 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_p [ 45 ] < < 28 )
| ( mask_p [ 44 ] < < 26 ) | ( mask_p [ 43 ] < < 24 )
| ( mask_p [ 42 ] < < 22 ) | ( mask_p [ 41 ] < < 20 )
| ( mask_p [ 40 ] < < 18 ) | ( mask_p [ 39 ] < < 16 )
| ( mask_p [ 38 ] < < 14 ) | ( mask_p [ 37 ] < < 12 )
| ( mask_p [ 36 ] < < 10 ) | ( mask_p [ 35 ] < < 8 )
| ( mask_p [ 34 ] < < 6 ) | ( mask_p [ 33 ] < < 4 )
| ( mask_p [ 32 ] < < 2 ) | ( mask_p [ 31 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK2_3 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_P_45_31 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tmp_mask = ( mask_p [ 61 ] < < 30 ) | ( mask_p [ 60 ] < < 28 )
| ( mask_p [ 59 ] < < 26 ) | ( mask_p [ 58 ] < < 24 )
| ( mask_p [ 57 ] < < 22 ) | ( mask_p [ 56 ] < < 20 )
| ( mask_p [ 55 ] < < 18 ) | ( mask_p [ 54 ] < < 16 )
| ( mask_p [ 53 ] < < 14 ) | ( mask_p [ 52 ] < < 12 )
| ( mask_p [ 51 ] < < 10 ) | ( mask_p [ 50 ] < < 8 )
| ( mask_p [ 49 ] < < 6 ) | ( mask_p [ 48 ] < < 4 )
| ( mask_p [ 47 ] < < 2 ) | ( mask_p [ 46 ] < < 0 ) ;
REG_WRITE ( ah , AR_PHY_BIN_MASK2_4 , tmp_mask ) ;
REG_WRITE ( ah , AR_PHY_MASK2_P_61_45 , tmp_mask ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
int ath9k_hw_reset ( struct ath_hw * ah , struct ath9k_channel * chan ,
2008-12-23 15:58:40 -08:00
bool bChannelChange )
2008-08-04 00:16:41 -07:00
{
u32 saveLedState ;
2008-12-23 15:58:40 -08:00
struct ath_softc * sc = ah - > ah_sc ;
2008-08-04 00:16:41 -07:00
struct ath9k_channel * curchan = ah - > ah_curchan ;
u32 saveDefAntenna ;
u32 macStaId1 ;
2008-12-23 15:58:40 -08:00
int i , rx_chainmask , r ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
ah - > ah_extprotspacing = sc - > ht_extprotspacing ;
ah - > ah_txchainmask = sc - > tx_chainmask ;
ah - > ah_rxchainmask = sc - > rx_chainmask ;
2008-08-04 00:16:41 -07:00
2009-01-26 20:28:14 +05:30
if ( AR_SREV_9285 ( ah ) ) {
2009-02-09 13:27:12 +05:30
ah - > ah_txchainmask & = 0x1 ;
ah - > ah_rxchainmask & = 0x1 ;
2009-01-26 20:28:14 +05:30
} else if ( AR_SREV_9280 ( ah ) ) {
2009-02-09 13:27:12 +05:30
ah - > ah_txchainmask & = 0x3 ;
ah - > ah_rxchainmask & = 0x3 ;
2008-08-04 00:16:41 -07:00
}
2008-12-23 15:58:40 -08:00
if ( ! ath9k_hw_setpower ( ah , ATH9K_PM_AWAKE ) )
return - EIO ;
2008-08-04 00:16:41 -07:00
if ( curchan )
ath9k_hw_getnf ( ah , curchan ) ;
if ( bChannelChange & &
2009-02-09 13:27:12 +05:30
( ah - > ah_chipFullSleep ! = true ) & &
2008-08-04 00:16:41 -07:00
( ah - > ah_curchan ! = NULL ) & &
( chan - > channel ! = ah - > ah_curchan - > channel ) & &
( ( chan - > channelFlags & CHANNEL_ALL ) = =
( ah - > ah_curchan - > channelFlags & CHANNEL_ALL ) ) & &
( ! AR_SREV_9280 ( ah ) | | ( ! IS_CHAN_A_5MHZ_SPACED ( chan ) & &
2008-11-24 12:08:35 +05:30
! IS_CHAN_A_5MHZ_SPACED ( ah - > ah_curchan ) ) ) ) {
2008-08-04 00:16:41 -07:00
2008-12-23 15:58:40 -08:00
if ( ath9k_hw_channel_change ( ah , chan , sc - > tx_chan_width ) ) {
2008-08-04 00:16:41 -07:00
ath9k_hw_loadnf ( ah , ah - > ah_curchan ) ;
ath9k_hw_start_nfcal ( ah ) ;
2008-12-23 15:58:40 -08:00
return 0 ;
2008-08-04 00:16:41 -07:00
}
}
saveDefAntenna = REG_READ ( ah , AR_DEF_ANTENNA ) ;
if ( saveDefAntenna = = 0 )
saveDefAntenna = 1 ;
macStaId1 = REG_READ ( ah , AR_STA_ID1 ) & AR_STA_ID1_BASE_RATE_11B ;
saveLedState = REG_READ ( ah , AR_CFG_LED ) &
( AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW ) ;
ath9k_hw_mark_phy_inactive ( ah ) ;
if ( ! ath9k_hw_chip_reset ( ah , chan ) ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET , " chip reset failed \n " ) ;
2008-12-23 15:58:40 -08:00
return - EINVAL ;
2008-08-04 00:16:41 -07:00
}
2009-01-21 19:24:13 +05:30
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
REG_SET_BIT ( ah , AR_GPIO_INPUT_EN_VAL , AR_GPIO_JTAG_DISABLE ) ;
2008-08-04 00:16:41 -07:00
2008-12-23 15:58:40 -08:00
r = ath9k_hw_process_ini ( ah , chan , sc - > tx_chan_width ) ;
if ( r )
return r ;
2008-08-04 00:16:41 -07:00
2009-01-08 13:32:13 +02:00
/* Setup MFP options for CCMP */
if ( AR_SREV_9280_20_OR_LATER ( ah ) ) {
/* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
* frames when constructing CCMP AAD . */
REG_RMW_FIELD ( ah , AR_AES_MUTE_MASK1 , AR_AES_MUTE_MASK1_FC_MGMT ,
0xc7ff ) ;
ah - > sw_mgmt_crypto = false ;
} else if ( AR_SREV_9160_10_OR_LATER ( ah ) ) {
/* Disable hardware crypto for management frames */
REG_CLR_BIT ( ah , AR_PCU_MISC_MODE2 ,
AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE ) ;
REG_SET_BIT ( ah , AR_PCU_MISC_MODE2 ,
AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT ) ;
ah - > sw_mgmt_crypto = true ;
} else
ah - > sw_mgmt_crypto = true ;
2008-08-04 00:16:41 -07:00
if ( IS_CHAN_OFDM ( chan ) | | IS_CHAN_HT ( chan ) )
ath9k_hw_set_delta_slope ( ah , chan ) ;
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
ath9k_hw_9280_spur_mitigate ( ah , chan ) ;
else
ath9k_hw_spur_mitigate ( ah , chan ) ;
if ( ! ath9k_hw_eeprom_set_board_values ( ah , chan ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_EEPROM ,
2008-11-28 22:18:05 +05:30
" error setting board options \n " ) ;
2008-12-23 15:58:40 -08:00
return - EIO ;
2008-08-04 00:16:41 -07:00
}
ath9k_hw_decrease_chain_power ( ah , chan ) ;
2009-02-09 13:27:10 +05:30
REG_WRITE ( ah , AR_STA_ID0 , get_unaligned_le32 ( ah - > macaddr ) ) ;
REG_WRITE ( ah , AR_STA_ID1 , get_unaligned_le16 ( ah - > macaddr + 4 )
2008-08-04 00:16:41 -07:00
| macStaId1
| AR_STA_ID1_RTS_USE_DEF
| ( ah - > ah_config .
2008-08-07 10:52:38 +05:30
ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0 )
2009-02-09 13:27:12 +05:30
| ah - > ah_staId1Defaults ) ;
2008-08-11 14:04:52 +05:30
ath9k_hw_set_operating_mode ( ah , ah - > ah_opmode ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:10 +05:30
REG_WRITE ( ah , AR_BSSMSKL , get_unaligned_le32 ( sc - > bssidmask ) ) ;
REG_WRITE ( ah , AR_BSSMSKU , get_unaligned_le16 ( sc - > bssidmask + 4 ) ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_DEF_ANTENNA , saveDefAntenna ) ;
2009-02-09 13:27:10 +05:30
REG_WRITE ( ah , AR_BSS_ID0 , get_unaligned_le32 ( sc - > curbssid ) ) ;
REG_WRITE ( ah , AR_BSS_ID1 , get_unaligned_le16 ( sc - > curbssid + 4 ) |
( ( sc - > curaid & 0x3fff ) < < AR_BSS_ID1_AID_S ) ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_ISR , ~ 0 ) ;
REG_WRITE ( ah , AR_RSSI_THR , INIT_RSSI_THR ) ;
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
2008-12-23 15:58:40 -08:00
if ( ! ( ath9k_hw_ar9280_set_channel ( ah , chan ) ) )
return - EIO ;
2008-08-04 00:16:41 -07:00
} else {
2008-12-23 15:58:40 -08:00
if ( ! ( ath9k_hw_set_channel ( ah , chan ) ) )
return - EIO ;
2008-08-04 00:16:41 -07:00
}
for ( i = 0 ; i < AR_NUM_DCU ; i + + )
REG_WRITE ( ah , AR_DQCUMASK ( i ) , 1 < < i ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_intrTxqs = 0 ;
2008-08-07 10:52:38 +05:30
for ( i = 0 ; i < ah - > ah_caps . total_queues ; i + + )
2008-08-04 00:16:41 -07:00
ath9k_hw_resettxqueue ( ah , i ) ;
2008-08-11 14:04:52 +05:30
ath9k_hw_init_interrupt_masks ( ah , ah - > ah_opmode ) ;
2008-08-04 00:16:41 -07:00
ath9k_hw_init_qos ( ah ) ;
2008-11-13 18:00:02 +05:30
# if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
2008-09-10 18:50:17 +05:30
if ( ah - > ah_caps . hw_caps & ATH9K_HW_CAP_RFSILENT )
ath9k_enable_rfkill ( ah ) ;
# endif
2008-08-04 00:16:41 -07:00
ath9k_hw_init_user_settings ( ah ) ;
REG_WRITE ( ah , AR_STA_ID1 ,
REG_READ ( ah , AR_STA_ID1 ) | AR_STA_ID1_PRESERVE_SEQNUM ) ;
ath9k_hw_set_dma ( ah ) ;
REG_WRITE ( ah , AR_OBS , 8 ) ;
2009-02-09 13:27:12 +05:30
if ( ah - > ah_intrMitigation ) {
2008-08-04 00:16:41 -07:00
REG_RMW_FIELD ( ah , AR_RIMT , AR_RIMT_LAST , 500 ) ;
REG_RMW_FIELD ( ah , AR_RIMT , AR_RIMT_FIRST , 2000 ) ;
}
ath9k_hw_init_bb ( ah , chan ) ;
2008-12-23 15:58:40 -08:00
if ( ! ath9k_hw_init_cal ( ah , chan ) )
return - EIO ; ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
rx_chainmask = ah - > ah_rxchainmask ;
2008-08-04 00:16:41 -07:00
if ( ( rx_chainmask = = 0x5 ) | | ( rx_chainmask = = 0x3 ) ) {
REG_WRITE ( ah , AR_PHY_RX_CHAINMASK , rx_chainmask ) ;
REG_WRITE ( ah , AR_PHY_CAL_CHAINMASK , rx_chainmask ) ;
}
REG_WRITE ( ah , AR_CFG_LED , saveLedState | AR_CFG_SCLK_32KHZ ) ;
if ( AR_SREV_9100 ( ah ) ) {
u32 mask ;
mask = REG_READ ( ah , AR_CFG ) ;
if ( mask & ( AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" CFG Byte Swap Set 0x%x \n " , mask ) ;
2008-08-04 00:16:41 -07:00
} else {
mask =
INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB ;
REG_WRITE ( ah , AR_CFG , mask ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" Setting CFG 0x%x \n " , REG_READ ( ah , AR_CFG ) ) ;
2008-08-04 00:16:41 -07:00
}
} else {
# ifdef __BIG_ENDIAN
REG_WRITE ( ah , AR_CFG , AR_CFG_SWTD | AR_CFG_SWRD ) ;
# endif
}
2008-12-23 15:58:40 -08:00
return 0 ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
/************************/
/* Key Cache Management */
/************************/
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
bool ath9k_hw_keyreset ( struct ath_hw * ah , u16 entry )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 keyType ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( entry > = ah - > ah_caps . keycache_size ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_KEYCACHE ,
2008-11-28 22:18:05 +05:30
" entry %u out of range \n " , entry ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
2008-10-29 10:16:30 +05:30
keyType = REG_READ ( ah , AR_KEYTABLE_TYPE ( entry ) ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( entry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( entry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( entry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( entry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY4 ( entry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_TYPE ( entry ) , AR_KEYTABLE_TYPE_CLR ) ;
REG_WRITE ( ah , AR_KEYTABLE_MAC0 ( entry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_MAC1 ( entry ) , 0 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( keyType = = AR_KEYTABLE_TYPE_TKIP & & ATH9K_IS_MIC_ENABLED ( ah ) ) {
u16 micentry = entry + 64 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( micentry ) , 0 ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
if ( ah - > ah_curchan = = NULL )
return true ;
2008-08-04 00:16:41 -07:00
return true ;
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_keysetmac ( struct ath_hw * ah , u16 entry , const u8 * mac )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 macHi , macLo ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( entry > = ah - > ah_caps . keycache_size ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_KEYCACHE ,
2008-11-28 22:18:05 +05:30
" entry %u out of range \n " , entry ) ;
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
if ( mac ! = NULL ) {
macHi = ( mac [ 5 ] < < 8 ) | mac [ 4 ] ;
macLo = ( mac [ 3 ] < < 24 ) |
( mac [ 2 ] < < 16 ) |
( mac [ 1 ] < < 8 ) |
mac [ 0 ] ;
macLo > > = 1 ;
macLo | = ( macHi & 1 ) < < 31 ;
macHi > > = 1 ;
2008-08-04 00:16:41 -07:00
} else {
2008-10-29 10:16:30 +05:30
macLo = macHi = 0 ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_MAC0 ( entry ) , macLo ) ;
REG_WRITE ( ah , AR_KEYTABLE_MAC1 ( entry ) , macHi | AR_KEYTABLE_VALID ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return true ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_set_keycache_entry ( struct ath_hw * ah , u16 entry ,
2008-10-29 10:16:30 +05:30
const struct ath9k_keyval * k ,
const u8 * mac , int xorKey )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
const struct ath9k_hw_capabilities * pCap = & ah - > ah_caps ;
u32 key0 , key1 , key2 , key3 , key4 ;
u32 keyType ;
u32 xorMask = xorKey ?
( ATH9K_KEY_XOR < < 24 | ATH9K_KEY_XOR < < 16 | ATH9K_KEY_XOR < < 8
| ATH9K_KEY_XOR ) : 0 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( entry > = pCap - > keycache_size ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_KEYCACHE ,
2008-11-28 22:18:05 +05:30
" entry %u out of range \n " , entry ) ;
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
switch ( k - > kv_type ) {
case ATH9K_CIPHER_AES_OCB :
keyType = AR_KEYTABLE_TYPE_AES ;
break ;
case ATH9K_CIPHER_AES_CCM :
if ( ! ( pCap - > hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM ) ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_KEYCACHE ,
2008-11-28 22:18:05 +05:30
" AES-CCM not supported by mac rev 0x%x \n " ,
2009-02-09 13:27:06 +05:30
ah - > hw_version . macRev ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
keyType = AR_KEYTABLE_TYPE_CCM ;
break ;
case ATH9K_CIPHER_TKIP :
keyType = AR_KEYTABLE_TYPE_TKIP ;
if ( ATH9K_IS_MIC_ENABLED ( ah )
& & entry + 64 > = pCap - > keycache_size ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_KEYCACHE ,
2008-11-28 22:18:05 +05:30
" entry %u inappropriate for TKIP \n " , entry ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
break ;
case ATH9K_CIPHER_WEP :
if ( k - > kv_len < LEN_WEP40 ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_KEYCACHE ,
2008-11-28 22:18:05 +05:30
" WEP key length %u too small \n " , k - > kv_len ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
if ( k - > kv_len < = LEN_WEP40 )
keyType = AR_KEYTABLE_TYPE_40 ;
else if ( k - > kv_len < = LEN_WEP104 )
keyType = AR_KEYTABLE_TYPE_104 ;
else
keyType = AR_KEYTABLE_TYPE_128 ;
break ;
case ATH9K_CIPHER_CLR :
keyType = AR_KEYTABLE_TYPE_CLR ;
break ;
default :
DPRINTF ( ah - > ah_sc , ATH_DBG_KEYCACHE ,
2008-11-28 22:18:05 +05:30
" cipher %u not supported \n " , k - > kv_type ) ;
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
key0 = get_unaligned_le32 ( k - > kv_val + 0 ) ^ xorMask ;
key1 = ( get_unaligned_le16 ( k - > kv_val + 4 ) ^ xorMask ) & 0xffff ;
key2 = get_unaligned_le32 ( k - > kv_val + 6 ) ^ xorMask ;
key3 = ( get_unaligned_le16 ( k - > kv_val + 10 ) ^ xorMask ) & 0xffff ;
key4 = get_unaligned_le32 ( k - > kv_val + 12 ) ^ xorMask ;
if ( k - > kv_len < = LEN_WEP104 )
key4 & = 0xff ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( keyType = = AR_KEYTABLE_TYPE_TKIP & & ATH9K_IS_MIC_ENABLED ( ah ) ) {
u16 micentry = entry + 64 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( entry ) , ~ key0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( entry ) , ~ key1 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( entry ) , key2 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( entry ) , key3 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY4 ( entry ) , key4 ) ;
REG_WRITE ( ah , AR_KEYTABLE_TYPE ( entry ) , keyType ) ;
( void ) ath9k_hw_keysetmac ( ah , entry , mac ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
if ( ah - > ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA ) {
2008-10-29 10:16:30 +05:30
u32 mic0 , mic1 , mic2 , mic3 , mic4 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
mic0 = get_unaligned_le32 ( k - > kv_mic + 0 ) ;
mic2 = get_unaligned_le32 ( k - > kv_mic + 4 ) ;
mic1 = get_unaligned_le16 ( k - > kv_txmic + 2 ) & 0xffff ;
mic3 = get_unaligned_le16 ( k - > kv_txmic + 0 ) & 0xffff ;
mic4 = get_unaligned_le32 ( k - > kv_txmic + 4 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( micentry ) , mic0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( micentry ) , mic1 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( micentry ) , mic2 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( micentry ) , mic3 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY4 ( micentry ) , mic4 ) ;
REG_WRITE ( ah , AR_KEYTABLE_TYPE ( micentry ) ,
AR_KEYTABLE_TYPE_CLR ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
} else {
u32 mic0 , mic2 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
mic0 = get_unaligned_le32 ( k - > kv_mic + 0 ) ;
mic2 = get_unaligned_le32 ( k - > kv_mic + 4 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( micentry ) , mic0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( micentry ) , mic2 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY4 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_TYPE ( micentry ) ,
AR_KEYTABLE_TYPE_CLR ) ;
}
REG_WRITE ( ah , AR_KEYTABLE_MAC0 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_MAC1 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( entry ) , key0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( entry ) , key1 ) ;
} else {
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( entry ) , key0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( entry ) , key1 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( entry ) , key2 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( entry ) , key3 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY4 ( entry ) , key4 ) ;
REG_WRITE ( ah , AR_KEYTABLE_TYPE ( entry ) , keyType ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
( void ) ath9k_hw_keysetmac ( ah , entry , mac ) ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ah - > ah_curchan = = NULL )
return true ;
2008-08-04 00:16:41 -07:00
return true ;
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_keyisvalid ( struct ath_hw * ah , u16 entry )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
if ( entry < ah - > ah_caps . keycache_size ) {
u32 val = REG_READ ( ah , AR_KEYTABLE_MAC1 ( entry ) ) ;
if ( val & AR_KEYTABLE_VALID )
return true ;
}
return false ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
/******************************/
/* Power Management (Chipset) */
/******************************/
2009-02-09 13:27:12 +05:30
static void ath9k_set_power_sleep ( struct ath_hw * ah , int setChip )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
REG_SET_BIT ( ah , AR_STA_ID1 , AR_STA_ID1_PWR_SAV ) ;
if ( setChip ) {
REG_CLR_BIT ( ah , AR_RTC_FORCE_WAKE ,
AR_RTC_FORCE_WAKE_EN ) ;
if ( ! AR_SREV_9100 ( ah ) )
REG_WRITE ( ah , AR_RC , AR_RC_AHB | AR_RC_HOSTIF ) ;
2008-08-04 00:16:41 -07:00
2009-01-14 20:17:09 +01:00
REG_CLR_BIT ( ah , ( AR_RTC_RESET ) ,
2008-10-29 10:16:30 +05:30
AR_RTC_RESET_EN ) ;
}
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
static void ath9k_set_power_network_sleep ( struct ath_hw * ah , int setChip )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
REG_SET_BIT ( ah , AR_STA_ID1 , AR_STA_ID1_PWR_SAV ) ;
if ( setChip ) {
struct ath9k_hw_capabilities * pCap = & ah - > ah_caps ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ! ( pCap - > hw_caps & ATH9K_HW_CAP_AUTOSLEEP ) ) {
REG_WRITE ( ah , AR_RTC_FORCE_WAKE ,
AR_RTC_FORCE_WAKE_ON_INT ) ;
} else {
REG_CLR_BIT ( ah , AR_RTC_FORCE_WAKE ,
AR_RTC_FORCE_WAKE_EN ) ;
2008-08-04 00:16:41 -07:00
}
}
}
2009-02-09 13:27:12 +05:30
static bool ath9k_hw_set_power_awake ( struct ath_hw * ah , int setChip )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 val ;
int i ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( setChip ) {
if ( ( REG_READ ( ah , AR_RTC_STATUS ) &
AR_RTC_STATUS_M ) = = AR_RTC_STATUS_SHUTDOWN ) {
if ( ath9k_hw_set_reset_reg ( ah ,
ATH9K_RESET_POWER_ON ) ! = true ) {
return false ;
}
}
if ( AR_SREV_9100 ( ah ) )
REG_SET_BIT ( ah , AR_RTC_RESET ,
AR_RTC_RESET_EN ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_SET_BIT ( ah , AR_RTC_FORCE_WAKE ,
AR_RTC_FORCE_WAKE_EN ) ;
udelay ( 50 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
for ( i = POWER_UP_TIME / 50 ; i > 0 ; i - - ) {
val = REG_READ ( ah , AR_RTC_STATUS ) & AR_RTC_STATUS_M ;
if ( val = = AR_RTC_STATUS_ON )
break ;
udelay ( 50 ) ;
REG_SET_BIT ( ah , AR_RTC_FORCE_WAKE ,
AR_RTC_FORCE_WAKE_EN ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
if ( i = = 0 ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_POWER_MGMT ,
2008-11-28 22:18:05 +05:30
" Failed to wakeup in %uus \n " , POWER_UP_TIME / 20 ) ;
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
}
}
2008-10-29 10:16:30 +05:30
REG_CLR_BIT ( ah , AR_STA_ID1 , AR_STA_ID1_PWR_SAV ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return true ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_setpower ( struct ath_hw * ah , enum ath9k_power_mode mode )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
int status = true , setChip = true ;
2008-10-29 10:16:30 +05:30
static const char * modes [ ] = {
" AWAKE " ,
" FULL-SLEEP " ,
" NETWORK SLEEP " ,
" UNDEFINED "
} ;
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_POWER_MGMT , " %s -> %s (%s) \n " ,
2009-01-20 11:17:08 +05:30
modes [ ah - > ah_power_mode ] , modes [ mode ] ,
2008-10-29 10:16:30 +05:30
setChip ? " set chip " : " " ) ;
switch ( mode ) {
case ATH9K_PM_AWAKE :
status = ath9k_hw_set_power_awake ( ah , setChip ) ;
break ;
case ATH9K_PM_FULL_SLEEP :
ath9k_set_power_sleep ( ah , setChip ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_chipFullSleep = true ;
2008-10-29 10:16:30 +05:30
break ;
case ATH9K_PM_NETWORK_SLEEP :
ath9k_set_power_network_sleep ( ah , setChip ) ;
break ;
2008-08-04 00:16:41 -07:00
default :
2008-10-29 10:16:30 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_POWER_MGMT ,
2008-11-28 22:18:05 +05:30
" Unknown power mode %u \n " , mode ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
2009-01-20 11:17:08 +05:30
ah - > ah_power_mode = mode ;
2008-10-29 10:16:30 +05:30
return status ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_configpcipowersave ( struct ath_hw * ah , int restore )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u8 i ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ah - > ah_isPciExpress ! = true )
return ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ah - > ah_config . pcie_powersave_enable = = 2 )
return ;
if ( restore )
return ;
if ( AR_SREV_9280_20_OR_LATER ( ah ) ) {
2009-02-09 13:27:12 +05:30
for ( i = 0 ; i < ah - > ah_iniPcieSerdes . ia_rows ; i + + ) {
REG_WRITE ( ah , INI_RA ( & ah - > ah_iniPcieSerdes , i , 0 ) ,
INI_RA ( & ah - > ah_iniPcieSerdes , i , 1 ) ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
udelay ( 1000 ) ;
} else if ( AR_SREV_9280 ( ah ) & &
2009-02-09 13:27:06 +05:30
( ah - > hw_version . macRev = = AR_SREV_REVISION_9280_10 ) ) {
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PCIE_SERDES , 0x9248fd00 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x24924924 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xa8000019 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x13160820 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xe5980560 ) ;
if ( ah - > ah_config . pcie_clock_req )
REG_WRITE ( ah , AR_PCIE_SERDES , 0x401deffc ) ;
else
REG_WRITE ( ah , AR_PCIE_SERDES , 0x401deffd ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x1aaabe40 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xbe105554 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x00043007 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES2 , 0x00000000 ) ;
udelay ( 1000 ) ;
} else {
REG_WRITE ( ah , AR_PCIE_SERDES , 0x9248fc00 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x24924924 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x28000039 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x53160824 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xe5980579 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x001defff ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x1aaabe40 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xbe105554 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x000e3007 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES2 , 0x00000000 ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
REG_SET_BIT ( ah , AR_PCIE_PM_CTRL , AR_PCIE_PM_CTRL_ENA ) ;
if ( ah - > ah_config . pcie_waen ) {
REG_WRITE ( ah , AR_WA , ah - > ah_config . pcie_waen ) ;
} else {
2008-12-08 19:43:48 +05:30
if ( AR_SREV_9285 ( ah ) )
REG_WRITE ( ah , AR_WA , AR9285_WA_DEFAULT ) ;
else if ( AR_SREV_9280 ( ah ) )
REG_WRITE ( ah , AR_WA , AR9280_WA_DEFAULT ) ;
2008-10-29 10:16:30 +05:30
else
2008-12-08 19:43:48 +05:30
REG_WRITE ( ah , AR_WA , AR_WA_DEFAULT ) ;
2008-10-29 10:16:30 +05:30
}
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
/**********************/
/* Interrupt Handling */
/**********************/
2009-02-09 13:27:12 +05:30
bool ath9k_hw_intrpend ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
u32 host_isr ;
if ( AR_SREV_9100 ( ah ) )
return true ;
host_isr = REG_READ ( ah , AR_INTR_ASYNC_CAUSE ) ;
if ( ( host_isr & AR_INTR_MAC_IRQ ) & & ( host_isr ! = AR_INTR_SPURIOUS ) )
return true ;
host_isr = REG_READ ( ah , AR_INTR_SYNC_CAUSE ) ;
if ( ( host_isr & AR_INTR_SYNC_DEFAULT )
& & ( host_isr ! = AR_INTR_SPURIOUS ) )
return true ;
return false ;
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_getisr ( struct ath_hw * ah , enum ath9k_int * masked )
2008-08-04 00:16:41 -07:00
{
u32 isr = 0 ;
u32 mask2 = 0 ;
2008-08-07 10:52:38 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > ah_caps ;
2008-08-04 00:16:41 -07:00
u32 sync_cause = 0 ;
bool fatal_int = false ;
if ( ! AR_SREV_9100 ( ah ) ) {
if ( REG_READ ( ah , AR_INTR_ASYNC_CAUSE ) & AR_INTR_MAC_IRQ ) {
if ( ( REG_READ ( ah , AR_RTC_STATUS ) & AR_RTC_STATUS_M )
= = AR_RTC_STATUS_ON ) {
isr = REG_READ ( ah , AR_ISR ) ;
}
}
2008-10-29 10:16:30 +05:30
sync_cause = REG_READ ( ah , AR_INTR_SYNC_CAUSE ) &
AR_INTR_SYNC_DEFAULT ;
2008-08-04 00:16:41 -07:00
* masked = 0 ;
if ( ! isr & & ! sync_cause )
return false ;
} else {
* masked = 0 ;
isr = REG_READ ( ah , AR_ISR ) ;
}
if ( isr ) {
if ( isr & AR_ISR_BCNMISC ) {
u32 isr2 ;
isr2 = REG_READ ( ah , AR_ISR_S2 ) ;
if ( isr2 & AR_ISR_S2_TIM )
mask2 | = ATH9K_INT_TIM ;
if ( isr2 & AR_ISR_S2_DTIM )
mask2 | = ATH9K_INT_DTIM ;
if ( isr2 & AR_ISR_S2_DTIMSYNC )
mask2 | = ATH9K_INT_DTIMSYNC ;
if ( isr2 & ( AR_ISR_S2_CABEND ) )
mask2 | = ATH9K_INT_CABEND ;
if ( isr2 & AR_ISR_S2_GTT )
mask2 | = ATH9K_INT_GTT ;
if ( isr2 & AR_ISR_S2_CST )
mask2 | = ATH9K_INT_CST ;
}
isr = REG_READ ( ah , AR_ISR_RAC ) ;
if ( isr = = 0xffffffff ) {
* masked = 0 ;
return false ;
}
* masked = isr & ATH9K_INT_COMMON ;
2009-02-09 13:27:12 +05:30
if ( ah - > ah_intrMitigation ) {
2008-08-04 00:16:41 -07:00
if ( isr & ( AR_ISR_RXMINTR | AR_ISR_RXINTM ) )
* masked | = ATH9K_INT_RX ;
}
if ( isr & ( AR_ISR_RXOK | AR_ISR_RXERR ) )
* masked | = ATH9K_INT_RX ;
if ( isr &
( AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
AR_ISR_TXEOL ) ) {
u32 s0_s , s1_s ;
* masked | = ATH9K_INT_TX ;
s0_s = REG_READ ( ah , AR_ISR_S0_S ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_intrTxqs | = MS ( s0_s , AR_ISR_S0_QCU_TXOK ) ;
ah - > ah_intrTxqs | = MS ( s0_s , AR_ISR_S0_QCU_TXDESC ) ;
2008-08-04 00:16:41 -07:00
s1_s = REG_READ ( ah , AR_ISR_S1_S ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_intrTxqs | = MS ( s1_s , AR_ISR_S1_QCU_TXERR ) ;
ah - > ah_intrTxqs | = MS ( s1_s , AR_ISR_S1_QCU_TXEOL ) ;
2008-08-04 00:16:41 -07:00
}
if ( isr & AR_ISR_RXORN ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_INTERRUPT ,
2008-11-28 22:18:05 +05:30
" receive FIFO overrun interrupt \n " ) ;
2008-08-04 00:16:41 -07:00
}
if ( ! AR_SREV_9100 ( ah ) ) {
2008-08-07 10:52:38 +05:30
if ( ! ( pCap - > hw_caps & ATH9K_HW_CAP_AUTOSLEEP ) ) {
2008-08-04 00:16:41 -07:00
u32 isr5 = REG_READ ( ah , AR_ISR_S5_S ) ;
if ( isr5 & AR_ISR_S5_TIM_TIMER )
* masked | = ATH9K_INT_TIM_TIMER ;
}
}
* masked | = mask2 ;
}
2008-10-29 10:16:30 +05:30
2008-08-04 00:16:41 -07:00
if ( AR_SREV_9100 ( ah ) )
return true ;
2008-10-29 10:16:30 +05:30
2008-08-04 00:16:41 -07:00
if ( sync_cause ) {
fatal_int =
( sync_cause &
( AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR ) )
? true : false ;
if ( fatal_int ) {
if ( sync_cause & AR_INTR_SYNC_HOST1_FATAL ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_ANY ,
2008-11-28 22:18:05 +05:30
" received PCI FATAL interrupt \n " ) ;
2008-08-04 00:16:41 -07:00
}
if ( sync_cause & AR_INTR_SYNC_HOST1_PERR ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_ANY ,
2008-11-28 22:18:05 +05:30
" received PCI PERR interrupt \n " ) ;
2008-08-04 00:16:41 -07:00
}
}
if ( sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_INTERRUPT ,
2008-11-28 22:18:05 +05:30
" AR_INTR_SYNC_RADM_CPL_TIMEOUT \n " ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_RC , AR_RC_HOSTIF ) ;
REG_WRITE ( ah , AR_RC , 0 ) ;
* masked | = ATH9K_INT_FATAL ;
}
if ( sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_INTERRUPT ,
2008-11-28 22:18:05 +05:30
" AR_INTR_SYNC_LOCAL_TIMEOUT \n " ) ;
2008-08-04 00:16:41 -07:00
}
REG_WRITE ( ah , AR_INTR_SYNC_CAUSE_CLR , sync_cause ) ;
( void ) REG_READ ( ah , AR_INTR_SYNC_CAUSE_CLR ) ;
}
2008-10-29 10:16:30 +05:30
2008-08-04 00:16:41 -07:00
return true ;
}
2009-02-09 13:27:12 +05:30
enum ath9k_int ath9k_hw_intrget ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
return ah - > ah_maskReg ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
enum ath9k_int ath9k_hw_set_interrupts ( struct ath_hw * ah , enum ath9k_int ints )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
u32 omask = ah - > ah_maskReg ;
2008-08-04 00:16:41 -07:00
u32 mask , mask2 ;
2008-08-07 10:52:38 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > ah_caps ;
2008-08-04 00:16:41 -07:00
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_INTERRUPT , " 0x%x => 0x%x \n " , omask , ints ) ;
2008-08-04 00:16:41 -07:00
if ( omask & ATH9K_INT_GLOBAL ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_INTERRUPT , " disable IER \n " ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_IER , AR_IER_DISABLE ) ;
( void ) REG_READ ( ah , AR_IER ) ;
if ( ! AR_SREV_9100 ( ah ) ) {
REG_WRITE ( ah , AR_INTR_ASYNC_ENABLE , 0 ) ;
( void ) REG_READ ( ah , AR_INTR_ASYNC_ENABLE ) ;
REG_WRITE ( ah , AR_INTR_SYNC_ENABLE , 0 ) ;
( void ) REG_READ ( ah , AR_INTR_SYNC_ENABLE ) ;
}
}
mask = ints & ATH9K_INT_COMMON ;
mask2 = 0 ;
if ( ints & ATH9K_INT_TX ) {
2009-02-09 13:27:12 +05:30
if ( ah - > ah_txOkInterruptMask )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_TXOK ;
2009-02-09 13:27:12 +05:30
if ( ah - > ah_txDescInterruptMask )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_TXDESC ;
2009-02-09 13:27:12 +05:30
if ( ah - > ah_txErrInterruptMask )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_TXERR ;
2009-02-09 13:27:12 +05:30
if ( ah - > ah_txEolInterruptMask )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_TXEOL ;
}
if ( ints & ATH9K_INT_RX ) {
mask | = AR_IMR_RXERR ;
2009-02-09 13:27:12 +05:30
if ( ah - > ah_intrMitigation )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_RXMINTR | AR_IMR_RXINTM ;
else
mask | = AR_IMR_RXOK | AR_IMR_RXDESC ;
2008-08-07 10:52:38 +05:30
if ( ! ( pCap - > hw_caps & ATH9K_HW_CAP_AUTOSLEEP ) )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_GENTMR ;
}
if ( ints & ( ATH9K_INT_BMISC ) ) {
mask | = AR_IMR_BCNMISC ;
if ( ints & ATH9K_INT_TIM )
mask2 | = AR_IMR_S2_TIM ;
if ( ints & ATH9K_INT_DTIM )
mask2 | = AR_IMR_S2_DTIM ;
if ( ints & ATH9K_INT_DTIMSYNC )
mask2 | = AR_IMR_S2_DTIMSYNC ;
if ( ints & ATH9K_INT_CABEND )
mask2 | = ( AR_IMR_S2_CABEND ) ;
}
if ( ints & ( ATH9K_INT_GTT | ATH9K_INT_CST ) ) {
mask | = AR_IMR_BCNMISC ;
if ( ints & ATH9K_INT_GTT )
mask2 | = AR_IMR_S2_GTT ;
if ( ints & ATH9K_INT_CST )
mask2 | = AR_IMR_S2_CST ;
}
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_INTERRUPT , " new IMR 0x%x \n " , mask ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_IMR , mask ) ;
mask = REG_READ ( ah , AR_IMR_S2 ) & ~ ( AR_IMR_S2_TIM |
AR_IMR_S2_DTIM |
AR_IMR_S2_DTIMSYNC |
AR_IMR_S2_CABEND |
AR_IMR_S2_CABTO |
AR_IMR_S2_TSFOOR |
AR_IMR_S2_GTT | AR_IMR_S2_CST ) ;
REG_WRITE ( ah , AR_IMR_S2 , mask | mask2 ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_maskReg = ints ;
2008-08-04 00:16:41 -07:00
2008-08-07 10:52:38 +05:30
if ( ! ( pCap - > hw_caps & ATH9K_HW_CAP_AUTOSLEEP ) ) {
2008-08-04 00:16:41 -07:00
if ( ints & ATH9K_INT_TIM_TIMER )
REG_SET_BIT ( ah , AR_IMR_S5 , AR_IMR_S5_TIM_TIMER ) ;
else
REG_CLR_BIT ( ah , AR_IMR_S5 , AR_IMR_S5_TIM_TIMER ) ;
}
if ( ints & ATH9K_INT_GLOBAL ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_INTERRUPT , " enable IER \n " ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_IER , AR_IER_ENABLE ) ;
if ( ! AR_SREV_9100 ( ah ) ) {
REG_WRITE ( ah , AR_INTR_ASYNC_ENABLE ,
AR_INTR_MAC_IRQ ) ;
REG_WRITE ( ah , AR_INTR_ASYNC_MASK , AR_INTR_MAC_IRQ ) ;
REG_WRITE ( ah , AR_INTR_SYNC_ENABLE ,
AR_INTR_SYNC_DEFAULT ) ;
REG_WRITE ( ah , AR_INTR_SYNC_MASK ,
AR_INTR_SYNC_DEFAULT ) ;
}
DPRINTF ( ah - > ah_sc , ATH_DBG_INTERRUPT , " AR_IMR 0x%x IER 0x%x \n " ,
REG_READ ( ah , AR_IMR ) , REG_READ ( ah , AR_IER ) ) ;
}
return omask ;
}
2008-10-29 10:16:30 +05:30
/*******************/
/* Beacon Handling */
/*******************/
2009-02-09 13:27:12 +05:30
void ath9k_hw_beaconinit ( struct ath_hw * ah , u32 next_beacon , u32 beacon_period )
2008-08-04 00:16:41 -07:00
{
int flags = 0 ;
2009-02-09 13:27:12 +05:30
ah - > ah_beaconInterval = beacon_period ;
2008-08-04 00:16:41 -07:00
switch ( ah - > ah_opmode ) {
2008-12-01 13:38:55 -08:00
case NL80211_IFTYPE_STATION :
case NL80211_IFTYPE_MONITOR :
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_NEXT_TBTT_TIMER , TU_TO_USEC ( next_beacon ) ) ;
REG_WRITE ( ah , AR_NEXT_DMA_BEACON_ALERT , 0xffff ) ;
REG_WRITE ( ah , AR_NEXT_SWBA , 0x7ffff ) ;
flags | = AR_TBTT_TIMER_EN ;
break ;
2008-12-01 13:38:55 -08:00
case NL80211_IFTYPE_ADHOC :
2008-08-04 00:16:41 -07:00
REG_SET_BIT ( ah , AR_TXCFG ,
AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY ) ;
REG_WRITE ( ah , AR_NEXT_NDP_TIMER ,
TU_TO_USEC ( next_beacon +
2009-02-09 13:27:12 +05:30
( ah - > ah_atimWindow ? ah - >
2008-08-04 00:16:41 -07:00
ah_atimWindow : 1 ) ) ) ;
flags | = AR_NDP_TIMER_EN ;
2008-12-01 13:38:55 -08:00
case NL80211_IFTYPE_AP :
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_NEXT_TBTT_TIMER , TU_TO_USEC ( next_beacon ) ) ;
REG_WRITE ( ah , AR_NEXT_DMA_BEACON_ALERT ,
TU_TO_USEC ( next_beacon -
ah - > ah_config .
2008-08-07 10:52:38 +05:30
dma_beacon_response_time ) ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_NEXT_SWBA ,
TU_TO_USEC ( next_beacon -
ah - > ah_config .
2008-08-07 10:52:38 +05:30
sw_beacon_response_time ) ) ;
2008-08-04 00:16:41 -07:00
flags | =
AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN ;
break ;
2008-12-01 13:38:55 -08:00
default :
DPRINTF ( ah - > ah_sc , ATH_DBG_BEACON ,
" %s: unsupported opmode: %d \n " ,
__func__ , ah - > ah_opmode ) ;
return ;
break ;
2008-08-04 00:16:41 -07:00
}
REG_WRITE ( ah , AR_BEACON_PERIOD , TU_TO_USEC ( beacon_period ) ) ;
REG_WRITE ( ah , AR_DMA_BEACON_PERIOD , TU_TO_USEC ( beacon_period ) ) ;
REG_WRITE ( ah , AR_SWBA_PERIOD , TU_TO_USEC ( beacon_period ) ) ;
REG_WRITE ( ah , AR_NDP_PERIOD , TU_TO_USEC ( beacon_period ) ) ;
beacon_period & = ~ ATH9K_BEACON_ENA ;
if ( beacon_period & ATH9K_BEACON_RESET_TSF ) {
beacon_period & = ~ ATH9K_BEACON_RESET_TSF ;
ath9k_hw_reset_tsf ( ah ) ;
}
REG_SET_BIT ( ah , AR_TIMER_MODE , flags ) ;
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_set_sta_beacon_timers ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
const struct ath9k_beacon_state * bs )
2008-08-04 00:16:41 -07:00
{
u32 nextTbtt , beaconintval , dtimperiod , beacontimeout ;
2008-08-07 10:52:38 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > ah_caps ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_NEXT_TBTT_TIMER , TU_TO_USEC ( bs - > bs_nexttbtt ) ) ;
REG_WRITE ( ah , AR_BEACON_PERIOD ,
TU_TO_USEC ( bs - > bs_intval & ATH9K_BEACON_PERIOD ) ) ;
REG_WRITE ( ah , AR_DMA_BEACON_PERIOD ,
TU_TO_USEC ( bs - > bs_intval & ATH9K_BEACON_PERIOD ) ) ;
REG_RMW_FIELD ( ah , AR_RSSI_THR ,
AR_RSSI_THR_BM_THR , bs - > bs_bmissthreshold ) ;
beaconintval = bs - > bs_intval & ATH9K_BEACON_PERIOD ;
if ( bs - > bs_sleepduration > beaconintval )
beaconintval = bs - > bs_sleepduration ;
dtimperiod = bs - > bs_dtimperiod ;
if ( bs - > bs_sleepduration > dtimperiod )
dtimperiod = bs - > bs_sleepduration ;
if ( beaconintval = = dtimperiod )
nextTbtt = bs - > bs_nextdtim ;
else
nextTbtt = bs - > bs_nexttbtt ;
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_BEACON , " next DTIM %d \n " , bs - > bs_nextdtim ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_BEACON , " next beacon %d \n " , nextTbtt ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_BEACON , " beacon period %d \n " , beaconintval ) ;
DPRINTF ( ah - > ah_sc , ATH_DBG_BEACON , " DTIM period %d \n " , dtimperiod ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_NEXT_DTIM ,
TU_TO_USEC ( bs - > bs_nextdtim - SLEEP_SLOP ) ) ;
REG_WRITE ( ah , AR_NEXT_TIM , TU_TO_USEC ( nextTbtt - SLEEP_SLOP ) ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_SLEEP1 ,
SM ( ( CAB_TIMEOUT_VAL < < 3 ) , AR_SLEEP1_CAB_TIMEOUT )
| AR_SLEEP1_ASSUME_DTIM ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( pCap - > hw_caps & ATH9K_HW_CAP_AUTOSLEEP )
beacontimeout = ( BEACON_TIMEOUT_VAL < < 3 ) ;
else
beacontimeout = MIN_BEACON_TIMEOUT_VAL ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_SLEEP2 ,
SM ( beacontimeout , AR_SLEEP2_BEACON_TIMEOUT ) ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_TIM_PERIOD , TU_TO_USEC ( beaconintval ) ) ;
REG_WRITE ( ah , AR_DTIM_PERIOD , TU_TO_USEC ( dtimperiod ) ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_SET_BIT ( ah , AR_TIMER_MODE ,
AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
AR_DTIM_TIMER_EN ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
/*******************/
/* HW Capabilities */
/*******************/
2009-02-09 13:27:12 +05:30
bool ath9k_hw_fill_cap_info ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-08-07 10:52:38 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > ah_caps ;
2008-10-29 10:16:30 +05:30
u16 capField = 0 , eeval ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
eeval = ath9k_hw_get_eeprom ( ah , EEP_REG_0 ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:08 +05:30
ah - > regulatory . current_rd = eeval ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
eeval = ath9k_hw_get_eeprom ( ah , EEP_REG_1 ) ;
2009-02-09 13:27:08 +05:30
ah - > regulatory . current_rd_ext = eeval ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
capField = ath9k_hw_get_eeprom ( ah , EEP_OP_CAP ) ;
2008-12-01 13:38:55 -08:00
if ( ah - > ah_opmode ! = NL80211_IFTYPE_AP & &
2009-02-09 13:27:06 +05:30
ah - > hw_version . subvendorid = = AR_SUBVENDOR_ID_NEW_A ) {
2009-02-09 13:27:08 +05:30
if ( ah - > regulatory . current_rd = = 0x64 | |
ah - > regulatory . current_rd = = 0x65 )
ah - > regulatory . current_rd + = 5 ;
else if ( ah - > regulatory . current_rd = = 0x41 )
ah - > regulatory . current_rd = 0x43 ;
2008-10-29 10:16:30 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_REGULATORY ,
2009-02-09 13:27:08 +05:30
" regdomain mapped to 0x%x \n " , ah - > regulatory . current_rd ) ;
2008-10-29 10:16:30 +05:30
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
eeval = ath9k_hw_get_eeprom ( ah , EEP_OP_MODE ) ;
bitmap_zero ( pCap - > wireless_modes , ATH9K_MODE_MAX ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( eeval & AR5416_OPFLAGS_11A ) {
set_bit ( ATH9K_MODE_11A , pCap - > wireless_modes ) ;
if ( ah - > ah_config . ht_enable ) {
if ( ! ( eeval & AR5416_OPFLAGS_N_5G_HT20 ) )
set_bit ( ATH9K_MODE_11NA_HT20 ,
pCap - > wireless_modes ) ;
if ( ! ( eeval & AR5416_OPFLAGS_N_5G_HT40 ) ) {
set_bit ( ATH9K_MODE_11NA_HT40PLUS ,
pCap - > wireless_modes ) ;
set_bit ( ATH9K_MODE_11NA_HT40MINUS ,
pCap - > wireless_modes ) ;
}
2008-08-04 00:16:41 -07:00
}
}
2008-10-29 10:16:30 +05:30
if ( eeval & AR5416_OPFLAGS_11G ) {
set_bit ( ATH9K_MODE_11B , pCap - > wireless_modes ) ;
set_bit ( ATH9K_MODE_11G , pCap - > wireless_modes ) ;
if ( ah - > ah_config . ht_enable ) {
if ( ! ( eeval & AR5416_OPFLAGS_N_2G_HT20 ) )
set_bit ( ATH9K_MODE_11NG_HT20 ,
pCap - > wireless_modes ) ;
if ( ! ( eeval & AR5416_OPFLAGS_N_2G_HT40 ) ) {
set_bit ( ATH9K_MODE_11NG_HT40PLUS ,
pCap - > wireless_modes ) ;
set_bit ( ATH9K_MODE_11NG_HT40MINUS ,
pCap - > wireless_modes ) ;
}
}
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
pCap - > tx_chainmask = ath9k_hw_get_eeprom ( ah , EEP_TX_MASK ) ;
if ( ( ah - > ah_isPciExpress )
| | ( eeval & AR5416_OPFLAGS_11A ) ) {
pCap - > rx_chainmask =
ath9k_hw_get_eeprom ( ah , EEP_RX_MASK ) ;
2008-08-04 00:16:41 -07:00
} else {
2008-10-29 10:16:30 +05:30
pCap - > rx_chainmask =
( ath9k_hw_gpio_get ( ah , 0 ) ) ? 0x5 : 0x7 ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:06 +05:30
if ( ! ( AR_SREV_9280 ( ah ) & & ( ah - > hw_version . macRev = = 0 ) ) )
2009-02-09 13:27:12 +05:30
ah - > ah_miscMode | = AR_PCU_MIC_NEW_LOC_ENA ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
pCap - > low_2ghz_chan = 2312 ;
pCap - > high_2ghz_chan = 2732 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
pCap - > low_5ghz_chan = 4920 ;
pCap - > high_5ghz_chan = 6100 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
pCap - > hw_caps & = ~ ATH9K_HW_CAP_CIPHER_CKIP ;
pCap - > hw_caps | = ATH9K_HW_CAP_CIPHER_TKIP ;
pCap - > hw_caps | = ATH9K_HW_CAP_CIPHER_AESCCM ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
pCap - > hw_caps & = ~ ATH9K_HW_CAP_MIC_CKIP ;
pCap - > hw_caps | = ATH9K_HW_CAP_MIC_TKIP ;
pCap - > hw_caps | = ATH9K_HW_CAP_MIC_AESCCM ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
pCap - > hw_caps | = ATH9K_HW_CAP_CHAN_SPREAD ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( ah - > ah_config . ht_enable )
pCap - > hw_caps | = ATH9K_HW_CAP_HT ;
else
pCap - > hw_caps & = ~ ATH9K_HW_CAP_HT ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
pCap - > hw_caps | = ATH9K_HW_CAP_GTT ;
pCap - > hw_caps | = ATH9K_HW_CAP_VEOL ;
pCap - > hw_caps | = ATH9K_HW_CAP_BSSIDMASK ;
pCap - > hw_caps & = ~ ATH9K_HW_CAP_MCAST_KEYSEARCH ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( capField & AR_EEPROM_EEPCAP_MAXQCU )
pCap - > total_queues =
MS ( capField , AR_EEPROM_EEPCAP_MAXQCU ) ;
else
pCap - > total_queues = ATH9K_NUM_TX_QUEUES ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( capField & AR_EEPROM_EEPCAP_KC_ENTRIES )
pCap - > keycache_size =
1 < < MS ( capField , AR_EEPROM_EEPCAP_KC_ENTRIES ) ;
else
pCap - > keycache_size = AR_KEYTABLE_SIZE ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
pCap - > hw_caps | = ATH9K_HW_CAP_FASTCC ;
pCap - > num_mr_retries = 4 ;
pCap - > tx_triglevel_max = MAX_TX_FIFO_THRESHOLD ;
2008-08-04 00:16:41 -07:00
2008-12-24 18:03:58 +05:30
if ( AR_SREV_9285_10_OR_LATER ( ah ) )
pCap - > num_gpio_pins = AR9285_NUM_GPIO ;
else if ( AR_SREV_9280_10_OR_LATER ( ah ) )
2008-10-29 10:16:30 +05:30
pCap - > num_gpio_pins = AR928X_NUM_GPIO ;
else
pCap - > num_gpio_pins = AR_NUM_GPIO ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
pCap - > hw_caps | = ATH9K_HW_CAP_WOW ;
pCap - > hw_caps | = ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT ;
} else {
pCap - > hw_caps & = ~ ATH9K_HW_CAP_WOW ;
pCap - > hw_caps & = ~ ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9160_10_OR_LATER ( ah ) | | AR_SREV_9100 ( ah ) ) {
pCap - > hw_caps | = ATH9K_HW_CAP_CST ;
pCap - > rts_aggr_limit = ATH_AMPDU_LIMIT_MAX ;
} else {
pCap - > rts_aggr_limit = ( 8 * 1024 ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
pCap - > hw_caps | = ATH9K_HW_CAP_ENHANCEDPM ;
2008-11-13 18:00:02 +05:30
# if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
2008-10-29 10:16:30 +05:30
ah - > ah_rfsilent = ath9k_hw_get_eeprom ( ah , EEP_RF_SILENT ) ;
if ( ah - > ah_rfsilent & EEP_RFSILENT_ENABLED ) {
ah - > ah_rfkill_gpio =
MS ( ah - > ah_rfsilent , EEP_RFSILENT_GPIO_SEL ) ;
ah - > ah_rfkill_polarity =
MS ( ah - > ah_rfsilent , EEP_RFSILENT_POLARITY ) ;
pCap - > hw_caps | = ATH9K_HW_CAP_RFSILENT ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
# endif
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:06 +05:30
if ( ( ah - > hw_version . macVersion = = AR_SREV_VERSION_5416_PCI ) | |
( ah - > hw_version . macVersion = = AR_SREV_VERSION_5416_PCIE ) | |
( ah - > hw_version . macVersion = = AR_SREV_VERSION_9160 ) | |
( ah - > hw_version . macVersion = = AR_SREV_VERSION_9100 ) | |
( ah - > hw_version . macVersion = = AR_SREV_VERSION_9280 ) )
2008-10-29 10:16:30 +05:30
pCap - > hw_caps & = ~ ATH9K_HW_CAP_AUTOSLEEP ;
2008-08-04 00:16:41 -07:00
else
2008-10-29 10:16:30 +05:30
pCap - > hw_caps | = ATH9K_HW_CAP_AUTOSLEEP ;
2008-08-04 00:16:41 -07:00
2008-12-08 19:43:48 +05:30
if ( AR_SREV_9280 ( ah ) | | AR_SREV_9285 ( ah ) )
2008-10-29 10:16:30 +05:30
pCap - > hw_caps & = ~ ATH9K_HW_CAP_4KB_SPLITTRANS ;
else
pCap - > hw_caps | = ATH9K_HW_CAP_4KB_SPLITTRANS ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:08 +05:30
if ( ah - > regulatory . current_rd_ext & ( 1 < < REG_EXT_JAPAN_MIDBAND ) ) {
2008-10-29 10:16:30 +05:30
pCap - > reg_cap =
AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
AR_EEPROM_EEREGCAP_EN_KK_U2 |
AR_EEPROM_EEREGCAP_EN_KK_MIDBAND ;
2008-08-04 00:16:41 -07:00
} else {
2008-10-29 10:16:30 +05:30
pCap - > reg_cap =
AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
pCap - > reg_cap | = AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND ;
pCap - > num_antcfg_5ghz =
2008-12-08 19:43:49 +05:30
ath9k_hw_get_num_ant_config ( ah , ATH9K_HAL_FREQ_BAND_5GHZ ) ;
2008-10-29 10:16:30 +05:30
pCap - > num_antcfg_2ghz =
2008-12-08 19:43:49 +05:30
ath9k_hw_get_num_ant_config ( ah , ATH9K_HAL_FREQ_BAND_2GHZ ) ;
2008-08-04 00:16:41 -07:00
2009-01-10 17:07:09 +05:30
if ( AR_SREV_9280_10_OR_LATER ( ah ) & & btcoex_enable ) {
2009-01-02 15:35:46 +05:30
pCap - > hw_caps | = ATH9K_HW_CAP_BT_COEX ;
ah - > ah_btactive_gpio = 6 ;
ah - > ah_wlanactive_gpio = 5 ;
}
2008-10-29 10:16:30 +05:30
return true ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_getcapability ( struct ath_hw * ah , enum ath9k_capability_type type ,
2008-10-29 10:16:30 +05:30
u32 capability , u32 * result )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
const struct ath9k_hw_capabilities * pCap = & ah - > ah_caps ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
switch ( type ) {
case ATH9K_CAP_CIPHER :
switch ( capability ) {
case ATH9K_CIPHER_AES_CCM :
case ATH9K_CIPHER_AES_OCB :
case ATH9K_CIPHER_TKIP :
case ATH9K_CIPHER_WEP :
case ATH9K_CIPHER_MIC :
case ATH9K_CIPHER_CLR :
return true ;
default :
return false ;
}
case ATH9K_CAP_TKIP_MIC :
switch ( capability ) {
case 0 :
return true ;
case 1 :
2009-02-09 13:27:12 +05:30
return ( ah - > ah_staId1Defaults &
2008-10-29 10:16:30 +05:30
AR_STA_ID1_CRPT_MIC_ENABLE ) ? true :
false ;
}
case ATH9K_CAP_TKIP_SPLIT :
2009-02-09 13:27:12 +05:30
return ( ah - > ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA ) ?
2008-10-29 10:16:30 +05:30
false : true ;
case ATH9K_CAP_WME_TKIPMIC :
return 0 ;
case ATH9K_CAP_PHYCOUNTERS :
2009-02-09 13:27:12 +05:30
return ah - > ah_hasHwPhyCounters ? 0 : - ENXIO ;
2008-10-29 10:16:30 +05:30
case ATH9K_CAP_DIVERSITY :
return ( REG_READ ( ah , AR_PHY_CCK_DETECT ) &
AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV ) ?
true : false ;
case ATH9K_CAP_PHYDIAG :
return true ;
case ATH9K_CAP_MCAST_KEYSRCH :
switch ( capability ) {
case 0 :
return true ;
case 1 :
if ( REG_READ ( ah , AR_STA_ID1 ) & AR_STA_ID1_ADHOC ) {
return false ;
} else {
2009-02-09 13:27:12 +05:30
return ( ah - > ah_staId1Defaults &
2008-10-29 10:16:30 +05:30
AR_STA_ID1_MCAST_KSRCH ) ? true :
false ;
}
}
return false ;
case ATH9K_CAP_TSF_ADJUST :
2009-02-09 13:27:12 +05:30
return ( ah - > ah_miscMode & AR_PCU_TX_ADD_TSF ) ?
2008-10-29 10:16:30 +05:30
true : false ;
case ATH9K_CAP_RFSILENT :
if ( capability = = 3 )
return false ;
case ATH9K_CAP_ANT_CFG_2GHZ :
* result = pCap - > num_antcfg_2ghz ;
return true ;
case ATH9K_CAP_ANT_CFG_5GHZ :
* result = pCap - > num_antcfg_5ghz ;
return true ;
case ATH9K_CAP_TXPOW :
switch ( capability ) {
case 0 :
return 0 ;
case 1 :
2009-02-09 13:27:08 +05:30
* result = ah - > regulatory . power_limit ;
2008-10-29 10:16:30 +05:30
return 0 ;
case 2 :
2009-02-09 13:27:08 +05:30
* result = ah - > regulatory . max_power_level ;
2008-10-29 10:16:30 +05:30
return 0 ;
case 3 :
2009-02-09 13:27:08 +05:30
* result = ah - > regulatory . tp_scale ;
2008-10-29 10:16:30 +05:30
return 0 ;
}
return false ;
default :
return false ;
2008-08-04 00:16:41 -07:00
}
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_setcapability ( struct ath_hw * ah , enum ath9k_capability_type type ,
2008-10-29 10:16:30 +05:30
u32 capability , u32 setting , int * status )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 v ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
switch ( type ) {
case ATH9K_CAP_TKIP_MIC :
if ( setting )
2009-02-09 13:27:12 +05:30
ah - > ah_staId1Defaults | =
2008-10-29 10:16:30 +05:30
AR_STA_ID1_CRPT_MIC_ENABLE ;
else
2009-02-09 13:27:12 +05:30
ah - > ah_staId1Defaults & =
2008-10-29 10:16:30 +05:30
~ AR_STA_ID1_CRPT_MIC_ENABLE ;
return true ;
case ATH9K_CAP_DIVERSITY :
v = REG_READ ( ah , AR_PHY_CCK_DETECT ) ;
if ( setting )
v | = AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV ;
else
v & = ~ AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV ;
REG_WRITE ( ah , AR_PHY_CCK_DETECT , v ) ;
return true ;
case ATH9K_CAP_MCAST_KEYSRCH :
if ( setting )
2009-02-09 13:27:12 +05:30
ah - > ah_staId1Defaults | = AR_STA_ID1_MCAST_KSRCH ;
2008-10-29 10:16:30 +05:30
else
2009-02-09 13:27:12 +05:30
ah - > ah_staId1Defaults & = ~ AR_STA_ID1_MCAST_KSRCH ;
2008-10-29 10:16:30 +05:30
return true ;
case ATH9K_CAP_TSF_ADJUST :
if ( setting )
2009-02-09 13:27:12 +05:30
ah - > ah_miscMode | = AR_PCU_TX_ADD_TSF ;
2008-10-29 10:16:30 +05:30
else
2009-02-09 13:27:12 +05:30
ah - > ah_miscMode & = ~ AR_PCU_TX_ADD_TSF ;
2008-10-29 10:16:30 +05:30
return true ;
default :
return false ;
2008-08-04 00:16:41 -07:00
}
}
2008-10-29 10:16:30 +05:30
/****************************/
/* GPIO / RFKILL / Antennae */
/****************************/
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
static void ath9k_hw_gpio_cfg_output_mux ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
u32 gpio , u32 type )
{
int addr ;
u32 gpio_shift , tmp ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( gpio > 11 )
addr = AR_GPIO_OUTPUT_MUX3 ;
else if ( gpio > 5 )
addr = AR_GPIO_OUTPUT_MUX2 ;
else
addr = AR_GPIO_OUTPUT_MUX1 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
gpio_shift = ( gpio % 6 ) * 5 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9280_20_OR_LATER ( ah )
| | ( addr ! = AR_GPIO_OUTPUT_MUX1 ) ) {
REG_RMW ( ah , addr , ( type < < gpio_shift ) ,
( 0x1f < < gpio_shift ) ) ;
2008-08-04 00:16:41 -07:00
} else {
2008-10-29 10:16:30 +05:30
tmp = REG_READ ( ah , addr ) ;
tmp = ( ( tmp & 0x1F0 ) < < 1 ) | ( tmp & ~ 0x1F0 ) ;
tmp & = ~ ( 0x1f < < gpio_shift ) ;
tmp | = ( type < < gpio_shift ) ;
REG_WRITE ( ah , addr , tmp ) ;
2008-08-04 00:16:41 -07:00
}
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_cfg_gpio_input ( struct ath_hw * ah , u32 gpio )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 gpio_shift ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
ASSERT ( gpio < ah - > ah_caps . num_gpio_pins ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
gpio_shift = gpio < < 1 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_RMW ( ah ,
AR_GPIO_OE_OUT ,
( AR_GPIO_OE_OUT_DRV_NO < < gpio_shift ) ,
( AR_GPIO_OE_OUT_DRV < < gpio_shift ) ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
u32 ath9k_hw_gpio_get ( struct ath_hw * ah , u32 gpio )
2008-08-04 00:16:41 -07:00
{
2008-12-24 18:03:58 +05:30
# define MS_REG_READ(x, y) \
( MS ( REG_READ ( ah , AR_GPIO_IN_OUT ) , x # # _GPIO_IN_VAL ) & ( AR_GPIO_BIT ( y ) ) )
2008-10-29 10:16:30 +05:30
if ( gpio > = ah - > ah_caps . num_gpio_pins )
return 0xffffffff ;
2008-08-04 00:16:41 -07:00
2008-12-24 18:03:58 +05:30
if ( AR_SREV_9285_10_OR_LATER ( ah ) )
return MS_REG_READ ( AR9285 , gpio ) ! = 0 ;
else if ( AR_SREV_9280_10_OR_LATER ( ah ) )
return MS_REG_READ ( AR928X , gpio ) ! = 0 ;
else
return MS_REG_READ ( AR , gpio ) ! = 0 ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_cfg_output ( struct ath_hw * ah , u32 gpio ,
2008-10-29 10:16:30 +05:30
u32 ah_signal_type )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 gpio_shift ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
ath9k_hw_gpio_cfg_output_mux ( ah , gpio , ah_signal_type ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
gpio_shift = 2 * gpio ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_RMW ( ah ,
AR_GPIO_OE_OUT ,
( AR_GPIO_OE_OUT_DRV_ALL < < gpio_shift ) ,
( AR_GPIO_OE_OUT_DRV < < gpio_shift ) ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_set_gpio ( struct ath_hw * ah , u32 gpio , u32 val )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
REG_RMW ( ah , AR_GPIO_IN_OUT , ( ( val & 1 ) < < gpio ) ,
AR_GPIO_BIT ( gpio ) ) ;
2008-08-04 00:16:41 -07:00
}
2008-11-13 18:00:02 +05:30
# if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
2009-02-09 13:27:12 +05:30
void ath9k_enable_rfkill ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
REG_SET_BIT ( ah , AR_GPIO_INPUT_EN_VAL ,
AR_GPIO_INPUT_EN_VAL_RFSILENT_BB ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_CLR_BIT ( ah , AR_GPIO_INPUT_MUX2 ,
AR_GPIO_INPUT_MUX2_RFSILENT ) ;
ath9k_hw_cfg_gpio_input ( ah , ah - > ah_rfkill_gpio ) ;
REG_SET_BIT ( ah , AR_PHY_TEST , RFSILENT_BB ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
# endif
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
u32 ath9k_hw_getdefantenna ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
return REG_READ ( ah , AR_DEF_ANTENNA ) & 0x7 ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_setantenna ( struct ath_hw * ah , u32 antenna )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_DEF_ANTENNA , ( antenna & 0x7 ) ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_setantennaswitch ( struct ath_hw * ah ,
2008-10-29 10:16:30 +05:30
enum ath9k_ant_setting settings ,
struct ath9k_channel * chan ,
u8 * tx_chainmask ,
u8 * rx_chainmask ,
u8 * antenna_cfgd )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
static u8 tx_chainmask_cfg , rx_chainmask_cfg ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9280 ( ah ) ) {
if ( ! tx_chainmask_cfg ) {
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tx_chainmask_cfg = * tx_chainmask ;
rx_chainmask_cfg = * rx_chainmask ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
switch ( settings ) {
case ATH9K_ANT_FIXED_A :
* tx_chainmask = ATH9K_ANTENNA0_CHAINMASK ;
* rx_chainmask = ATH9K_ANTENNA0_CHAINMASK ;
* antenna_cfgd = true ;
break ;
case ATH9K_ANT_FIXED_B :
if ( ah - > ah_caps . tx_chainmask >
ATH9K_ANTENNA1_CHAINMASK ) {
* tx_chainmask = ATH9K_ANTENNA1_CHAINMASK ;
}
* rx_chainmask = ATH9K_ANTENNA1_CHAINMASK ;
* antenna_cfgd = true ;
break ;
case ATH9K_ANT_VARIABLE :
* tx_chainmask = tx_chainmask_cfg ;
* rx_chainmask = rx_chainmask_cfg ;
* antenna_cfgd = true ;
break ;
default :
break ;
}
} else {
2009-02-09 13:27:12 +05:30
ah - > ah_diversityControl = settings ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
return true ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
/*********************/
/* General Operation */
/*********************/
2009-02-09 13:27:12 +05:30
u32 ath9k_hw_getrxfilter ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 bits = REG_READ ( ah , AR_RX_FILTER ) ;
u32 phybits = REG_READ ( ah , AR_PHY_ERR ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( phybits & AR_PHY_ERR_RADAR )
bits | = ATH9K_RX_FILTER_PHYRADAR ;
if ( phybits & ( AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING ) )
bits | = ATH9K_RX_FILTER_PHYERR ;
2008-08-14 13:26:55 +05:30
2008-10-29 10:16:30 +05:30
return bits ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_setrxfilter ( struct ath_hw * ah , u32 bits )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u32 phybits ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_RX_FILTER , ( bits & 0xffff ) | AR_RX_COMPR_BAR ) ;
phybits = 0 ;
if ( bits & ATH9K_RX_FILTER_PHYRADAR )
phybits | = AR_PHY_ERR_RADAR ;
if ( bits & ATH9K_RX_FILTER_PHYERR )
phybits | = AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING ;
REG_WRITE ( ah , AR_PHY_ERR , phybits ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( phybits )
REG_WRITE ( ah , AR_RXCFG ,
REG_READ ( ah , AR_RXCFG ) | AR_RXCFG_ZLFDMA ) ;
else
REG_WRITE ( ah , AR_RXCFG ,
REG_READ ( ah , AR_RXCFG ) & ~ AR_RXCFG_ZLFDMA ) ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
bool ath9k_hw_phy_disable ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
return ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_WARM ) ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
bool ath9k_hw_disable ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
if ( ! ath9k_hw_setpower ( ah , ATH9K_PM_AWAKE ) )
return false ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_COLD ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
bool ath9k_hw_set_txpowerlimit ( struct ath_hw * ah , u32 limit )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
struct ath9k_channel * chan = ah - > ah_curchan ;
2009-01-22 15:16:48 -08:00
struct ieee80211_channel * channel = chan - > chan ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:08 +05:30
ah - > regulatory . power_limit = min ( limit , ( u32 ) MAX_RATE_POWER ) ;
2008-10-03 15:45:27 -07:00
2008-10-29 10:16:30 +05:30
if ( ath9k_hw_set_txpower ( ah , chan ,
ath9k_regd_get_ctl ( ah , chan ) ,
2009-01-22 15:16:48 -08:00
channel - > max_antenna_gain * 2 ,
channel - > max_power * 2 ,
2008-10-29 10:16:30 +05:30
min ( ( u32 ) MAX_RATE_POWER ,
2009-02-09 13:27:08 +05:30
( u32 ) ah - > regulatory . power_limit ) ) ! = 0 )
2008-10-03 15:45:27 -07:00
return false ;
2008-10-29 10:16:30 +05:30
2008-10-03 15:45:27 -07:00
return true ;
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_setmac ( struct ath_hw * ah , const u8 * mac )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:10 +05:30
memcpy ( ah - > macaddr , mac , ETH_ALEN ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_setopmode ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
ath9k_hw_set_operating_mode ( ah , ah - > ah_opmode ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_setmcastfilter ( struct ath_hw * ah , u32 filter0 , u32 filter1 )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_MCAST_FIL0 , filter0 ) ;
REG_WRITE ( ah , AR_MCAST_FIL1 , filter1 ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:10 +05:30
void ath9k_hw_setbssidmask ( struct ath_softc * sc )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:10 +05:30
REG_WRITE ( sc - > sc_ah , AR_BSSMSKL , get_unaligned_le32 ( sc - > bssidmask ) ) ;
REG_WRITE ( sc - > sc_ah , AR_BSSMSKU , get_unaligned_le16 ( sc - > bssidmask + 4 ) ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:10 +05:30
void ath9k_hw_write_associd ( struct ath_softc * sc )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:10 +05:30
REG_WRITE ( sc - > sc_ah , AR_BSS_ID0 , get_unaligned_le32 ( sc - > curbssid ) ) ;
REG_WRITE ( sc - > sc_ah , AR_BSS_ID1 , get_unaligned_le16 ( sc - > curbssid + 4 ) |
( ( sc - > curaid & 0x3fff ) < < AR_BSS_ID1_AID_S ) ) ;
2008-08-04 00:16:41 -07:00
}
2009-02-09 13:27:12 +05:30
u64 ath9k_hw_gettsf64 ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u64 tsf ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
tsf = REG_READ ( ah , AR_TSF_U32 ) ;
tsf = ( tsf < < 32 ) | REG_READ ( ah , AR_TSF_L32 ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return tsf ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
void ath9k_hw_settsf64 ( struct ath_hw * ah , u64 tsf64 )
2009-01-23 05:44:21 +01:00
{
REG_WRITE ( ah , AR_TSF_L32 , 0x00000000 ) ;
REG_WRITE ( ah , AR_TSF_U32 , ( tsf64 > > 32 ) & 0xffffffff ) ;
REG_WRITE ( ah , AR_TSF_L32 , tsf64 & 0xffffffff ) ;
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_reset_tsf ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
int count ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
count = 0 ;
while ( REG_READ ( ah , AR_SLP32_MODE ) & AR_SLP32_TSF_WRITE_STATUS ) {
count + + ;
if ( count > 10 ) {
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET ,
2008-11-28 22:18:05 +05:30
" AR_SLP32_TSF_WRITE_STATUS limit exceeded \n " ) ;
2008-10-29 10:16:30 +05:30
break ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
udelay ( 10 ) ;
}
REG_WRITE ( ah , AR_RESET_TSF , AR_RESET_TSF_ONCE ) ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
bool ath9k_hw_set_tsfadjust ( struct ath_hw * ah , u32 setting )
2008-10-29 10:16:30 +05:30
{
if ( setting )
2009-02-09 13:27:12 +05:30
ah - > ah_miscMode | = AR_PCU_TX_ADD_TSF ;
2008-10-29 10:16:30 +05:30
else
2009-02-09 13:27:12 +05:30
ah - > ah_miscMode & = ~ AR_PCU_TX_ADD_TSF ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return true ;
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:12 +05:30
bool ath9k_hw_setslottime ( struct ath_hw * ah , u32 us )
2008-10-29 10:16:30 +05:30
{
if ( us < ATH9K_SLOT_TIME_9 | | us > ath9k_hw_mac_to_usec ( ah , 0xffff ) ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( ah - > ah_sc , ATH_DBG_RESET , " bad slot time %u \n " , us ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_slottime = ( u32 ) - 1 ;
2008-10-29 10:16:30 +05:30
return false ;
} else {
REG_WRITE ( ah , AR_D_GBL_IFS_SLOT , ath9k_hw_mac_to_clks ( ah , us ) ) ;
2009-02-09 13:27:12 +05:30
ah - > ah_slottime = us ;
2008-10-29 10:16:30 +05:30
return true ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:16:30 +05:30
}
2009-02-09 13:27:12 +05:30
void ath9k_hw_set11nmac2040 ( struct ath_hw * ah , enum ath9k_ht_macmode mode )
2008-10-29 10:16:30 +05:30
{
u32 macmode ;
if ( mode = = ATH9K_HT_MACMODE_2040 & &
! ah - > ah_config . cwm_ignore_extcca )
macmode = AR_2040_JOINED_RX_CLEAR ;
else
macmode = 0 ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_2040_MODE , macmode ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-02 15:35:46 +05:30
/***************************/
/* Bluetooth Coexistence */
/***************************/
2009-02-09 13:27:12 +05:30
void ath9k_hw_btcoex_enable ( struct ath_hw * ah )
2009-01-02 15:35:46 +05:30
{
/* connect bt_active to baseband */
REG_CLR_BIT ( ah , AR_GPIO_INPUT_EN_VAL ,
( AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF ) ) ;
REG_SET_BIT ( ah , AR_GPIO_INPUT_EN_VAL ,
AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB ) ;
/* Set input mux for bt_active to gpio pin */
REG_RMW_FIELD ( ah , AR_GPIO_INPUT_MUX1 ,
AR_GPIO_INPUT_MUX1_BT_ACTIVE ,
ah - > ah_btactive_gpio ) ;
/* Configure the desired gpio port for input */
ath9k_hw_cfg_gpio_input ( ah , ah - > ah_btactive_gpio ) ;
/* Configure the desired GPIO port for TX_FRAME output */
ath9k_hw_cfg_output ( ah , ah - > ah_wlanactive_gpio ,
AR_GPIO_OUTPUT_MUX_AS_TX_FRAME ) ;
}