2008-08-04 00:16:41 -07:00
/*
2009-03-13 09:07:23 +05:30
* Copyright ( c ) 2008 - 2009 Atheros Communications Inc .
2008-08-04 00:16:41 -07:00
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
# include <linux/io.h>
# include <asm/unaligned.h>
2009-09-09 02:33:11 -07:00
# include "hw.h"
2009-09-13 23:39:31 -07:00
# include "rc.h"
2008-08-04 00:16:41 -07:00
# include "initvals.h"
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 ) ;
2009-09-13 23:04:44 -07:00
static void ath9k_hw_set_regs ( struct ath_hw * ah , struct ath9k_channel * chan ) ;
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
2009-09-23 23:07:00 -04:00
MODULE_AUTHOR ( " Atheros Communications " ) ;
MODULE_DESCRIPTION ( " Support for Atheros 802.11n wireless LAN cards. " ) ;
MODULE_SUPPORTED_DEVICE ( " Atheros 802.11n WLAN cards " ) ;
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
static int __init ath9k_init ( void )
{
return 0 ;
}
module_init ( ath9k_init ) ;
static void __exit ath9k_exit ( void )
{
return ;
}
module_exit ( ath9k_exit ) ;
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
{
2009-09-13 00:03:27 -07:00
struct ieee80211_conf * conf = & ath9k_hw_common ( ah ) - > hw - > conf ;
2009-02-09 13:27:12 +05:30
2009-02-09 13:27:26 +05:30
if ( ! ah - > curchan ) /* should really check for CCK instead */
2008-12-23 15:58:48 -08:00
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
{
2009-09-13 00:03:27 -07:00
struct ieee80211_conf * conf = & ath9k_hw_common ( ah ) - > 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
{
2009-09-13 00:03:27 -07:00
struct ieee80211_conf * conf = & ath9k_hw_common ( ah ) - > hw - > conf ;
2009-02-09 13:27:12 +05:30
2009-02-09 13:27:26 +05:30
if ( ! ah - > curchan ) /* should really check for CCK instead */
2008-12-23 15:58:48 -08:00
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
{
2009-09-13 00:03:27 -07:00
struct ieee80211_conf * conf = & ath9k_hw_common ( ah ) - > 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-16 13:23:20 +05:30
bool ath9k_hw_wait ( struct ath_hw * ah , u32 reg , u32 mask , u32 val , u32 timeout )
2008-08-04 00:16:41 -07:00
{
int i ;
2009-02-16 13:23:20 +05:30
BUG_ON ( timeout < AH_TIME_QUANTUM ) ;
for ( i = 0 ; i < ( timeout / AH_TIME_QUANTUM ) ; i + + ) {
2008-08-04 00:16:41 -07:00
if ( ( REG_READ ( ah , reg ) & mask ) = = val )
return true ;
udelay ( AH_TIME_QUANTUM ) ;
}
2008-11-28 22:18:05 +05:30
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_ANY ,
" timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x \n " ,
timeout , 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
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_wait ) ;
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
{
2009-02-09 13:27:26 +05:30
struct ath9k_hw_capabilities * pCap = & 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 ,
2009-05-06 02:20:00 -04:00
const 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 :
2009-02-09 13:27:26 +05:30
if ( ah - > curchan & & IS_CHAN_QUARTER_RATE ( ah - > curchan ) ) {
2008-10-29 10:16:30 +05:30
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 ) ;
2009-02-09 13:27:26 +05:30
} else if ( ah - > curchan & &
IS_CHAN_HALF_RATE ( ah - > curchan ) ) {
2008-10-29 10:16:30 +05:30
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 :
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_FATAL ,
" Unknown phy %u (rate ix %u) \n " ,
rates - > info [ rateix ] . phy , rateix ) ;
2008-10-29 10:16:30 +05:30
txTime = 0 ;
break ;
}
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
return txTime ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_computetxtime ) ;
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 ) ;
2009-09-13 22:05:04 -07:00
/* 25 MHz spacing is supported by hw but not on upper layers */
2008-10-29 10:16:30 +05:30
centers - > ext_center =
2009-09-13 22:05:04 -07:00
centers - > synth_center + ( extoff * HT40_CHANNEL_CENTER_SHIFT ) ;
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 ) ;
2009-02-09 13:27:26 +05:30
ah - > is_pciexpress = ( val & AR_SREV_TYPE2_HOST_MODE ) ? 0 : 1 ;
2008-10-29 10:16:30 +05:30
} 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 )
2009-02-09 13:27:26 +05:30
ah - > is_pciexpress = true ;
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 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
{
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" address test failed "
" addr: 0x%08x - wr:0x%08x != "
" rd:0x%08x \n " ,
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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" address test failed "
" addr: 0x%08x - wr:0x%08x != "
" rd:0x%08x \n " ,
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 " ;
2009-07-23 10:59:57 +05:30
case AR5416_DEVID_AR9287_PCI :
case AR5416_DEVID_AR9287_PCIE :
return " Atheros 9287 " ;
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-08-03 12:24:43 -07:00
static void ath9k_hw_init_config ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
int i ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
ah - > config . dma_beacon_response_time = 2 ;
ah - > config . sw_beacon_response_time = 10 ;
ah - > config . additional_swba_backoff = 0 ;
ah - > config . ack_6mb = 0x0 ;
ah - > config . cwm_ignore_extcca = 0 ;
ah - > config . pcie_powersave_enable = 0 ;
ah - > config . pcie_clock_req = 0 ;
ah - > config . pcie_waen = 0 ;
ah - > config . analog_shiftreg = 1 ;
ah - > config . ht_enable = 1 ;
ah - > config . ofdm_trig_low = 200 ;
ah - > config . ofdm_trig_high = 500 ;
ah - > config . cck_trig_high = 200 ;
ah - > config . cck_trig_low = 100 ;
ah - > config . enable_ani = 1 ;
2009-08-13 09:34:32 +05:30
ah - > config . diversity_control = ATH9K_ANT_VARIABLE ;
2009-02-09 13:27:26 +05:30
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 + + ) {
2009-02-09 13:27:26 +05:30
ah - > config . spurchans [ i ] [ 0 ] = AR_NO_SPUR ;
ah - > config . spurchans [ i ] [ 1 ] = AR_NO_SPUR ;
2008-08-04 00:16:41 -07:00
}
2009-03-30 15:28:35 +05:30
ah - > config . intr_mitigation = true ;
2009-03-12 18:18:49 -04:00
/*
* We need this for PCI devices only ( Cardbus , PCI , miniPCI )
* _and_ if on non - uniprocessor systems ( Multiprocessor / HT ) .
* This means we use it for all AR5416 devices , and the few
* minor PCI AR9280 devices out there .
*
* Serialization is required because these devices do not handle
* well the case of two concurrent reads / writes due to the latency
* involved . During one read / write another read / write can be issued
* on another CPU while the previous read / write may still be working
* on our hardware , if we hit this case the hardware poops in a loop .
* We prevent this by serializing reads and writes .
*
* This issue is not present on PCI - Express devices or pre - AR5416
* devices ( legacy , 802.11 abg ) .
*/
if ( num_possible_cpus ( ) > 1 )
2009-03-17 15:01:30 -07:00
ah - > config . serialize_regmode = SER_REG_MODE_AUTO ;
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_init ) ;
2008-08-04 00:16:41 -07:00
2009-08-03 12:24:42 -07:00
static void ath9k_hw_init_defaults ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2009-08-17 18:07:23 -07:00
struct ath_regulatory * regulatory = ath9k_hw_regulatory ( ah ) ;
regulatory - > country_code = CTRY_DEFAULT ;
regulatory - > power_limit = MAX_RATE_POWER ;
regulatory - > tp_scale = ATH9K_TP_SCALE_MAX ;
2009-02-09 13:27:06 +05:30
ah - > hw_version . magic = AR5416_MAGIC ;
ah - > hw_version . subvendorid = 0 ;
2008-08-04 00:16:41 -07:00
ah - > ah_flags = 0 ;
2009-08-03 12:24:37 -07:00
if ( ah - > hw_version . 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:26 +05:30
ah - > atim_window = 0 ;
ah - > sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE ;
ah - > beacon_interval = 100 ;
ah - > enable_32kHz_clock = DONT_USE_32KHZ ;
ah - > slottime = ( u32 ) - 1 ;
ah - > acktimeout = ( u32 ) - 1 ;
ah - > ctstimeout = ( u32 ) - 1 ;
ah - > globaltxtimeout = ( u32 ) - 1 ;
ah - > gbeacon_rate = 0 ;
2008-08-04 00:16:41 -07:00
2009-07-24 17:27:22 +02:00
ah - > power_mode = ATH9K_PM_UNDEFINED ;
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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_FATAL ,
" 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 :
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_FATAL ,
" Radio Chip Rev 0x%02X not supported \n " ,
val & AR_RADIO_SREV_MAJOR ) ;
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
{
2009-09-10 09:22:37 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2008-08-04 00:16:41 -07:00
u32 sum ;
int i ;
u16 eeval ;
sum = 0 ;
for ( i = 0 ; i < 3 ; i + + ) {
2009-02-09 13:27:24 +05:30
eeval = ah - > eep_ops - > get_eeprom ( ah , AR_EEPROM_MAC ( i ) ) ;
2008-08-04 00:16:41 -07:00
sum + = eeval ;
2009-09-10 09:22:37 -07:00
common - > macaddr [ 2 * i ] = eeval > > 8 ;
common - > macaddr [ 2 * i + 1 ] = eeval & 0xff ;
2008-08-04 00:16:41 -07:00
}
2009-03-30 15:28:25 +05:30
if ( sum = = 0 | | sum = = 0xffff * 3 )
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 ;
2009-02-09 13:27:24 +05:30
if ( ah - > eep_ops - > get_eeprom ( ah , EEP_MINOR_REV ) > = AR5416_EEP_MINOR_VER_17 ) {
rxgain_type = ah - > eep_ops - > get_eeprom ( ah , EEP_RXGAIN_TYPE ) ;
2008-11-13 17:58:41 +05:30
if ( rxgain_type = = AR5416_EEP_RXGAIN_13DB_BACKOFF )
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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 {
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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 ;
2009-02-09 13:27:24 +05:30
if ( ah - > eep_ops - > get_eeprom ( ah , EEP_MINOR_REV ) > = AR5416_EEP_MINOR_VER_19 ) {
txgain_type = ah - > eep_ops - > get_eeprom ( ah , EEP_TXGAIN_TYPE ) ;
2008-11-13 17:58:41 +05:30
if ( txgain_type = = AR5416_EEP_TXGAIN_HIGH_POWER )
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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 {
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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-08-03 12:24:46 -07:00
static int ath9k_hw_post_init ( 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
2009-03-30 15:28:25 +05:30
if ( ! ath9k_hw_chip_test ( ah ) )
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 ;
2009-08-03 12:24:46 -07:00
ecode = ath9k_hw_eeprom_init ( ah ) ;
2008-10-29 10:16:30 +05:30
if ( ecode ! = 0 )
return ecode ;
2009-03-13 08:55:55 +05:30
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_CONFIG ,
" Eeprom VER: %d, REV: %d \n " ,
ah - > eep_ops - > get_eeprom_ver ( ah ) ,
ah - > eep_ops - > get_eeprom_rev ( ah ) ) ;
2009-03-13 08:55:55 +05:30
2008-10-29 10:16:30 +05:30
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 ) ;
2009-08-03 12:24:46 -07:00
ath9k_hw_ani_init ( ah ) ;
2008-08-04 00:16:41 -07:00
}
return 0 ;
}
2009-08-03 12:24:39 -07:00
static bool ath9k_hw_devid_supported ( u16 devid )
{
switch ( devid ) {
case AR5416_DEVID_PCI :
case AR5416_DEVID_PCIE :
case AR5416_AR9100_DEVID :
case AR9160_DEVID_PCI :
case AR9280_DEVID_PCI :
case AR9280_DEVID_PCIE :
case AR9285_DEVID_PCIE :
case AR5416_DEVID_AR9287_PCI :
case AR5416_DEVID_AR9287_PCIE :
2009-09-23 23:07:02 -04:00
case AR9271_USB :
2009-08-03 12:24:39 -07:00
return true ;
default :
break ;
}
return false ;
}
2009-08-03 12:24:41 -07:00
static bool ath9k_hw_macversion_supported ( u32 macversion )
{
switch ( macversion ) {
case AR_SREV_VERSION_5416_PCI :
case AR_SREV_VERSION_5416_PCIE :
case AR_SREV_VERSION_9160 :
case AR_SREV_VERSION_9100 :
case AR_SREV_VERSION_9280 :
case AR_SREV_VERSION_9285 :
case AR_SREV_VERSION_9287 :
2009-08-03 23:14:12 -04:00
case AR_SREV_VERSION_9271 :
2009-09-23 23:07:02 -04:00
return true ;
2009-08-03 12:24:41 -07:00
default :
break ;
}
return false ;
}
2009-08-03 12:24:45 -07:00
static void ath9k_hw_init_cal_settings ( struct ath_hw * ah )
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:26 +05:30
ah - > iq_caldata . calData = & iq_cal_single_sample ;
ah - > adcgain_caldata . calData =
2008-10-29 10:16:30 +05:30
& adc_gain_cal_single_sample ;
2009-02-09 13:27:26 +05:30
ah - > adcdc_caldata . calData =
2008-10-29 10:16:30 +05:30
& adc_dc_cal_single_sample ;
2009-02-09 13:27:26 +05:30
ah - > adcdc_calinitdata . calData =
2008-10-29 10:16:30 +05:30
& adc_init_dc_cal ;
} else {
2009-02-09 13:27:26 +05:30
ah - > iq_caldata . calData = & iq_cal_multi_sample ;
ah - > adcgain_caldata . calData =
2008-10-29 10:16:30 +05:30
& adc_gain_cal_multi_sample ;
2009-02-09 13:27:26 +05:30
ah - > adcdc_caldata . calData =
2008-10-29 10:16:30 +05:30
& adc_dc_cal_multi_sample ;
2009-02-09 13:27:26 +05:30
ah - > adcdc_calinitdata . calData =
2008-10-29 10:16:30 +05:30
& adc_init_dc_cal ;
}
2009-02-09 13:27:26 +05:30
ah - > supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL ;
2008-10-29 10:16:30 +05:30
}
2009-08-03 12:24:45 -07:00
}
2008-08-04 00:16:41 -07:00
2009-08-03 12:24:45 -07:00
static void ath9k_hw_init_mode_regs ( struct ath_hw * ah )
{
2009-08-03 23:14:12 -04:00
if ( AR_SREV_9271 ( ah ) ) {
INIT_INI_ARRAY ( & ah - > iniModes , ar9271Modes_9271_1_0 ,
ARRAY_SIZE ( ar9271Modes_9271_1_0 ) , 6 ) ;
INIT_INI_ARRAY ( & ah - > iniCommon , ar9271Common_9271_1_0 ,
ARRAY_SIZE ( ar9271Common_9271_1_0 ) , 2 ) ;
return ;
}
2009-07-23 10:59:57 +05:30
if ( AR_SREV_9287_11_OR_LATER ( ah ) ) {
INIT_INI_ARRAY ( & ah - > iniModes , ar9287Modes_9287_1_1 ,
ARRAY_SIZE ( ar9287Modes_9287_1_1 ) , 6 ) ;
INIT_INI_ARRAY ( & ah - > iniCommon , ar9287Common_9287_1_1 ,
ARRAY_SIZE ( ar9287Common_9287_1_1 ) , 2 ) ;
if ( ah - > config . pcie_clock_req )
INIT_INI_ARRAY ( & ah - > iniPcieSerdes ,
ar9287PciePhy_clkreq_off_L1_9287_1_1 ,
ARRAY_SIZE ( ar9287PciePhy_clkreq_off_L1_9287_1_1 ) , 2 ) ;
else
INIT_INI_ARRAY ( & ah - > iniPcieSerdes ,
ar9287PciePhy_clkreq_always_on_L1_9287_1_1 ,
ARRAY_SIZE ( ar9287PciePhy_clkreq_always_on_L1_9287_1_1 ) ,
2 ) ;
} else if ( AR_SREV_9287_10_OR_LATER ( ah ) ) {
INIT_INI_ARRAY ( & ah - > iniModes , ar9287Modes_9287_1_0 ,
ARRAY_SIZE ( ar9287Modes_9287_1_0 ) , 6 ) ;
INIT_INI_ARRAY ( & ah - > iniCommon , ar9287Common_9287_1_0 ,
ARRAY_SIZE ( ar9287Common_9287_1_0 ) , 2 ) ;
if ( ah - > config . pcie_clock_req )
INIT_INI_ARRAY ( & ah - > iniPcieSerdes ,
ar9287PciePhy_clkreq_off_L1_9287_1_0 ,
ARRAY_SIZE ( ar9287PciePhy_clkreq_off_L1_9287_1_0 ) , 2 ) ;
else
INIT_INI_ARRAY ( & ah - > iniPcieSerdes ,
ar9287PciePhy_clkreq_always_on_L1_9287_1_0 ,
ARRAY_SIZE ( ar9287PciePhy_clkreq_always_on_L1_9287_1_0 ) ,
2 ) ;
} else if ( AR_SREV_9285_12_OR_LATER ( ah ) ) {
2008-08-04 00:16:41 -07:00
2009-03-06 11:24:10 +05:30
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & ah - > iniCommon , ar9285Common_9285_1_2 ,
2008-12-08 19:43:48 +05:30
ARRAY_SIZE ( ar9285Common_9285_1_2 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
if ( ah - > config . pcie_clock_req ) {
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & ah - > iniModes , ar9285Modes_9285 ,
2008-12-08 19:43:48 +05:30
ARRAY_SIZE ( ar9285Modes_9285 ) , 6 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniCommon , ar9285Common_9285 ,
2008-12-08 19:43:48 +05:30
ARRAY_SIZE ( ar9285Common_9285 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
if ( ah - > config . pcie_clock_req ) {
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & ah - > iniModes , ar9280Modes_9280_2 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar9280Modes_9280_2 ) , 6 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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
2009-02-09 13:27:26 +05:30
if ( ah - > config . pcie_clock_req ) {
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & ah - > iniModes , ar9280Modes_9280 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar9280Modes_9280 ) , 6 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & ah - > iniModes , ar5416Modes_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Modes_9160 ) , 6 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniCommon , ar5416Common_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Common_9160 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank0 , ar5416Bank0_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank0_9160 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank1 , ar5416Bank1_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank1_9160 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank2 , ar5416Bank2_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank2_9160 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank3 , ar5416Bank3_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank3_9160 ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank6 , ar5416Bank6_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6_9160 ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank6TPC , ar5416Bank6TPC_9160 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6TPC_9160 ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & ah - > iniModes , ar5416Modes_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Modes_9100 ) , 6 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniCommon , ar5416Common_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Common_9100 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank0 , ar5416Bank0_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank0_9100 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & 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:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank1 , ar5416Bank1_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank1_9100 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank2 , ar5416Bank2_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank2_9100 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank3 , ar5416Bank3_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank3_9100 ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank6 , ar5416Bank6_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6_9100 ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank6TPC , ar5416Bank6TPC_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6TPC_9100 ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank7 , ar5416Bank7_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank7_9100 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniAddac , ar5416Addac_9100 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Addac_9100 ) , 2 ) ;
} else {
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniModes , ar5416Modes ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Modes ) , 6 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniCommon , ar5416Common ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Common ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank0 , ar5416Bank0 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank0 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBB_RfGain , ar5416BB_RfGain ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416BB_RfGain ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank1 , ar5416Bank1 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank1 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank2 , ar5416Bank2 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank2 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank3 , ar5416Bank3 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank3 ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank6 , ar5416Bank6 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6 ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank6TPC , ar5416Bank6TPC ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank6TPC ) , 3 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniBank7 , ar5416Bank7 ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Bank7 ) , 2 ) ;
2009-02-09 13:27:26 +05:30
INIT_INI_ARRAY ( & ah - > iniAddac , ar5416Addac ,
2008-10-29 10:16:30 +05:30
ARRAY_SIZE ( ar5416Addac ) , 2 ) ;
2008-08-04 00:16:41 -07:00
}
2009-08-03 12:24:45 -07:00
}
2008-08-04 00:16:41 -07:00
2009-08-03 12:24:45 -07:00
static void ath9k_hw_init_mode_gain_regs ( struct ath_hw * ah )
{
2009-09-23 16:27:27 +05:30
if ( AR_SREV_9287_11_OR_LATER ( ah ) )
2009-07-23 10:59:57 +05:30
INIT_INI_ARRAY ( & ah - > iniModesRxGain ,
ar9287Modes_rx_gain_9287_1_1 ,
ARRAY_SIZE ( ar9287Modes_rx_gain_9287_1_1 ) , 6 ) ;
else if ( AR_SREV_9287_10 ( ah ) )
INIT_INI_ARRAY ( & ah - > iniModesRxGain ,
ar9287Modes_rx_gain_9287_1_0 ,
ARRAY_SIZE ( ar9287Modes_rx_gain_9287_1_0 ) , 6 ) ;
else if ( AR_SREV_9280_20 ( ah ) )
ath9k_hw_init_rxgain_ini ( ah ) ;
2009-09-23 16:27:27 +05:30
if ( AR_SREV_9287_11_OR_LATER ( ah ) ) {
2009-07-23 10:59:57 +05:30
INIT_INI_ARRAY ( & ah - > iniModesTxGain ,
ar9287Modes_tx_gain_9287_1_1 ,
ARRAY_SIZE ( ar9287Modes_tx_gain_9287_1_1 ) , 6 ) ;
} else if ( AR_SREV_9287_10 ( ah ) ) {
INIT_INI_ARRAY ( & ah - > iniModesTxGain ,
ar9287Modes_tx_gain_9287_1_0 ,
ARRAY_SIZE ( ar9287Modes_tx_gain_9287_1_0 ) , 6 ) ;
} else if ( AR_SREV_9280_20 ( ah ) ) {
ath9k_hw_init_txgain_ini ( ah ) ;
} else if ( AR_SREV_9285_12_OR_LATER ( ah ) ) {
2009-03-06 11:24:10 +05:30
u32 txgain_type = ah - > eep_ops - > get_eeprom ( ah , EEP_TXGAIN_TYPE ) ;
/* txgain table */
if ( txgain_type = = AR5416_EEP_TXGAIN_HIGH_POWER ) {
INIT_INI_ARRAY ( & ah - > iniModesTxGain ,
ar9285Modes_high_power_tx_gain_9285_1_2 ,
ARRAY_SIZE ( ar9285Modes_high_power_tx_gain_9285_1_2 ) , 6 ) ;
} else {
INIT_INI_ARRAY ( & ah - > iniModesTxGain ,
ar9285Modes_original_tx_gain_9285_1_2 ,
ARRAY_SIZE ( ar9285Modes_original_tx_gain_9285_1_2 ) , 6 ) ;
}
}
2009-08-03 12:24:45 -07:00
}
2009-03-06 11:24:10 +05:30
2009-08-03 12:24:45 -07:00
static void ath9k_hw_init_11a_eeprom_fix ( struct ath_hw * ah )
{
u32 i , j ;
2009-02-12 10:06:45 +05:30
if ( ( ah - > hw_version . devid = = AR9280_DEVID_PCI ) & &
test_bit ( ATH9K_MODE_11A , ah - > caps . wireless_modes ) ) {
/* EEPROM Fixup */
2009-02-09 13:27:26 +05:30
for ( i = 0 ; i < ah - > iniModes . ia_rows ; i + + ) {
u32 reg = INI_RA ( & ah - > iniModes , i , 0 ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
for ( j = 1 ; j < ah - > iniModes . ia_columns ; j + + ) {
u32 val = INI_RA ( & ah - > iniModes , i , j ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
INI_RA ( & ah - > iniModes , i , j ) =
2008-12-08 19:43:48 +05:30
ath9k_hw_ini_fixup ( ah ,
2009-02-09 13:27:26 +05:30
& 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
}
2009-08-03 12:24:45 -07:00
}
2009-08-03 12:24:46 -07:00
int ath9k_hw_init ( struct ath_hw * ah )
2009-08-03 12:24:45 -07:00
{
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2009-08-03 12:24:54 -07:00
int r = 0 ;
2009-08-03 12:24:45 -07:00
2009-09-23 23:07:01 -04:00
if ( ! ath9k_hw_devid_supported ( ah - > hw_version . devid ) ) {
ath_print ( common , ATH_DBG_FATAL ,
" Unsupported device ID: 0x%0x \n " ,
ah - > hw_version . devid ) ;
2009-08-03 12:24:54 -07:00
return - EOPNOTSUPP ;
2009-09-23 23:07:01 -04:00
}
2009-08-03 12:24:45 -07:00
ath9k_hw_init_defaults ( ah ) ;
ath9k_hw_init_config ( ah ) ;
if ( ! ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_POWER_ON ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" Couldn't reset chip \n " ) ;
2009-08-03 12:24:54 -07:00
return - EIO ;
2009-08-03 12:24:45 -07:00
}
2009-09-09 21:10:09 -07:00
if ( ! ath9k_hw_setpower ( ah , ATH9K_PM_AWAKE ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL , " Couldn't wakeup chip \n " ) ;
2009-08-03 12:24:54 -07:00
return - EIO ;
2009-08-03 12:24:45 -07:00
}
if ( ah - > config . serialize_regmode = = SER_REG_MODE_AUTO ) {
if ( ah - > hw_version . macVersion = = AR_SREV_VERSION_5416_PCI | |
( AR_SREV_9280 ( ah ) & & ! ah - > is_pciexpress ) ) {
ah - > config . serialize_regmode =
SER_REG_MODE_ON ;
} else {
ah - > config . serialize_regmode =
SER_REG_MODE_OFF ;
}
}
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_RESET , " serialize_regmode is %d \n " ,
2009-08-03 12:24:45 -07:00
ah - > config . serialize_regmode ) ;
if ( ! ath9k_hw_macversion_supported ( ah - > hw_version . macVersion ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" Mac Chip Rev 0x%02x.%x is not supported by "
" this driver \n " , ah - > hw_version . macVersion ,
ah - > hw_version . macRev ) ;
2009-08-03 12:24:54 -07:00
return - EOPNOTSUPP ;
2009-08-03 12:24:45 -07:00
}
if ( AR_SREV_9100 ( ah ) ) {
ah - > iq_caldata . calData = & iq_cal_multi_sample ;
ah - > supp_cals = IQ_MISMATCH_CAL ;
ah - > is_pciexpress = false ;
}
2009-08-03 23:14:12 -04:00
if ( AR_SREV_9271 ( ah ) )
ah - > is_pciexpress = false ;
2009-08-03 12:24:45 -07:00
ah - > hw_version . phyRev = REG_READ ( ah , AR_PHY_CHIP_ID ) ;
ath9k_hw_init_cal_settings ( ah ) ;
ah - > ani_function = ATH9K_ANI_ALL ;
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
ah - > ani_function & = ~ ATH9K_ANI_NOISE_IMMUNITY_LEVEL ;
ath9k_hw_init_mode_regs ( ah ) ;
if ( ah - > is_pciexpress )
2009-09-17 09:24:58 +05:30
ath9k_hw_configpcipowersave ( ah , 0 , 0 ) ;
2009-08-03 12:24:45 -07:00
else
ath9k_hw_disablepcie ( ah ) ;
2009-09-18 15:04:07 +05:30
/* Support for Japan ch.14 (2484) spread */
if ( AR_SREV_9287_11_OR_LATER ( ah ) ) {
INIT_INI_ARRAY ( & ah - > iniCckfirNormal ,
ar9287Common_normal_cck_fir_coeff_92871_1 ,
ARRAY_SIZE ( ar9287Common_normal_cck_fir_coeff_92871_1 ) , 2 ) ;
INIT_INI_ARRAY ( & ah - > iniCckfirJapan2484 ,
ar9287Common_japan_2484_cck_fir_coeff_92871_1 ,
ARRAY_SIZE ( ar9287Common_japan_2484_cck_fir_coeff_92871_1 ) , 2 ) ;
}
2009-08-03 12:24:46 -07:00
r = ath9k_hw_post_init ( ah ) ;
2009-08-03 12:24:45 -07:00
if ( r )
2009-08-03 12:24:54 -07:00
return r ;
2009-08-03 12:24:45 -07:00
ath9k_hw_init_mode_gain_regs ( ah ) ;
ath9k_hw_fill_cap_info ( ah ) ;
ath9k_hw_init_11a_eeprom_fix ( ah ) ;
2008-12-07 21:43:10 +05:30
2009-08-03 12:24:36 -07:00
r = ath9k_hw_init_macaddr ( ah ) ;
if ( r ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" Failed to initialize MAC address \n " ) ;
2009-08-03 12:24:54 -07:00
return r ;
2008-08-04 00:16:41 -07:00
}
2009-08-03 23:14:12 -04:00
if ( AR_SREV_9285 ( ah ) | | AR_SREV_9271 ( ah ) )
2009-02-09 13:27:26 +05:30
ah - > tx_trig_level = ( AR_FTRIG_256B > > AR_FTRIG_S ) ;
2008-10-29 10:16:30 +05:30
else
2009-02-09 13:27:26 +05:30
ah - > tx_trig_level = ( 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
2009-10-06 21:19:07 -04:00
common - > state = ATH_HW_INITIALIZED ;
2009-08-03 12:24:36 -07:00
return 0 ;
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:26 +05:30
rx_chainmask = ah - > rxchainmask ;
tx_chainmask = 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:26 +05:30
ah - > mask_reg = 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-03-30 15:28:35 +05:30
if ( ah - > config . intr_mitigation )
2009-02-09 13:27:26 +05:30
ah - > mask_reg | = AR_IMR_RXINTM | AR_IMR_RXMINTR ;
2008-08-04 00:16:41 -07:00
else
2009-02-09 13:27:26 +05:30
ah - > mask_reg | = AR_IMR_RXOK ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
ah - > mask_reg | = 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:26 +05:30
ah - > mask_reg | = AR_IMR_MIB ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
REG_WRITE ( ah , AR_IMR , ah - > mask_reg ) ;
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 ) ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_RESET ,
" bad ack timeout %u \n " , us ) ;
2009-02-09 13:27:26 +05:30
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:26 +05:30
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 ) ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_RESET ,
" bad cts timeout %u \n " , us ) ;
2009-02-09 13:27:26 +05:30
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:26 +05:30
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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_XMIT ,
" bad global tx timeout %u \n " , tu ) ;
2009-02-09 13:27:26 +05:30
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:26 +05:30
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-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_RESET , " ah->misc_mode 0x%x \n " ,
ah - > misc_mode ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
if ( ah - > misc_mode ! = 0 )
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PCU_MISC ,
2009-02-09 13:27:26 +05:30
REG_READ ( ah , AR_PCU_MISC ) | ah - > misc_mode ) ;
if ( ah - > slottime ! = ( u32 ) - 1 )
ath9k_hw_setslottime ( ah , ah - > slottime ) ;
if ( ah - > acktimeout ! = ( u32 ) - 1 )
ath9k_hw_set_ack_timeout ( ah , ah - > acktimeout ) ;
if ( ah - > ctstimeout ! = ( u32 ) - 1 )
ath9k_hw_set_cts_timeout ( ah , ah - > ctstimeout ) ;
if ( ah - > globaltxtimeout ! = ( u32 ) - 1 )
ath9k_hw_set_global_txtimeout ( 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
{
2009-10-06 21:19:07 -04:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
if ( common - > state < = ATH_HW_INITIALIZED )
goto free_hw ;
2008-10-29 10:16:30 +05:30
if ( ! AR_SREV_9100 ( ah ) )
2009-08-03 12:24:51 -07:00
ath9k_hw_ani_disable ( ah ) ;
2008-10-29 10:16:30 +05:30
2009-09-09 21:10:09 -07:00
ath9k_hw_setpower ( ah , ATH9K_PM_FULL_SLEEP ) ;
2009-10-06 21:19:07 -04:00
free_hw :
ath9k_hw_rf_free ( ah ) ;
2008-10-29 10:16:30 +05:30
kfree ( ah ) ;
2009-08-03 12:24:52 -07:00
ah = NULL ;
2008-10-29 10:16:30 +05:30
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_detach ) ;
2008-10-29 10:16:30 +05:30
/*******/
/* 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 )
{
2009-08-03 23:14:12 -04:00
u32 val ;
if ( AR_SREV_9271 ( ah ) ) {
/*
* Enable spectral scan to solution for issues with stuck
* beacons on AR9271 1.0 . The beacon stuck issue is not seeon on
* AR9271 1.1
*/
if ( AR_SREV_9271_10 ( ah ) ) {
val = REG_READ ( ah , AR_PHY_SPECTRAL_SCAN ) | AR_PHY_SPECTRAL_SCAN_ENABLE ;
REG_WRITE ( ah , AR_PHY_SPECTRAL_SCAN , val ) ;
}
else if ( AR_SREV_9271_11 ( ah ) )
/*
* change AR_PHY_RF_CTL3 setting to fix MAC issue
* present on AR9271 1.1
*/
REG_WRITE ( ah , AR_PHY_RF_CTL3 , 0x3a020001 ) ;
return ;
}
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 ) ) ;
2009-09-17 09:26:14 +05:30
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
val = REG_READ ( ah , AR_PCU_MISC_MODE2 ) &
( ~ AR_PCU_MISC_MODE2_HWWAR1 ) ;
if ( AR_SREV_9287_10_OR_LATER ( ah ) )
val = val & ( ~ AR_PCU_MISC_MODE2_HWWAR2 ) ;
REG_WRITE ( ah , AR_PCU_MISC_MODE2 , val ) ;
}
2008-12-08 19:43:50 +05:30
2009-03-06 09:08:51 +01:00
if ( ! AR_SREV_5416_20_OR_LATER ( ah ) | |
2008-10-29 10:16:30 +05:30
AR_SREV_9280_10_OR_LATER ( ah ) )
return ;
2009-08-03 23:14:12 -04:00
/*
* Disable BB clock gating
* Necessary to avoid issues on AR5416 2.0
*/
2008-10-29 10:16:30 +05:30
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 ) ;
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_EEPROM ,
2008-10-29 10:16:30 +05:30
" ini VAL: %x EEPROM: %x \n " , value ,
( pBase - > version & 0xff ) ) ;
if ( ( pBase - > version & 0xff ) > 0x0a ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_EEPROM ,
" PWDCLKIND: %d \n " ,
pBase - > pwdclkind ) ;
2008-10-29 10:16:30 +05:30
value & = ~ AR_AN_TOP2_PWDCLKIND ;
value | = AR_AN_TOP2_PWDCLKIND &
( pBase - > pwdclkind < < AR_AN_TOP2_PWDCLKIND_S ) ;
} else {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_EEPROM ,
" PWDCLKIND Earlier Rev \n " ) ;
2008-10-29 10:16:30 +05:30
}
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_EEPROM ,
" final ini VAL: %x \n " , value ) ;
2008-10-29 10:16:30 +05:30
}
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:26 +05:30
if ( 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-12 13:57:03 +05:30
static void ath9k_olc_init ( struct ath_hw * ah )
{
u32 i ;
2009-08-14 11:27:16 +05:30
if ( OLC_FOR_AR9287_10_LATER ) {
REG_SET_BIT ( ah , AR_PHY_TX_PWRCTRL9 ,
AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL ) ;
ath9k_hw_analog_shift_rmw ( ah , AR9287_AN_TXPC0 ,
AR9287_AN_TXPC0_TXPCMODE ,
AR9287_AN_TXPC0_TXPCMODE_S ,
AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE ) ;
udelay ( 100 ) ;
} else {
for ( i = 0 ; i < AR9280_TX_GAIN_TABLE_SIZE ; i + + )
ah - > originalGain [ i ] =
MS ( REG_READ ( ah , AR_PHY_TX_GAIN_TBL1 + i * 4 ) ,
AR_PHY_TX_GAIN ) ;
ah - > PDADCdelta = 0 ;
}
2009-02-12 13:57:03 +05:30
}
2009-03-30 22:30:29 -04:00
static u32 ath9k_regd_get_ctl ( struct ath_regulatory * reg ,
struct ath9k_channel * chan )
{
u32 ctl = ath_regd_get_band_ctl ( reg , chan - > chan - > band ) ;
if ( IS_CHAN_B ( chan ) )
ctl | = CTL_11B ;
else if ( IS_CHAN_G ( chan ) )
ctl | = CTL_11G ;
else
ctl | = CTL_11A ;
return ctl ;
}
2009-02-09 13:27:12 +05:30
static int ath9k_hw_process_ini ( struct ath_hw * ah ,
2009-09-13 23:04:44 -07:00
struct ath9k_channel * chan )
2008-08-04 00:16:41 -07:00
{
2009-08-17 18:07:23 -07:00
struct ath_regulatory * regulatory = ath9k_hw_regulatory ( ah ) ;
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 ;
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 ) ;
2009-02-09 13:27:24 +05:30
ah - > eep_ops - > set_addac ( ah , chan ) ;
2008-08-04 00:16:41 -07:00
2009-03-06 09:08:51 +01:00
if ( AR_SREV_5416_22_OR_LATER ( ah ) ) {
2009-02-09 13:27:26 +05:30
REG_WRITE_ARRAY ( & ah - > iniAddac , 1 , regWrites ) ;
2008-08-04 00:16:41 -07:00
} else {
struct ar5416IniArray temp ;
u32 addacSize =
2009-02-09 13:27:26 +05:30
sizeof ( u32 ) * ah - > iniAddac . ia_rows *
ah - > iniAddac . ia_columns ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
memcpy ( ah - > addac5416_21 ,
ah - > iniAddac . ia_array , addacSize ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
( ah - > addac5416_21 ) [ 31 * ah - > iniAddac . ia_columns + 1 ] = 0 ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
temp . ia_array = ah - > addac5416_21 ;
temp . ia_columns = ah - > iniAddac . ia_columns ;
temp . ia_rows = 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:26 +05:30
for ( i = 0 ; i < ah - > iniModes . ia_rows ; i + + ) {
u32 reg = INI_RA ( & ah - > iniModes , i , 0 ) ;
u32 val = INI_RA ( & ah - > iniModes , i , modesIndex ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , reg , val ) ;
if ( reg > = 0x7800 & & reg < 0x78a0
2009-02-09 13:27:26 +05:30
& & ah - > config . analog_shiftreg ) {
2008-08-04 00:16:41 -07:00
udelay ( 100 ) ;
}
DO_DELAY ( regWrites ) ;
}
2009-07-23 10:59:57 +05:30
if ( AR_SREV_9280 ( ah ) | | AR_SREV_9287_10_OR_LATER ( ah ) )
2009-02-09 13:27:26 +05:30
REG_WRITE_ARRAY ( & ah - > iniModesRxGain , modesIndex , regWrites ) ;
2008-11-13 17:58:41 +05:30
2009-07-23 10:59:57 +05:30
if ( AR_SREV_9280 ( ah ) | | AR_SREV_9285_12_OR_LATER ( ah ) | |
AR_SREV_9287_10_OR_LATER ( ah ) )
2009-02-09 13:27:26 +05:30
REG_WRITE_ARRAY ( & ah - > iniModesTxGain , modesIndex , regWrites ) ;
2008-11-13 17:58:41 +05:30
2009-02-09 13:27:26 +05:30
for ( i = 0 ; i < ah - > iniCommon . ia_rows ; i + + ) {
u32 reg = INI_RA ( & ah - > iniCommon , i , 0 ) ;
u32 val = INI_RA ( & ah - > iniCommon , i , 1 ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , reg , val ) ;
if ( reg > = 0x7800 & & reg < 0x78a0
2009-02-09 13:27:26 +05:30
& & 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:26 +05:30
REG_WRITE_ARRAY ( & ah - > iniModesAdditional , modesIndex ,
2008-08-04 00:16:41 -07:00
regWrites ) ;
}
ath9k_hw_override_ini ( ah , chan ) ;
2009-09-13 23:04:44 -07:00
ath9k_hw_set_regs ( ah , chan ) ;
2008-08-04 00:16:41 -07:00
ath9k_hw_init_chain_masks ( ah ) ;
2009-02-12 13:57:03 +05:30
if ( OLC_FOR_AR9280_20_LATER )
ath9k_olc_init ( ah ) ;
2009-05-08 17:54:51 -07:00
ah - > eep_ops - > set_txpower ( ah , chan ,
2009-08-17 18:07:23 -07:00
ath9k_regd_get_ctl ( regulatory , chan ) ,
2009-05-08 17:54:51 -07:00
channel - > max_antenna_gain * 2 ,
channel - > max_power * 2 ,
min ( ( u32 ) MAX_RATE_POWER ,
2009-08-17 18:07:23 -07:00
( u32 ) regulatory - > power_limit ) ) ;
2008-08-04 00:16:41 -07:00
if ( ! ath9k_hw_set_rf_regs ( ah , chan , freqIndex ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_FATAL ,
" 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 ;
2009-08-03 23:14:12 -04:00
/*
* set AHB_MODE not to do cacheline prefetches
*/
2008-10-29 10:16:30 +05:30
regval = REG_READ ( ah , AR_AHB_MODE ) ;
REG_WRITE ( ah , AR_AHB_MODE , regval | AR_AHB_PREFETCH_RD_EN ) ;
2009-08-03 23:14:12 -04:00
/*
* let mac dma reads be in 128 byte chunks
*/
2008-10-29 10:16:30 +05:30
regval = REG_READ ( ah , AR_TXCFG ) & ~ AR_TXCFG_DMASZ_MASK ;
REG_WRITE ( ah , AR_TXCFG , regval | AR_TXCFG_DMASZ_128B ) ;
2009-08-03 23:14:12 -04:00
/*
* Restore TX Trigger Level to its pre - reset value .
* The initial value depends on whether aggregation is enabled , and is
* adjusted whenever underruns are detected .
*/
2009-02-09 13:27:26 +05:30
REG_RMW_FIELD ( ah , AR_TXCFG , AR_FTRIG , ah - > tx_trig_level ) ;
2008-10-29 10:16:30 +05:30
2009-08-03 23:14:12 -04:00
/*
* let mac dma writes be in 128 byte chunks
*/
2008-10-29 10:16:30 +05:30
regval = REG_READ ( ah , AR_RXCFG ) & ~ AR_RXCFG_DMASZ_MASK ;
REG_WRITE ( ah , AR_RXCFG , regval | AR_RXCFG_DMASZ_128B ) ;
2009-08-03 23:14:12 -04:00
/*
* Setup receive FIFO threshold to hold off TX activities
*/
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_RXFIFO_CFG , 0x200 ) ;
2009-08-03 23:14:12 -04:00
/*
* reduce the number of usable entries in PCU TXBUF to avoid
* wrap around issues .
*/
2008-10-29 10:16:30 +05:30
if ( AR_SREV_9285 ( ah ) ) {
2009-08-03 23:14:12 -04:00
/* For AR9285 the number of Fifos are reduced to half.
* So set the usable tx buf size also to half to
* avoid data / delimiter underruns
*/
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PCU_TXBUF_CTRL ,
AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE ) ;
2009-08-03 23:14:12 -04:00
} else if ( ! AR_SREV_9271 ( ah ) ) {
2008-10-29 10:16:30 +05:30
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 :
2009-03-20 22:59:59 -04:00
case NL80211_IFTYPE_MESH_POINT :
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 ;
2009-02-16 13:23:12 +05:30
if ( AR_SREV_9100 ( ah ) ) {
u32 val = REG_READ ( ah , AR_RTC_DERIVED_CLK ) ;
val & = ~ AR_RTC_DERIVED_CLK_PERIOD ;
val | = SM ( 1 , AR_RTC_DERIVED_CLK_PERIOD ) ;
REG_WRITE ( ah , AR_RTC_DERIVED_CLK , val ) ;
( void ) REG_READ ( ah , AR_RTC_DERIVED_CLK ) ;
}
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 ) ;
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 ) ;
2009-02-16 13:23:20 +05:30
if ( ! ath9k_hw_wait ( ah , AR_RTC_RC , AR_RTC_RC_M , 0 , AH_WAIT_TIMEOUT ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_RESET ,
" 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 ) ;
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-08-31 17:48:36 +05:30
if ( ! AR_SREV_9100 ( ah ) )
REG_WRITE ( ah , AR_RC , AR_RC_AHB ) ;
2009-01-14 20:17:09 +01:00
REG_WRITE ( ah , AR_RTC_RESET , 0 ) ;
2009-02-12 13:57:03 +05:30
udelay ( 2 ) ;
2009-08-31 17:48:36 +05:30
if ( ! AR_SREV_9100 ( ah ) )
REG_WRITE ( ah , AR_RC , 0 ) ;
2009-01-14 20:17:09 +01:00
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 ,
2009-02-16 13:23:20 +05:30
AR_RTC_STATUS_ON ,
AH_WAIT_TIMEOUT ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , 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 ) ;
case ATH9K_RESET_WARM :
case ATH9K_RESET_COLD :
return ath9k_hw_set_reset ( ah , type ) ;
default :
return false ;
}
2008-08-04 00:16:41 -07:00
}
2009-09-13 23:04:44 -07:00
static void ath9k_hw_set_regs ( 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 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
}
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_PHY_TURBO , phymode ) ;
2009-09-13 23:04:44 -07:00
ath9k_hw_set11nmac2040 ( ah ) ;
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
{
2009-09-17 09:27:59 +05:30
if ( AR_SREV_9280 ( ah ) & & ah - > eep_ops - > get_eeprom ( ah , EEP_OL_PWRCTRL ) ) {
2009-02-12 13:57:03 +05:30
if ( ! ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_POWER_ON ) )
return false ;
} else if ( ! ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_WARM ) )
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
2009-09-09 21:10:09 -07:00
if ( ! ath9k_hw_setpower ( ah , ATH9K_PM_AWAKE ) )
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
ah - > chip_fullsleep = 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 ,
2009-09-13 23:04:44 -07:00
struct ath9k_channel * chan )
2008-08-04 00:16:41 -07:00
{
2009-08-17 18:07:23 -07:00
struct ath_regulatory * regulatory = ath9k_hw_regulatory ( ah ) ;
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
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 ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_QUEUE ,
" 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 ,
2009-02-16 13:23:20 +05:30
AR_PHY_RFBUS_GRANT_EN , AH_WAIT_TIMEOUT ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" Could not kill baseband RX \n " ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
2009-09-13 23:04:44 -07:00
ath9k_hw_set_regs ( ah , chan ) ;
2008-08-04 00:16:41 -07:00
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
2009-05-08 17:54:51 -07:00
ath9k_hw_ar9280_set_channel ( ah , chan ) ;
2008-08-04 00:16:41 -07:00
} else {
if ( ! ( ath9k_hw_set_channel ( ah , chan ) ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" Failed to set channel \n " ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
}
2009-05-08 17:54:51 -07:00
ah - > eep_ops - > set_txpower ( ah , chan ,
2009-08-17 18:07:23 -07:00
ath9k_regd_get_ctl ( regulatory , chan ) ,
2009-02-09 13:27:24 +05:30
channel - > max_antenna_gain * 2 ,
channel - > max_power * 2 ,
min ( ( u32 ) MAX_RATE_POWER ,
2009-08-17 18:07:23 -07:00
( u32 ) regulatory - > power_limit ) ) ;
2008-08-04 00:16:41 -07:00
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 ;
2009-02-09 13:27:26 +05:30
ah - > config . spurmode = SPUR_ENABLE_EEPROM ;
2008-10-29 10:16:30 +05:30
for ( i = 0 ; i < AR_EEPROM_MODAL_SPURS ; i + + ) {
2009-02-09 13:27:24 +05:30
cur_bb_spur = ah - > eep_ops - > get_spur_channel ( ah , i , is2GHz ) ;
2008-10-29 10:16:30 +05:30
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 + + ) {
2009-02-09 13:27:24 +05:30
cur_bb_spur = ah - > eep_ops - > get_spur_channel ( ah , i , is2GHz ) ;
2008-10-29 10:16:30 +05:30
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-06-13 14:50:26 +05:30
static void ath9k_enable_rfkill ( struct ath_hw * ah )
{
REG_SET_BIT ( ah , AR_GPIO_INPUT_EN_VAL ,
AR_GPIO_INPUT_EN_VAL_RFSILENT_BB ) ;
REG_CLR_BIT ( ah , AR_GPIO_INPUT_MUX2 ,
AR_GPIO_INPUT_MUX2_RFSILENT ) ;
ath9k_hw_cfg_gpio_input ( ah , ah - > rfkill_gpio ) ;
REG_SET_BIT ( ah , AR_PHY_TEST , RFSILENT_BB ) ;
}
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
{
2009-09-10 09:22:37 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2008-08-04 00:16:41 -07:00
u32 saveLedState ;
2009-02-09 13:27:26 +05:30
struct ath9k_channel * curchan = ah - > curchan ;
2008-08-04 00:16:41 -07:00
u32 saveDefAntenna ;
u32 macStaId1 ;
2009-09-17 09:25:25 +05:30
u64 tsf = 0 ;
2008-12-23 15:58:40 -08:00
int i , rx_chainmask , r ;
2008-08-04 00:16:41 -07:00
2009-09-13 21:07:07 -07:00
ah - > txchainmask = common - > tx_chainmask ;
ah - > rxchainmask = common - > rx_chainmask ;
2008-08-04 00:16:41 -07:00
2009-09-09 21:10:09 -07:00
if ( ! ath9k_hw_setpower ( ah , ATH9K_PM_AWAKE ) )
2008-12-23 15:58:40 -08:00
return - EIO ;
2008-08-04 00:16:41 -07:00
2009-09-17 09:26:44 +05:30
if ( curchan & & ! ah - > chip_fullsleep )
2008-08-04 00:16:41 -07:00
ath9k_hw_getnf ( ah , curchan ) ;
if ( bChannelChange & &
2009-02-09 13:27:26 +05:30
( ah - > chip_fullsleep ! = true ) & &
( ah - > curchan ! = NULL ) & &
( chan - > channel ! = ah - > curchan - > channel ) & &
2008-08-04 00:16:41 -07:00
( ( chan - > channelFlags & CHANNEL_ALL ) = =
2009-02-09 13:27:26 +05:30
( ah - > curchan - > channelFlags & CHANNEL_ALL ) ) & &
2009-09-17 09:27:10 +05:30
! ( AR_SREV_9280 ( ah ) | | IS_CHAN_A_5MHZ_SPACED ( chan ) | |
IS_CHAN_A_5MHZ_SPACED ( ah - > curchan ) ) ) {
2008-08-04 00:16:41 -07:00
2009-09-13 23:04:44 -07:00
if ( ath9k_hw_channel_change ( ah , chan ) ) {
2009-02-09 13:27:26 +05:30
ath9k_hw_loadnf ( ah , ah - > curchan ) ;
2008-08-04 00:16:41 -07:00
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 ;
2009-09-17 09:25:25 +05:30
/* For chips on which RTC reset is done, save TSF before it gets cleared */
if ( AR_SREV_9280 ( ah ) & & ah - > eep_ops - > get_eeprom ( ah , EEP_OL_PWRCTRL ) )
tsf = ath9k_hw_gettsf64 ( ah ) ;
2008-08-04 00:16:41 -07:00
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 ) ;
2009-08-03 23:14:12 -04:00
if ( AR_SREV_9271 ( ah ) & & ah - > htc_reset_init ) {
REG_WRITE ( ah ,
AR9271_RESET_POWER_DOWN_CONTROL ,
AR9271_RADIO_RF_RST ) ;
udelay ( 50 ) ;
}
2008-08-04 00:16:41 -07:00
if ( ! ath9k_hw_chip_reset ( ah , chan ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL , " Chip reset failed \n " ) ;
2008-12-23 15:58:40 -08:00
return - EINVAL ;
2008-08-04 00:16:41 -07:00
}
2009-08-03 23:14:12 -04:00
if ( AR_SREV_9271 ( ah ) & & ah - > htc_reset_init ) {
ah - > htc_reset_init = false ;
REG_WRITE ( ah ,
AR9271_RESET_POWER_DOWN_CONTROL ,
AR9271_GATE_MAC_CTL ) ;
udelay ( 50 ) ;
}
2009-09-17 09:25:25 +05:30
/* Restore TSF */
if ( tsf & & AR_SREV_9280 ( ah ) & & ah - > eep_ops - > get_eeprom ( ah , EEP_OL_PWRCTRL ) )
ath9k_hw_settsf64 ( ah , tsf ) ;
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
2009-08-14 11:33:36 +05:30
if ( AR_SREV_9287_12_OR_LATER ( ah ) ) {
2009-07-23 10:59:57 +05:30
/* Enable ASYNC FIFO */
REG_SET_BIT ( ah , AR_MAC_PCU_ASYNC_FIFO_REG3 ,
AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL ) ;
REG_SET_BIT ( ah , AR_PHY_MODE , AR_PHY_MODE_ASYNCFIFO ) ;
REG_CLR_BIT ( ah , AR_MAC_PCU_ASYNC_FIFO_REG3 ,
AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET ) ;
REG_SET_BIT ( ah , AR_MAC_PCU_ASYNC_FIFO_REG3 ,
AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET ) ;
}
2009-09-13 23:04:44 -07:00
r = ath9k_hw_process_ini ( ah , chan ) ;
2008-12-23 15:58:40 -08:00
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 ) ;
2009-03-13 08:56:05 +05:30
ah - > eep_ops - > set_board_values ( ah , chan ) ;
2008-08-04 00:16:41 -07:00
ath9k_hw_decrease_chain_power ( ah , chan ) ;
2009-09-10 09:22:37 -07:00
REG_WRITE ( ah , AR_STA_ID0 , get_unaligned_le32 ( common - > macaddr ) ) ;
REG_WRITE ( ah , AR_STA_ID1 , get_unaligned_le16 ( common - > macaddr + 4 )
2008-08-04 00:16:41 -07:00
| macStaId1
| AR_STA_ID1_RTS_USE_DEF
2009-02-09 13:27:26 +05:30
| ( ah - > config .
2008-08-07 10:52:38 +05:30
ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0 )
2009-02-09 13:27:26 +05:30
| ah - > sta_id1_defaults ) ;
ath9k_hw_set_operating_mode ( ah , ah - > opmode ) ;
2008-08-04 00:16:41 -07:00
2009-09-10 17:52:45 -07:00
ath_hw_setbssidmask ( common ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_DEF_ANTENNA , saveDefAntenna ) ;
2009-09-10 08:57:00 -07:00
ath9k_hw_write_associd ( ah ) ;
2008-08-04 00:16:41 -07:00
REG_WRITE ( ah , AR_ISR , ~ 0 ) ;
REG_WRITE ( ah , AR_RSSI_THR , INIT_RSSI_THR ) ;
2009-05-08 17:54:51 -07:00
if ( AR_SREV_9280_10_OR_LATER ( ah ) )
ath9k_hw_ar9280_set_channel ( ah , chan ) ;
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:26 +05:30
ah - > intr_txqs = 0 ;
for ( i = 0 ; i < ah - > caps . total_queues ; i + + )
2008-08-04 00:16:41 -07:00
ath9k_hw_resettxqueue ( ah , i ) ;
2009-02-09 13:27:26 +05:30
ath9k_hw_init_interrupt_masks ( ah , ah - > opmode ) ;
2008-08-04 00:16:41 -07:00
ath9k_hw_init_qos ( ah ) ;
2009-02-09 13:27:26 +05:30
if ( ah - > caps . hw_caps & ATH9K_HW_CAP_RFSILENT )
2008-09-10 18:50:17 +05:30
ath9k_enable_rfkill ( ah ) ;
2009-06-13 14:50:26 +05:30
2008-08-04 00:16:41 -07:00
ath9k_hw_init_user_settings ( ah ) ;
2009-08-14 11:33:36 +05:30
if ( AR_SREV_9287_12_OR_LATER ( ah ) ) {
2009-07-23 10:59:57 +05:30
REG_WRITE ( ah , AR_D_GBL_IFS_SIFS ,
AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR ) ;
REG_WRITE ( ah , AR_D_GBL_IFS_SLOT ,
AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR ) ;
REG_WRITE ( ah , AR_D_GBL_IFS_EIFS ,
AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR ) ;
REG_WRITE ( ah , AR_TIME_OUT , AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR ) ;
REG_WRITE ( ah , AR_USEC , AR_USEC_ASYNC_FIFO_DUR ) ;
REG_SET_BIT ( ah , AR_MAC_PCU_LOGIC_ANALYZER ,
AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768 ) ;
REG_RMW_FIELD ( ah , AR_AHB_MODE , AR_AHB_CUSTOM_BURST_EN ,
AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL ) ;
}
2009-08-14 11:33:36 +05:30
if ( AR_SREV_9287_12_OR_LATER ( ah ) ) {
2009-07-23 10:59:57 +05:30
REG_SET_BIT ( ah , AR_PCU_MISC_MODE2 ,
AR_PCU_MISC_MODE2_ENABLE_AGGWEP ) ;
}
2008-08-04 00:16:41 -07:00
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-03-30 15:28:35 +05:30
if ( ah - > config . intr_mitigation ) {
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 ) )
2009-06-28 09:26:32 -07:00
return - EIO ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
rx_chainmask = 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 ) ;
2009-08-03 23:14:12 -04:00
/*
* For big endian systems turn on swapping for descriptors
*/
2008-08-04 00:16:41 -07:00
if ( AR_SREV_9100 ( ah ) ) {
u32 mask ;
mask = REG_READ ( ah , AR_CFG ) ;
if ( mask & ( AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , 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 ) ;
2009-09-13 02:42:02 -07:00
ath_print ( common , 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 {
2009-08-03 23:14:12 -04:00
/* Configure AR9271 target WLAN */
if ( AR_SREV_9271 ( ah ) )
REG_WRITE ( ah , AR_CFG , AR_CFG_SWRB | AR_CFG_SWTB ) ;
2008-08-04 00:16:41 -07:00
# ifdef __BIG_ENDIAN
2009-08-03 23:14:12 -04:00
else
REG_WRITE ( ah , AR_CFG , AR_CFG_SWTD | AR_CFG_SWRD ) ;
2008-08-04 00:16:41 -07:00
# endif
}
2009-09-09 14:52:02 -07:00
if ( ah - > btcoex_hw . enabled )
2009-08-26 21:08:45 +05:30
ath9k_hw_btcoex_enable ( ah ) ;
2008-12-23 15:58:40 -08:00
return 0 ;
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_reset ) ;
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
2009-02-09 13:27:26 +05:30
if ( entry > = ah - > caps . keycache_size ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_FATAL ,
" keychache 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
}
return true ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_keyreset ) ;
2008-08-04 00:16:41 -07:00
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
2009-02-09 13:27:26 +05:30
if ( entry > = ah - > caps . keycache_size ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_FATAL ,
" keychache 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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_keysetmac ) ;
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 ,
2009-03-02 18:15:53 +02:00
const u8 * mac )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:26 +05:30
const struct ath9k_hw_capabilities * pCap = & ah - > caps ;
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2008-10-29 10:16:30 +05:30
u32 key0 , key1 , key2 , key3 , key4 ;
u32 keyType ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
if ( entry > = pCap - > keycache_size ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" keycache 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 ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_ANY ,
" AES-CCM not supported by mac rev 0x%x \n " ,
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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_ANY ,
" entry %u inappropriate for TKIP \n " , entry ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
break ;
case ATH9K_CIPHER_WEP :
2009-05-21 21:47:03 +08:00
if ( k - > kv_len < WLAN_KEY_LEN_WEP40 ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_ANY ,
" WEP key length %u too small \n " , k - > kv_len ) ;
2008-10-29 10:16:30 +05:30
return false ;
}
2009-05-21 21:47:03 +08:00
if ( k - > kv_len < = WLAN_KEY_LEN_WEP40 )
2008-10-29 10:16:30 +05:30
keyType = AR_KEYTABLE_TYPE_40 ;
2009-05-21 21:47:03 +08:00
else if ( k - > kv_len < = WLAN_KEY_LEN_WEP104 )
2008-10-29 10:16:30 +05:30
keyType = AR_KEYTABLE_TYPE_104 ;
else
keyType = AR_KEYTABLE_TYPE_128 ;
break ;
case ATH9K_CIPHER_CLR :
keyType = AR_KEYTABLE_TYPE_CLR ;
break ;
default :
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" 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
}
2009-03-02 18:15:53 +02:00
key0 = get_unaligned_le32 ( k - > kv_val + 0 ) ;
key1 = get_unaligned_le16 ( k - > kv_val + 4 ) ;
key2 = get_unaligned_le32 ( k - > kv_val + 6 ) ;
key3 = get_unaligned_le16 ( k - > kv_val + 10 ) ;
key4 = get_unaligned_le32 ( k - > kv_val + 12 ) ;
2009-05-21 21:47:03 +08:00
if ( k - > kv_len < = WLAN_KEY_LEN_WEP104 )
2008-10-29 10:16:30 +05:30
key4 & = 0xff ;
2008-08-04 00:16:41 -07:00
2009-03-02 15:06:31 +02:00
/*
* Note : Key cache registers access special memory area that requires
* two 32 - bit writes to actually update the values in the internal
* memory . Consequently , the exact order and pairs used here must be
* maintained .
*/
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
2009-03-02 15:06:31 +02:00
/*
* Write inverted key [ 47 : 0 ] first to avoid Michael MIC errors
* on frames that could be sent or received at the same time .
* The correct key will be written in the end once everything
* else is ready .
*/
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( entry ) , ~ key0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( entry ) , ~ key1 ) ;
2009-03-02 15:06:31 +02:00
/* Write key[95:48] */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( entry ) , key2 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( entry ) , key3 ) ;
2009-03-02 15:06:31 +02:00
/* Write key[127:96] and key type */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY4 ( entry ) , key4 ) ;
REG_WRITE ( ah , AR_KEYTABLE_TYPE ( entry ) , keyType ) ;
2009-03-02 15:06:31 +02:00
/* Write MAC address for the entry */
2008-10-29 10:16:30 +05:30
( void ) ath9k_hw_keysetmac ( ah , entry , mac ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
if ( ah - > misc_mode & AR_PCU_MIC_NEW_LOC_ENA ) {
2009-03-02 15:06:31 +02:00
/*
* TKIP uses two key cache entries :
* Michael MIC TX / RX keys in the same key cache entry
* ( idx = main index + 64 ) :
* key0 [ 31 : 0 ] = RX key [ 31 : 0 ]
* key1 [ 15 : 0 ] = TX key [ 31 : 16 ]
* key1 [ 31 : 16 ] = reserved
* key2 [ 31 : 0 ] = RX key [ 63 : 32 ]
* key3 [ 15 : 0 ] = TX key [ 15 : 0 ]
* key3 [ 31 : 16 ] = reserved
* key4 [ 31 : 0 ] = TX key [ 63 : 32 ]
*/
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 ) ;
2009-03-02 15:06:31 +02:00
/* Write RX[31:0] and TX[31:16] */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( micentry ) , mic0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( micentry ) , mic1 ) ;
2009-03-02 15:06:31 +02:00
/* Write RX[63:32] and TX[15:0] */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( micentry ) , mic2 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( micentry ) , mic3 ) ;
2009-03-02 15:06:31 +02:00
/* Write TX[63:32] and keyType(reserved) */
2008-10-29 10:16:30 +05:30
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 {
2009-03-02 15:06:31 +02:00
/*
* TKIP uses four key cache entries ( two for group
* keys ) :
* Michael MIC TX / RX keys are in different key cache
* entries ( idx = main index + 64 for TX and
* main index + 32 + 96 for RX ) :
* key0 [ 31 : 0 ] = TX / RX MIC key [ 31 : 0 ]
* key1 [ 31 : 0 ] = reserved
* key2 [ 31 : 0 ] = TX / RX MIC key [ 63 : 32 ]
* key3 [ 31 : 0 ] = reserved
* key4 [ 31 : 0 ] = reserved
*
* Upper layer code will call this function separately
* for TX and RX keys when these registers offsets are
* used .
*/
2008-10-29 10:16:30 +05:30
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 ) ;
2009-03-02 15:06:31 +02:00
/* Write MIC key[31:0] */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( micentry ) , mic0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( micentry ) , 0 ) ;
2009-03-02 15:06:31 +02:00
/* Write MIC key[63:32] */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( micentry ) , mic2 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( micentry ) , 0 ) ;
2009-03-02 15:06:31 +02:00
/* Write TX[63:32] and keyType(reserved) */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY4 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_TYPE ( micentry ) ,
AR_KEYTABLE_TYPE_CLR ) ;
}
2009-03-02 15:06:31 +02:00
/* MAC address registers are reserved for the MIC entry */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_MAC0 ( micentry ) , 0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_MAC1 ( micentry ) , 0 ) ;
2009-03-02 15:06:31 +02:00
/*
* Write the correct ( un - inverted ) key [ 47 : 0 ] last to enable
* TKIP now that all other registers are set with correct
* values .
*/
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( entry ) , key0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( entry ) , key1 ) ;
} else {
2009-03-02 15:06:31 +02:00
/* Write key[47:0] */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY0 ( entry ) , key0 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY1 ( entry ) , key1 ) ;
2009-03-02 15:06:31 +02:00
/* Write key[95:48] */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY2 ( entry ) , key2 ) ;
REG_WRITE ( ah , AR_KEYTABLE_KEY3 ( entry ) , key3 ) ;
2009-03-02 15:06:31 +02:00
/* Write key[127:96] and key type */
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_KEYTABLE_KEY4 ( entry ) , key4 ) ;
REG_WRITE ( ah , AR_KEYTABLE_TYPE ( entry ) , keyType ) ;
2008-08-04 00:16:41 -07:00
2009-03-02 15:06:31 +02:00
/* Write MAC address for the entry */
2008-10-29 10:16:30 +05:30
( void ) ath9k_hw_keysetmac ( ah , entry , mac ) ;
}
2008-08-04 00:16:41 -07:00
return true ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_set_keycache_entry ) ;
2008-08-04 00:16:41 -07:00
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
{
2009-02-09 13:27:26 +05:30
if ( entry < ah - > caps . keycache_size ) {
2008-10-29 10:16:30 +05:30
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
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_keyisvalid ) ;
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-09-18 15:04:27 +05:30
if ( ! AR_SREV_5416 ( ah ) )
REG_CLR_BIT ( ah , ( AR_RTC_RESET ) ,
AR_RTC_RESET_EN ) ;
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 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 ) {
2009-02-09 13:27:26 +05:30
struct ath9k_hw_capabilities * pCap = & 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 ;
}
2009-09-18 15:07:03 +05:30
ath9k_hw_init_pll ( ah , NULL ) ;
2008-10-29 10:16:30 +05:30
}
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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_FATAL ,
" 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-09-09 21:10:09 -07:00
bool ath9k_hw_setpower ( struct ath_hw * ah , enum ath9k_power_mode mode )
2008-08-04 00:16:41 -07:00
{
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
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 "
} ;
2009-07-24 17:27:22 +02:00
if ( ah - > power_mode = = mode )
return status ;
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_RESET , " %s -> %s \n " ,
modes [ ah - > power_mode ] , modes [ mode ] ) ;
2008-10-29 10:16:30 +05:30
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:26 +05:30
ah - > chip_fullsleep = 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 :
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_FATAL ,
" Unknown power mode %u \n " , mode ) ;
2008-08-04 00:16:41 -07:00
return false ;
}
2009-02-09 13:27:26 +05:30
ah - > power_mode = mode ;
2008-10-29 10:16:30 +05:30
return status ;
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_setpower ) ;
2008-08-04 00:16:41 -07:00
2009-02-10 15:35:22 -08:00
/*
* Helper for ASPM support .
*
* Disable PLL when in L0s as well as receiver clock when in L1 .
* This power saving option must be enabled through the SerDes .
*
* Programming the SerDes must go through the same 288 bit serial shift
* register as the other analog registers . Hence the 9 writes .
*/
2009-09-17 09:24:58 +05:30
void ath9k_hw_configpcipowersave ( struct ath_hw * ah , int restore , int power_off )
2008-08-04 00:16:41 -07:00
{
2008-10-29 10:16:30 +05:30
u8 i ;
2009-09-17 09:24:58 +05:30
u32 val ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
if ( ah - > is_pciexpress ! = true )
2008-10-29 10:16:30 +05:30
return ;
2008-08-04 00:16:41 -07:00
2009-02-10 15:35:22 -08:00
/* Do not touch SerDes registers */
2009-02-09 13:27:26 +05:30
if ( ah - > config . pcie_powersave_enable = = 2 )
2008-10-29 10:16:30 +05:30
return ;
2009-02-10 15:35:22 -08:00
/* Nothing to do on restore for 11N */
2009-09-17 09:24:58 +05:30
if ( ! restore ) {
if ( AR_SREV_9280_20_OR_LATER ( ah ) ) {
/*
* AR9280 2.0 or later chips use SerDes values from the
* initvals . h initialized depending on chipset during
* ath9k_hw_init ( )
*/
for ( i = 0 ; i < ah - > iniPcieSerdes . ia_rows ; i + + ) {
REG_WRITE ( ah , INI_RA ( & ah - > iniPcieSerdes , i , 0 ) ,
INI_RA ( & ah - > iniPcieSerdes , i , 1 ) ) ;
}
} else if ( AR_SREV_9280 ( ah ) & &
( ah - > hw_version . macRev = = AR_SREV_REVISION_9280_10 ) ) {
REG_WRITE ( ah , AR_PCIE_SERDES , 0x9248fd00 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x24924924 ) ;
/* RX shut off when elecidle is asserted */
REG_WRITE ( ah , AR_PCIE_SERDES , 0xa8000019 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x13160820 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xe5980560 ) ;
/* Shut off CLKREQ active in L1 */
if ( ah - > config . pcie_clock_req )
REG_WRITE ( ah , AR_PCIE_SERDES , 0x401deffc ) ;
else
REG_WRITE ( ah , AR_PCIE_SERDES , 0x401deffd ) ;
2008-10-29 10:16:30 +05:30
2009-09-17 09:24:58 +05:30
REG_WRITE ( ah , AR_PCIE_SERDES , 0x1aaabe40 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xbe105554 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x00043007 ) ;
2008-10-29 10:16:30 +05:30
2009-09-17 09:24:58 +05:30
/* Load the new settings */
REG_WRITE ( ah , AR_PCIE_SERDES2 , 0x00000000 ) ;
2008-10-29 10:16:30 +05:30
2009-09-17 09:24:58 +05:30
} else {
REG_WRITE ( ah , AR_PCIE_SERDES , 0x9248fc00 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x24924924 ) ;
2008-10-29 10:16:30 +05:30
2009-09-17 09:24:58 +05:30
/* RX shut off when elecidle is asserted */
REG_WRITE ( ah , AR_PCIE_SERDES , 0x28000039 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x53160824 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xe5980579 ) ;
2008-10-29 10:16:30 +05:30
2009-09-17 09:24:58 +05:30
/*
* Ignore ah - > ah_config . pcie_clock_req setting for
* pre - AR9280 11 n
*/
REG_WRITE ( ah , AR_PCIE_SERDES , 0x001defff ) ;
2009-02-10 15:35:22 -08:00
2009-09-17 09:24:58 +05:30
REG_WRITE ( ah , AR_PCIE_SERDES , 0x1aaabe40 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0xbe105554 ) ;
REG_WRITE ( ah , AR_PCIE_SERDES , 0x000e3007 ) ;
2009-02-10 15:35:22 -08:00
2009-09-17 09:24:58 +05:30
/* Load the new settings */
REG_WRITE ( ah , AR_PCIE_SERDES2 , 0x00000000 ) ;
}
2009-02-10 15:35:22 -08:00
2009-09-17 09:24:58 +05:30
udelay ( 1000 ) ;
2009-02-10 15:35:22 -08:00
2009-09-17 09:24:58 +05:30
/* set bit 19 to allow forcing of pcie core into L1 state */
REG_SET_BIT ( ah , AR_PCIE_PM_CTRL , AR_PCIE_PM_CTRL_ENA ) ;
2008-08-04 00:16:41 -07:00
2009-09-17 09:24:58 +05:30
/* Several PCIe massages to ensure proper behaviour */
if ( ah - > config . pcie_waen ) {
val = ah - > config . pcie_waen ;
if ( ! power_off )
val & = ( ~ AR_WA_D3_L1_DISABLE ) ;
} else {
if ( AR_SREV_9285 ( ah ) | | AR_SREV_9271 ( ah ) | |
AR_SREV_9287 ( ah ) ) {
val = AR9285_WA_DEFAULT ;
if ( ! power_off )
val & = ( ~ AR_WA_D3_L1_DISABLE ) ;
} else if ( AR_SREV_9280 ( ah ) ) {
/*
* On AR9280 chips bit 22 of 0x4004 needs to be
* set otherwise card may disappear .
*/
val = AR9280_WA_DEFAULT ;
if ( ! power_off )
val & = ( ~ AR_WA_D3_L1_DISABLE ) ;
} else
val = AR_WA_DEFAULT ;
}
2009-02-10 15:35:27 -08:00
2009-09-17 09:24:58 +05:30
REG_WRITE ( ah , AR_WA , val ) ;
}
2008-10-29 10:16:30 +05:30
2009-09-17 09:24:58 +05:30
if ( power_off ) {
2009-02-10 15:35:22 -08:00
/*
2009-09-17 09:24:58 +05:30
* Set PCIe workaround bits
* bit 14 in WA register ( disable L1 ) should only
* be set when device enters D3 and be cleared
* when device comes back to D0 .
2009-02-10 15:35:22 -08:00
*/
2009-09-17 09:24:58 +05:30
if ( ah - > config . pcie_waen ) {
if ( ah - > config . pcie_waen & AR_WA_D3_L1_DISABLE )
REG_SET_BIT ( ah , AR_WA , AR_WA_D3_L1_DISABLE ) ;
} else {
if ( ( ( AR_SREV_9285 ( ah ) | | AR_SREV_9271 ( ah ) | |
AR_SREV_9287 ( ah ) ) & &
( AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE ) ) | |
( AR_SREV_9280 ( ah ) & &
( AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE ) ) ) {
REG_SET_BIT ( ah , AR_WA , AR_WA_D3_L1_DISABLE ) ;
}
}
2008-10-29 10:16:30 +05:30
}
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_configpcipowersave ) ;
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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_intrpend ) ;
2008-08-04 00:16:41 -07:00
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 ;
2009-02-09 13:27:26 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > caps ;
2008-08-04 00:16:41 -07:00
u32 sync_cause = 0 ;
bool fatal_int = false ;
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2008-08-04 00:16:41 -07:00
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 ;
2009-02-12 10:06:47 +05:30
if ( isr2 & AR_ISR_S2_TSFOOR )
mask2 | = ATH9K_INT_TSFOOR ;
2008-08-04 00:16:41 -07:00
}
isr = REG_READ ( ah , AR_ISR_RAC ) ;
if ( isr = = 0xffffffff ) {
* masked = 0 ;
return false ;
}
* masked = isr & ATH9K_INT_COMMON ;
2009-03-30 15:28:35 +05:30
if ( ah - > config . intr_mitigation ) {
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:26 +05:30
ah - > intr_txqs | = MS ( s0_s , AR_ISR_S0_QCU_TXOK ) ;
ah - > intr_txqs | = 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:26 +05:30
ah - > intr_txqs | = MS ( s1_s , AR_ISR_S1_QCU_TXERR ) ;
ah - > intr_txqs | = MS ( s1_s , AR_ISR_S1_QCU_TXEOL ) ;
2008-08-04 00:16:41 -07:00
}
if ( isr & AR_ISR_RXORN ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_INTERRUPT ,
" 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
2009-08-26 21:08:49 +05:30
if ( isr & AR_ISR_GENTMR ) {
u32 s5_s ;
s5_s = REG_READ ( ah , AR_ISR_S5_S ) ;
if ( isr & AR_ISR_GENTMR ) {
ah - > intr_gen_timer_trigger =
MS ( s5_s , AR_ISR_S5_GENTIMER_TRIG ) ;
ah - > intr_gen_timer_thresh =
MS ( s5_s , AR_ISR_S5_GENTIMER_THRESH ) ;
if ( ah - > intr_gen_timer_trigger )
* masked | = ATH9K_INT_GENTIMER ;
}
}
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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_ANY ,
" received PCI FATAL interrupt \n " ) ;
2008-08-04 00:16:41 -07:00
}
if ( sync_cause & AR_INTR_SYNC_HOST1_PERR ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_ANY ,
" received PCI PERR interrupt \n " ) ;
2008-08-04 00:16:41 -07:00
}
2009-04-12 02:57:54 -07:00
* masked | = ATH9K_INT_FATAL ;
2008-08-04 00:16:41 -07:00
}
if ( sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_INTERRUPT ,
" 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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_INTERRUPT ,
" 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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_getisr ) ;
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:26 +05:30
u32 omask = ah - > mask_reg ;
2008-08-04 00:16:41 -07:00
u32 mask , mask2 ;
2009-02-09 13:27:26 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > caps ;
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2008-08-04 00:16:41 -07:00
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_INTERRUPT , " 0x%x => 0x%x \n " , omask , ints ) ;
2008-08-04 00:16:41 -07:00
if ( omask & ATH9K_INT_GLOBAL ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , 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:26 +05:30
if ( ah - > txok_interrupt_mask )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_TXOK ;
2009-02-09 13:27:26 +05:30
if ( ah - > txdesc_interrupt_mask )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_TXDESC ;
2009-02-09 13:27:26 +05:30
if ( ah - > txerr_interrupt_mask )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_TXERR ;
2009-02-09 13:27:26 +05:30
if ( ah - > txeol_interrupt_mask )
2008-08-04 00:16:41 -07:00
mask | = AR_IMR_TXEOL ;
}
if ( ints & ATH9K_INT_RX ) {
mask | = AR_IMR_RXERR ;
2009-03-30 15:28:35 +05:30
if ( ah - > config . intr_mitigation )
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 )
2009-02-12 10:06:47 +05:30
mask2 | = AR_IMR_S2_CABEND ;
if ( ints & ATH9K_INT_TSFOOR )
mask2 | = AR_IMR_S2_TSFOOR ;
2008-08-04 00:16:41 -07:00
}
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 ;
}
2009-09-13 02:42:02 -07:00
ath_print ( common , 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:26 +05:30
ah - > mask_reg = 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 ) {
2009-09-13 02:42:02 -07:00
ath_print ( common , 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 ) ;
}
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_INTERRUPT , " AR_IMR 0x%x IER 0x%x \n " ,
REG_READ ( ah , AR_IMR ) , REG_READ ( ah , AR_IER ) ) ;
2008-08-04 00:16:41 -07:00
}
return omask ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_set_interrupts ) ;
2008-08-04 00:16:41 -07:00
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:26 +05:30
ah - > beacon_interval = beacon_period ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:26 +05:30
switch ( 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 :
2009-03-20 22:59:59 -04:00
case NL80211_IFTYPE_MESH_POINT :
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:26 +05:30
( ah - > atim_window ? ah - >
atim_window : 1 ) ) ) ;
2008-08-04 00:16:41 -07:00
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 -
2009-02-09 13:27:26 +05:30
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 -
2009-02-09 13:27:26 +05:30
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 :
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_BEACON ,
" %s: unsupported opmode: %d \n " ,
__func__ , ah - > opmode ) ;
2008-12-01 13:38:55 -08:00
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 ) {
ath9k_hw_reset_tsf ( ah ) ;
}
REG_SET_BIT ( ah , AR_TIMER_MODE , flags ) ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_beaconinit ) ;
2008-08-04 00:16:41 -07:00
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 ;
2009-02-09 13:27:26 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > caps ;
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
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 ;
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_BEACON , " next DTIM %d \n " , bs - > bs_nextdtim ) ;
ath_print ( common , ATH_DBG_BEACON , " next beacon %d \n " , nextTbtt ) ;
ath_print ( common , ATH_DBG_BEACON , " beacon period %d \n " , beaconintval ) ;
ath_print ( common , 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
2009-02-12 10:06:47 +05:30
/* TSF Out of Range Threshold */
REG_WRITE ( ah , AR_TSFOOR_THRESHOLD , bs - > bs_tsfoor_threshold ) ;
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_set_sta_beacon_timers ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:16:30 +05:30
/*******************/
/* HW Capabilities */
/*******************/
2009-03-30 15:28:28 +05:30
void ath9k_hw_fill_cap_info ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:26 +05:30
struct ath9k_hw_capabilities * pCap = & ah - > caps ;
2009-08-17 18:07:23 -07:00
struct ath_regulatory * regulatory = ath9k_hw_regulatory ( ah ) ;
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2009-09-09 14:52:02 -07:00
struct ath_btcoex_hw * btcoex_hw = & ah - > btcoex_hw ;
2009-08-17 18:07:23 -07:00
2008-10-29 10:16:30 +05:30
u16 capField = 0 , eeval ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:24 +05:30
eeval = ah - > eep_ops - > get_eeprom ( ah , EEP_REG_0 ) ;
2009-08-17 18:07:23 -07:00
regulatory - > current_rd = eeval ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:24 +05:30
eeval = ah - > eep_ops - > get_eeprom ( ah , EEP_REG_1 ) ;
2009-02-12 10:06:43 +05:30
if ( AR_SREV_9285_10_OR_LATER ( ah ) )
eeval | = AR9285_RDEXT_DEFAULT ;
2009-08-17 18:07:23 -07:00
regulatory - > current_rd_ext = eeval ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:24 +05:30
capField = ah - > eep_ops - > get_eeprom ( ah , EEP_OP_CAP ) ;
2008-10-29 10:16:30 +05:30
2009-02-09 13:27:26 +05:30
if ( ah - > opmode ! = NL80211_IFTYPE_AP & &
2009-02-09 13:27:06 +05:30
ah - > hw_version . subvendorid = = AR_SUBVENDOR_ID_NEW_A ) {
2009-08-17 18:07:23 -07:00
if ( regulatory - > current_rd = = 0x64 | |
regulatory - > current_rd = = 0x65 )
regulatory - > current_rd + = 5 ;
else if ( regulatory - > current_rd = = 0x41 )
regulatory - > current_rd = 0x43 ;
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_REGULATORY ,
" regdomain mapped to 0x%x \n " , regulatory - > current_rd ) ;
2008-10-29 10:16:30 +05:30
}
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:24 +05:30
eeval = ah - > eep_ops - > get_eeprom ( ah , EEP_OP_MODE ) ;
2008-10-29 10:16:30 +05:30
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 ) ;
2009-02-09 13:27:26 +05:30
if ( ah - > config . ht_enable ) {
2008-10-29 10:16:30 +05:30
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_11G , pCap - > wireless_modes ) ;
2009-02-09 13:27:26 +05:30
if ( ah - > config . ht_enable ) {
2008-10-29 10:16:30 +05:30
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
2009-02-09 13:27:24 +05:30
pCap - > tx_chainmask = ah - > eep_ops - > get_eeprom ( ah , EEP_TX_MASK ) ;
2009-08-03 23:14:12 -04:00
/*
* For AR9271 we will temporarilly uses the rx chainmax as read from
* the EEPROM .
*/
2009-02-20 15:13:23 +05:30
if ( ( ah - > hw_version . devid = = AR5416_DEVID_PCI ) & &
2009-08-03 23:14:12 -04:00
! ( eeval & AR5416_OPFLAGS_11A ) & &
! ( AR_SREV_9271 ( ah ) ) )
/* CB71: GPIO 0 is pulled down to indicate 3 rx chains */
2009-02-20 15:13:23 +05:30
pCap - > rx_chainmask = ath9k_hw_gpio_get ( ah , 0 ) ? 0x5 : 0x7 ;
else
2009-08-03 23:14:12 -04:00
/* Use rx_chainmask from EEPROM. */
2009-02-20 15:13:23 +05:30
pCap - > rx_chainmask = ah - > eep_ops - > get_eeprom ( ah , EEP_RX_MASK ) ;
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:26 +05:30
ah - > misc_mode | = 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
2009-02-09 13:27:26 +05:30
if ( ah - > config . ht_enable )
2008-10-29 10:16:30 +05:30
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 - > 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_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)
2009-02-09 13:27:26 +05:30
ah - > rfsilent = ah - > eep_ops - > get_eeprom ( ah , EEP_RF_SILENT ) ;
if ( ah - > rfsilent & EEP_RFSILENT_ENABLED ) {
ah - > rfkill_gpio =
MS ( ah - > rfsilent , EEP_RFSILENT_GPIO_SEL ) ;
ah - > rfkill_polarity =
MS ( ah - > rfsilent , EEP_RFSILENT_POLARITY ) ;
2008-10-29 10:16:30 +05:30
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-09-17 09:29:07 +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-08-17 18:07:23 -07:00
if ( 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
}
2009-09-18 15:07:33 +05:30
/* Advertise midband for AR5416 with FCC midband set in eeprom */
if ( regulatory - > current_rd_ext & ( 1 < < REG_EXT_FCC_MIDBAND ) & &
AR_SREV_5416 ( ah ) )
pCap - > reg_cap | = AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND ;
2008-10-29 10:16:30 +05:30
pCap - > num_antcfg_5ghz =
2009-02-09 13:27:24 +05:30
ah - > eep_ops - > get_num_ant_config ( ah , ATH9K_HAL_FREQ_BAND_5GHZ ) ;
2008-10-29 10:16:30 +05:30
pCap - > num_antcfg_2ghz =
2009-02-09 13:27:24 +05:30
ah - > eep_ops - > get_num_ant_config ( ah , ATH9K_HAL_FREQ_BAND_2GHZ ) ;
2008-08-04 00:16:41 -07:00
2009-09-09 15:25:50 +05:30
if ( AR_SREV_9280_10_OR_LATER ( ah ) & &
2009-09-09 16:05:32 -07:00
ath9k_hw_btcoex_supported ( ah ) ) {
2009-09-09 14:52:02 -07:00
btcoex_hw - > btactive_gpio = ATH_BTACTIVE_GPIO ;
btcoex_hw - > wlanactive_gpio = ATH_WLANACTIVE_GPIO ;
2009-08-26 21:08:47 +05:30
2009-09-09 15:25:52 +05:30
if ( AR_SREV_9285 ( ah ) ) {
2009-09-09 14:52:02 -07:00
btcoex_hw - > scheme = ATH_BTCOEX_CFG_3WIRE ;
btcoex_hw - > btpriority_gpio = ATH_BTPRIORITY_GPIO ;
2009-09-09 15:25:52 +05:30
} else {
2009-09-09 14:52:02 -07:00
btcoex_hw - > scheme = ATH_BTCOEX_CFG_2WIRE ;
2009-09-09 15:25:52 +05:30
}
2009-08-26 21:08:47 +05:30
} else {
2009-09-09 14:52:02 -07:00
btcoex_hw - > scheme = ATH_BTCOEX_CFG_NONE ;
2009-01-02 15:35:46 +05:30
}
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
{
2009-08-17 18:07:23 -07:00
struct ath_regulatory * regulatory = ath9k_hw_regulatory ( ah ) ;
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:26 +05:30
return ( ah - > sta_id1_defaults &
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:26 +05:30
return ( ah - > misc_mode & AR_PCU_MIC_NEW_LOC_ENA ) ?
2008-10-29 10:16:30 +05:30
false : true ;
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_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:26 +05:30
return ( ah - > sta_id1_defaults &
2008-10-29 10:16:30 +05:30
AR_STA_ID1_MCAST_KSRCH ) ? true :
false ;
}
}
return false ;
case ATH9K_CAP_TXPOW :
switch ( capability ) {
case 0 :
return 0 ;
case 1 :
2009-08-17 18:07:23 -07:00
* result = regulatory - > power_limit ;
2008-10-29 10:16:30 +05:30
return 0 ;
case 2 :
2009-08-17 18:07:23 -07:00
* result = regulatory - > max_power_level ;
2008-10-29 10:16:30 +05:30
return 0 ;
case 3 :
2009-08-17 18:07:23 -07:00
* result = regulatory - > tp_scale ;
2008-10-29 10:16:30 +05:30
return 0 ;
}
return false ;
2009-02-12 13:57:03 +05:30
case ATH9K_CAP_DS :
return ( AR_SREV_9280_20_OR_LATER ( ah ) & &
( ah - > eep_ops - > get_eeprom ( ah , EEP_RC_CHAIN_MASK ) = = 1 ) )
? false : true ;
2008-10-29 10:16:30 +05:30
default :
return false ;
2008-08-04 00:16:41 -07:00
}
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_getcapability ) ;
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:26 +05:30
ah - > sta_id1_defaults | =
2008-10-29 10:16:30 +05:30
AR_STA_ID1_CRPT_MIC_ENABLE ;
else
2009-02-09 13:27:26 +05:30
ah - > sta_id1_defaults & =
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:26 +05:30
ah - > sta_id1_defaults | = AR_STA_ID1_MCAST_KSRCH ;
2008-10-29 10:16:30 +05:30
else
2009-02-09 13:27:26 +05:30
ah - > sta_id1_defaults & = ~ AR_STA_ID1_MCAST_KSRCH ;
2008-10-29 10:16:30 +05:30
return true ;
default :
return false ;
2008-08-04 00:16:41 -07:00
}
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_setcapability ) ;
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
2009-09-13 23:28:00 -07:00
BUG_ON ( gpio > = 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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_cfg_gpio_input ) ;
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 ) ) )
2009-02-09 13:27:26 +05:30
if ( gpio > = ah - > caps . num_gpio_pins )
2008-10-29 10:16:30 +05:30
return 0xffffffff ;
2008-08-04 00:16:41 -07:00
2009-07-23 10:59:57 +05:30
if ( AR_SREV_9287_10_OR_LATER ( ah ) )
return MS_REG_READ ( AR9287 , gpio ) ! = 0 ;
else if ( AR_SREV_9285_10_OR_LATER ( ah ) )
2008-12-24 18:03:58 +05:30
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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_gpio_get ) ;
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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_cfg_output ) ;
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
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_set_gpio ) ;
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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_getdefantenna ) ;
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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_setantenna ) ;
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 :
2009-02-09 13:27:26 +05:30
if ( ah - > caps . tx_chainmask >
2008-10-29 10:16:30 +05:30
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-08-13 09:34:32 +05:30
ah - > config . diversity_control = 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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_getrxfilter ) ;
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
2009-09-03 12:08:43 +05:30
REG_WRITE ( ah , AR_RX_FILTER , bits ) ;
2008-10-29 10:16:30 +05:30
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 ) ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_setrxfilter ) ;
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
{
2009-09-18 15:07:03 +05:30
if ( ! ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_WARM ) )
return false ;
ath9k_hw_init_pll ( ah , NULL ) ;
return true ;
2008-10-29 10:16:30 +05:30
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_phy_disable ) ;
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
{
2009-09-09 21:10:09 -07:00
if ( ! ath9k_hw_setpower ( ah , ATH9K_PM_AWAKE ) )
2008-10-29 10:16:30 +05:30
return false ;
2008-08-04 00:16:41 -07:00
2009-09-18 15:07:03 +05:30
if ( ! ath9k_hw_set_reset_reg ( ah , ATH9K_RESET_COLD ) )
return false ;
ath9k_hw_init_pll ( ah , NULL ) ;
return true ;
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_disable ) ;
2008-08-04 00:16:41 -07:00
2009-05-08 17:54:51 -07:00
void ath9k_hw_set_txpowerlimit ( struct ath_hw * ah , u32 limit )
2008-08-04 00:16:41 -07:00
{
2009-08-17 18:07:23 -07:00
struct ath_regulatory * regulatory = ath9k_hw_regulatory ( ah ) ;
2009-02-09 13:27:26 +05:30
struct ath9k_channel * chan = 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-08-17 18:07:23 -07:00
regulatory - > power_limit = min ( limit , ( u32 ) MAX_RATE_POWER ) ;
2008-10-03 15:45:27 -07:00
2009-05-08 17:54:51 -07:00
ah - > eep_ops - > set_txpower ( ah , chan ,
2009-08-17 18:07:23 -07:00
ath9k_regd_get_ctl ( regulatory , chan ) ,
2009-05-08 17:54:51 -07:00
channel - > max_antenna_gain * 2 ,
channel - > max_power * 2 ,
min ( ( u32 ) MAX_RATE_POWER ,
2009-08-17 18:07:23 -07:00
( u32 ) regulatory - > power_limit ) ) ;
2008-10-03 15:45:27 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_set_txpowerlimit ) ;
2008-10-03 15:45:27 -07:00
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-09-10 09:22:37 -07:00
memcpy ( ath9k_hw_common ( ah ) - > macaddr , mac , ETH_ALEN ) ;
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_setmac ) ;
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
{
2009-02-09 13:27:26 +05:30
ath9k_hw_set_operating_mode ( ah , ah - > opmode ) ;
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_setopmode ) ;
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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_setmcastfilter ) ;
2008-08-04 00:16:41 -07:00
2009-09-10 08:50:20 -07:00
void ath9k_hw_write_associd ( struct ath_hw * ah )
2008-08-04 00:16:41 -07:00
{
2009-09-10 09:22:37 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
REG_WRITE ( ah , AR_BSS_ID0 , get_unaligned_le32 ( common - > curbssid ) ) ;
REG_WRITE ( ah , AR_BSS_ID1 , get_unaligned_le16 ( common - > curbssid + 4 ) |
( ( common - > curaid & 0x3fff ) < < AR_BSS_ID1_AID_S ) ) ;
2008-08-04 00:16:41 -07:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_write_associd ) ;
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 ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_gettsf64 ) ;
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 , tsf64 & 0xffffffff ) ;
2009-03-02 23:28:38 +01:00
REG_WRITE ( ah , AR_TSF_U32 , ( tsf64 > > 32 ) & 0xffffffff ) ;
2009-01-23 05:44:21 +01:00
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_settsf64 ) ;
2009-01-23 05:44:21 +01:00
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
{
2009-06-21 00:02:15 +02:00
if ( ! ath9k_hw_wait ( ah , AR_SLP32_MODE , AR_SLP32_TSF_WRITE_STATUS , 0 ,
AH_TSF_WRITE_TIMEOUT ) )
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_RESET ,
" AR_SLP32_TSF_WRITE_STATUS limit exceeded \n " ) ;
2009-06-21 00:02:15 +02:00
2008-10-29 10:16:30 +05:30
REG_WRITE ( ah , AR_RESET_TSF , AR_RESET_TSF_ONCE ) ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_reset_tsf ) ;
2008-08-04 00:16:41 -07:00
2009-08-07 09:45:09 +05:30
void 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:26 +05:30
ah - > misc_mode | = AR_PCU_TX_ADD_TSF ;
2008-10-29 10:16:30 +05:30
else
2009-02-09 13:27:26 +05:30
ah - > misc_mode & = ~ AR_PCU_TX_ADD_TSF ;
2008-10-29 10:16:30 +05:30
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_set_tsfadjust ) ;
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 ) ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_RESET ,
" bad slot time %u \n " , us ) ;
2009-02-09 13:27:26 +05:30
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:26 +05:30
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-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_setslottime ) ;
2008-10-29 10:16:30 +05:30
2009-09-13 23:04:44 -07:00
void ath9k_hw_set11nmac2040 ( struct ath_hw * ah )
2008-10-29 10:16:30 +05:30
{
2009-09-13 23:04:44 -07:00
struct ieee80211_conf * conf = & ath9k_hw_common ( ah ) - > hw - > conf ;
2008-10-29 10:16:30 +05:30
u32 macmode ;
2009-09-13 23:04:44 -07:00
if ( conf_is_ht40 ( conf ) & & ! ah - > config . cwm_ignore_extcca )
2008-10-29 10:16:30 +05:30
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-08-26 21:08:49 +05:30
/* HW Generic timers configuration */
static const struct ath_gen_timer_configuration gen_tmr_configuration [ ] =
{
{ AR_NEXT_NDP_TIMER , AR_NDP_PERIOD , AR_TIMER_MODE , 0x0080 } ,
{ AR_NEXT_NDP_TIMER , AR_NDP_PERIOD , AR_TIMER_MODE , 0x0080 } ,
{ AR_NEXT_NDP_TIMER , AR_NDP_PERIOD , AR_TIMER_MODE , 0x0080 } ,
{ AR_NEXT_NDP_TIMER , AR_NDP_PERIOD , AR_TIMER_MODE , 0x0080 } ,
{ AR_NEXT_NDP_TIMER , AR_NDP_PERIOD , AR_TIMER_MODE , 0x0080 } ,
{ AR_NEXT_NDP_TIMER , AR_NDP_PERIOD , AR_TIMER_MODE , 0x0080 } ,
{ AR_NEXT_NDP_TIMER , AR_NDP_PERIOD , AR_TIMER_MODE , 0x0080 } ,
{ AR_NEXT_NDP_TIMER , AR_NDP_PERIOD , AR_TIMER_MODE , 0x0080 } ,
{ AR_NEXT_NDP2_TIMER , AR_NDP2_PERIOD , AR_NDP2_TIMER_MODE , 0x0001 } ,
{ AR_NEXT_NDP2_TIMER + 1 * 4 , AR_NDP2_PERIOD + 1 * 4 ,
AR_NDP2_TIMER_MODE , 0x0002 } ,
{ AR_NEXT_NDP2_TIMER + 2 * 4 , AR_NDP2_PERIOD + 2 * 4 ,
AR_NDP2_TIMER_MODE , 0x0004 } ,
{ AR_NEXT_NDP2_TIMER + 3 * 4 , AR_NDP2_PERIOD + 3 * 4 ,
AR_NDP2_TIMER_MODE , 0x0008 } ,
{ AR_NEXT_NDP2_TIMER + 4 * 4 , AR_NDP2_PERIOD + 4 * 4 ,
AR_NDP2_TIMER_MODE , 0x0010 } ,
{ AR_NEXT_NDP2_TIMER + 5 * 4 , AR_NDP2_PERIOD + 5 * 4 ,
AR_NDP2_TIMER_MODE , 0x0020 } ,
{ AR_NEXT_NDP2_TIMER + 6 * 4 , AR_NDP2_PERIOD + 6 * 4 ,
AR_NDP2_TIMER_MODE , 0x0040 } ,
{ AR_NEXT_NDP2_TIMER + 7 * 4 , AR_NDP2_PERIOD + 7 * 4 ,
AR_NDP2_TIMER_MODE , 0x0080 }
} ;
/* HW generic timer primitives */
/* compute and clear index of rightmost 1 */
static u32 rightmost_index ( struct ath_gen_timer_table * timer_table , u32 * mask )
{
u32 b ;
b = * mask ;
b & = ( 0 - b ) ;
* mask & = ~ b ;
b * = debruijn32 ;
b > > = 27 ;
return timer_table - > gen_timer_index [ b ] ;
}
2009-08-26 21:08:50 +05:30
u32 ath9k_hw_gettsf32 ( struct ath_hw * ah )
2009-08-26 21:08:49 +05:30
{
return REG_READ ( ah , AR_TSF_L32 ) ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_gettsf32 ) ;
2009-08-26 21:08:49 +05:30
struct ath_gen_timer * ath_gen_timer_alloc ( struct ath_hw * ah ,
void ( * trigger ) ( void * ) ,
void ( * overflow ) ( void * ) ,
void * arg ,
u8 timer_index )
{
struct ath_gen_timer_table * timer_table = & ah - > hw_gen_timers ;
struct ath_gen_timer * timer ;
timer = kzalloc ( sizeof ( struct ath_gen_timer ) , GFP_KERNEL ) ;
if ( timer = = NULL ) {
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_FATAL ,
" Failed to allocate memory "
" for hw timer[%d] \n " , timer_index ) ;
2009-08-26 21:08:49 +05:30
return NULL ;
}
/* allocate a hardware generic timer slot */
timer_table - > timers [ timer_index ] = timer ;
timer - > index = timer_index ;
timer - > trigger = trigger ;
timer - > overflow = overflow ;
timer - > arg = arg ;
return timer ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath_gen_timer_alloc ) ;
2009-08-26 21:08:49 +05:30
2009-09-13 02:08:34 -07:00
void ath9k_hw_gen_timer_start ( struct ath_hw * ah ,
struct ath_gen_timer * timer ,
u32 timer_next ,
u32 timer_period )
2009-08-26 21:08:49 +05:30
{
struct ath_gen_timer_table * timer_table = & ah - > hw_gen_timers ;
u32 tsf ;
BUG_ON ( ! timer_period ) ;
set_bit ( timer - > index , & timer_table - > timer_mask . timer_bits ) ;
tsf = ath9k_hw_gettsf32 ( ah ) ;
2009-09-13 02:42:02 -07:00
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_HWTIMER ,
" curent tsf %x period %x "
" timer_next %x \n " , tsf , timer_period , timer_next ) ;
2009-08-26 21:08:49 +05:30
/*
* Pull timer_next forward if the current TSF already passed it
* because of software latency
*/
if ( timer_next < tsf )
timer_next = tsf + timer_period ;
/*
* Program generic timer registers
*/
REG_WRITE ( ah , gen_tmr_configuration [ timer - > index ] . next_addr ,
timer_next ) ;
REG_WRITE ( ah , gen_tmr_configuration [ timer - > index ] . period_addr ,
timer_period ) ;
REG_SET_BIT ( ah , gen_tmr_configuration [ timer - > index ] . mode_addr ,
gen_tmr_configuration [ timer - > index ] . mode_mask ) ;
/* Enable both trigger and thresh interrupt masks */
REG_SET_BIT ( ah , AR_IMR_S5 ,
( SM ( AR_GENTMR_BIT ( timer - > index ) , AR_IMR_S5_GENTIMER_THRESH ) |
SM ( AR_GENTMR_BIT ( timer - > index ) , AR_IMR_S5_GENTIMER_TRIG ) ) ) ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_gen_timer_start ) ;
2009-08-26 21:08:49 +05:30
2009-09-13 02:08:34 -07:00
void ath9k_hw_gen_timer_stop ( struct ath_hw * ah , struct ath_gen_timer * timer )
2009-08-26 21:08:49 +05:30
{
struct ath_gen_timer_table * timer_table = & ah - > hw_gen_timers ;
if ( ( timer - > index < AR_FIRST_NDP_TIMER ) | |
( timer - > index > = ATH_MAX_GEN_TIMER ) ) {
return ;
}
/* Clear generic timer enable bits. */
REG_CLR_BIT ( ah , gen_tmr_configuration [ timer - > index ] . mode_addr ,
gen_tmr_configuration [ timer - > index ] . mode_mask ) ;
/* Disable both trigger and thresh interrupt masks */
REG_CLR_BIT ( ah , AR_IMR_S5 ,
( SM ( AR_GENTMR_BIT ( timer - > index ) , AR_IMR_S5_GENTIMER_THRESH ) |
SM ( AR_GENTMR_BIT ( timer - > index ) , AR_IMR_S5_GENTIMER_TRIG ) ) ) ;
clear_bit ( timer - > index , & timer_table - > timer_mask . timer_bits ) ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath9k_hw_gen_timer_stop ) ;
2009-08-26 21:08:49 +05:30
void ath_gen_timer_free ( struct ath_hw * ah , struct ath_gen_timer * timer )
{
struct ath_gen_timer_table * timer_table = & ah - > hw_gen_timers ;
/* free the hardware generic timer slot */
timer_table - > timers [ timer - > index ] = NULL ;
kfree ( timer ) ;
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath_gen_timer_free ) ;
2009-08-26 21:08:49 +05:30
/*
* Generic Timer Interrupts handling
*/
void ath_gen_timer_isr ( struct ath_hw * ah )
{
struct ath_gen_timer_table * timer_table = & ah - > hw_gen_timers ;
struct ath_gen_timer * timer ;
2009-09-13 02:42:02 -07:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
2009-08-26 21:08:49 +05:30
u32 trigger_mask , thresh_mask , index ;
/* get hardware generic timer interrupt status */
trigger_mask = ah - > intr_gen_timer_trigger ;
thresh_mask = ah - > intr_gen_timer_thresh ;
trigger_mask & = timer_table - > timer_mask . val ;
thresh_mask & = timer_table - > timer_mask . val ;
trigger_mask & = ~ thresh_mask ;
while ( thresh_mask ) {
index = rightmost_index ( timer_table , & thresh_mask ) ;
timer = timer_table - > timers [ index ] ;
BUG_ON ( ! timer ) ;
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_HWTIMER ,
" TSF overflow for Gen timer %d \n " , index ) ;
2009-08-26 21:08:49 +05:30
timer - > overflow ( timer - > arg ) ;
}
while ( trigger_mask ) {
index = rightmost_index ( timer_table , & trigger_mask ) ;
timer = timer_table - > timers [ index ] ;
BUG_ON ( ! timer ) ;
2009-09-13 02:42:02 -07:00
ath_print ( common , ATH_DBG_HWTIMER ,
" Gen timer[%d] trigger \n " , index ) ;
2009-08-26 21:08:49 +05:30
timer - > trigger ( timer - > arg ) ;
}
}
2009-09-23 23:07:00 -04:00
EXPORT_SYMBOL ( ath_gen_timer_isr ) ;
2009-10-27 12:59:33 -04:00
static struct {
u32 version ;
const char * name ;
} ath_mac_bb_names [ ] = {
/* Devices with external radios */
{ AR_SREV_VERSION_5416_PCI , " 5416 " } ,
{ AR_SREV_VERSION_5416_PCIE , " 5418 " } ,
{ AR_SREV_VERSION_9100 , " 9100 " } ,
{ AR_SREV_VERSION_9160 , " 9160 " } ,
/* Single-chip solutions */
{ AR_SREV_VERSION_9280 , " 9280 " } ,
{ AR_SREV_VERSION_9285 , " 9285 " } ,
{ AR_SREV_VERSION_9287 , " 9287 " }
} ;
/* For devices with external radios */
static struct {
u16 version ;
const char * name ;
} ath_rf_names [ ] = {
{ 0 , " 5133 " } ,
{ AR_RAD5133_SREV_MAJOR , " 5133 " } ,
{ AR_RAD5122_SREV_MAJOR , " 5122 " } ,
{ AR_RAD2133_SREV_MAJOR , " 2133 " } ,
{ AR_RAD2122_SREV_MAJOR , " 2122 " }
} ;
/*
* Return the MAC / BB name . " ???? " is returned if the MAC / BB is unknown .
*/
2009-10-27 12:59:34 -04:00
static const char * ath9k_hw_mac_bb_name ( u32 mac_bb_version )
2009-10-27 12:59:33 -04:00
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( ath_mac_bb_names ) ; i + + ) {
if ( ath_mac_bb_names [ i ] . version = = mac_bb_version ) {
return ath_mac_bb_names [ i ] . name ;
}
}
return " ???? " ;
}
/*
* Return the RF name . " ???? " is returned if the RF is unknown .
* Used for devices with external radios .
*/
2009-10-27 12:59:34 -04:00
static const char * ath9k_hw_rf_name ( u16 rf_version )
2009-10-27 12:59:33 -04:00
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( ath_rf_names ) ; i + + ) {
if ( ath_rf_names [ i ] . version = = rf_version ) {
return ath_rf_names [ i ] . name ;
}
}
return " ???? " ;
}
2009-10-27 12:59:34 -04:00
void ath9k_hw_name ( struct ath_hw * ah , char * hw_name , size_t len )
{
int used ;
/* chipsets >= AR9280 are single-chip */
if ( AR_SREV_9280_10_OR_LATER ( ah ) ) {
used = snprintf ( hw_name , len ,
" Atheros AR%s Rev:%x " ,
ath9k_hw_mac_bb_name ( ah - > hw_version . macVersion ) ,
ah - > hw_version . macRev ) ;
}
else {
used = snprintf ( hw_name , len ,
" Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x " ,
ath9k_hw_mac_bb_name ( ah - > hw_version . macVersion ) ,
ah - > hw_version . macRev ,
ath9k_hw_rf_name ( ( ah - > hw_version . analog5GhzRev &
AR_RADIO_SREV_MAJOR ) ) ,
ah - > hw_version . phyRev ) ;
}
hw_name [ used ] = ' \0 ' ;
}
EXPORT_SYMBOL ( ath9k_hw_name ) ;