ath5k: Reset cleanup and generic cleanup

* No functional changes

 * Clean up reset:
 Introduce init functions for each unit and call them instead
 of having everything inside ath5k_hw_reset (it's just c/p for
 now so nothing changes except calling order -I tested it with
 various cards and it's ok-)

 * Further cleanups:
 ofdm_timings belongs to phy.c
 rate_duration belongs to pcu.c
 clock functions are general and belong to reset.c (more to follow)

 * Reorder functions for better organization:
 We start with helpers and other functions follow in categories,
 init functions are last

 Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>

Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Nick Kossifidis
2010-11-23 20:36:45 +02:00
committed by John W. Linville
parent ea066d5a91
commit 9320b5c4a7
9 changed files with 1053 additions and 905 deletions

View File

@ -29,6 +29,95 @@
#include "rfbuffer.h"
#include "rfgain.h"
/******************\
* Helper functions *
\******************/
/*
* Get the PHY Chip revision
*/
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
{
unsigned int i;
u32 srev;
u16 ret;
/*
* Set the radio chip access register
*/
switch (chan) {
case CHANNEL_2GHZ:
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
break;
case CHANNEL_5GHZ:
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
break;
default:
return 0;
}
mdelay(2);
/* ...wait until PHY is ready and read the selected radio revision */
ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
for (i = 0; i < 8; i++)
ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
if (ah->ah_version == AR5K_AR5210) {
srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
} else {
srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
((srev & 0x0f) << 4), 8);
}
/* Reset to the 5GHz mode */
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
return ret;
}
/*
* Check if a channel is supported
*/
bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
{
/* Check if the channel is in our supported range */
if (flags & CHANNEL_2GHZ) {
if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
(freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
return true;
} else if (flags & CHANNEL_5GHZ)
if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
(freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
return true;
return false;
}
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
{
u8 refclk_freq;
if ((ah->ah_radio == AR5K_RF5112) ||
(ah->ah_radio == AR5K_RF5413) ||
(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
refclk_freq = 40;
else
refclk_freq = 32;
if ((channel->center_freq % refclk_freq != 0) &&
((channel->center_freq % refclk_freq < 10) ||
(channel->center_freq % refclk_freq > 22)))
return true;
else
return false;
}
/*
* Used to modify RF Banks before writing them to AR5K_RF_BUFFER
*/
@ -110,6 +199,78 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
return data;
}
/**
* ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
*
* @ah: the &struct ath5k_hw
* @channel: the currently set channel upon reset
*
* Write the delta slope coefficient (used on pilot tracking ?) for OFDM
* operation on the AR5212 upon reset. This is a helper for ath5k_hw_phy_init.
*
* Since delta slope is floating point we split it on its exponent and
* mantissa and provide these values on hw.
*
* For more infos i think this patent is related
* http://www.freepatentsonline.com/7184495.html
*/
static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
{
/* Get exponent and mantissa and set it */
u32 coef_scaled, coef_exp, coef_man,
ds_coef_exp, ds_coef_man, clock;
BUG_ON(!(ah->ah_version == AR5K_AR5212) ||
!(channel->hw_value & CHANNEL_OFDM));
/* Get coefficient
* ALGO: coef = (5 * clock / carrier_freq) / 2
* we scale coef by shifting clock value by 24 for
* better precision since we use integers */
/* TODO: Half/quarter rate */
clock = (channel->hw_value & CHANNEL_TURBO) ? 80 : 40;
coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
/* Get exponent
* ALGO: coef_exp = 14 - highest set bit position */
coef_exp = ilog2(coef_scaled);
/* Doesn't make sense if it's zero*/
if (!coef_scaled || !coef_exp)
return -EINVAL;
/* Note: we've shifted coef_scaled by 24 */
coef_exp = 14 - (coef_exp - 24);
/* Get mantissa (significant digits)
* ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
coef_man = coef_scaled +
(1 << (24 - coef_exp - 1));
/* Calculate delta slope coefficient exponent
* and mantissa (remove scaling) and set them on hw */
ds_coef_man = coef_man >> (24 - coef_exp);
ds_coef_exp = coef_exp - 16;
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
return 0;
}
int ath5k_hw_phy_disable(struct ath5k_hw *ah)
{
/*Just a try M.F.*/
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
return 0;
}
/**********************\
* RF Gain optimization *
\**********************/
@ -436,7 +597,7 @@ done:
/* Write initial RF gain table to set the RF sensitivity
* this one works on all RF chips and has nothing to do
* with gain_F calibration */
int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
{
const struct ath5k_ini_rfgain *ath5k_rfg;
unsigned int i, size;
@ -494,12 +655,11 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
* RF Registers setup *
\********************/
/*
* Setup RF registers by writing RF buffer on hw
*/
int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
unsigned int mode)
static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
struct ieee80211_channel *channel, unsigned int mode)
{
const struct ath5k_rf_reg *rf_regs;
const struct ath5k_ini_rfbuffer *ini_rfb;
@ -821,24 +981,6 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
PHY/RF channel functions
\**************************/
/*
* Check if a channel is supported
*/
bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
{
/* Check if the channel is in our supported range */
if (flags & CHANNEL_2GHZ) {
if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
(freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
return true;
} else if (flags & CHANNEL_5GHZ)
if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
(freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
return true;
return false;
}
/*
* Convertion needed for RF5110
*/
@ -1045,7 +1187,8 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
/*
* Set a channel on the radio chip
*/
int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
static int ath5k_hw_channel(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
{
int ret;
/*
@ -1419,31 +1562,12 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
return ret;
}
/***************************\
* Spur mitigation functions *
\***************************/
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
{
u8 refclk_freq;
if ((ah->ah_radio == AR5K_RF5112) ||
(ah->ah_radio == AR5K_RF5413) ||
(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
refclk_freq = 40;
else
refclk_freq = 32;
if ((channel->center_freq % refclk_freq != 0) &&
((channel->center_freq % refclk_freq < 10) ||
(channel->center_freq % refclk_freq > 22)))
return true;
else
return false;
}
void
static void
ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
{
@ -1666,63 +1790,6 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
}
}
/********************\
Misc PHY functions
\********************/
int ath5k_hw_phy_disable(struct ath5k_hw *ah)
{
/*Just a try M.F.*/
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
return 0;
}
/*
* Get the PHY Chip revision
*/
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
{
unsigned int i;
u32 srev;
u16 ret;
/*
* Set the radio chip access register
*/
switch (chan) {
case CHANNEL_2GHZ:
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
break;
case CHANNEL_5GHZ:
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
break;
default:
return 0;
}
mdelay(2);
/* ...wait until PHY is ready and read the selected radio revision */
ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
for (i = 0; i < 8; i++)
ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
if (ah->ah_version == AR5K_AR5210) {
srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
} else {
srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
((srev & 0x0f) << 4), 8);
}
/* Reset to the 5GHz mode */
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
return ret;
}
/*****************\
* Antenna control *
@ -2984,7 +3051,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
/*
* Set transmission power
*/
int
static int
ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 ee_mode, u8 txpower)
{
@ -3108,3 +3175,176 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
return ath5k_hw_txpower(ah, channel, ee_mode, txpower);
}
/*************\
Init function
\*************/
int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 mode, u8 ee_mode, u8 freq)
{
int ret, i;
u32 phy_tst1;
ret = 0;
/*
* 5211/5212 Specific
*/
if (ah->ah_version != AR5K_AR5210) {
/*
* Write initial RF gain settings
* This should work for both 5111/5112
*/
ret = ath5k_hw_rfgain_init(ah, freq);
if (ret)
return ret;
mdelay(1);
/*
* Set TX power
*/
ret = ath5k_hw_txpower(ah, channel, ee_mode,
ah->ah_txpower.txp_max_pwr / 2);
if (ret)
return ret;
/*
* Write RF buffer
*/
ret = ath5k_hw_rfregs_init(ah, channel, mode);
if (ret)
return ret;
/* Write OFDM timings on 5212*/
if (ah->ah_version == AR5K_AR5212 &&
channel->hw_value & CHANNEL_OFDM) {
ret = ath5k_hw_write_ofdm_timings(ah, channel);
if (ret)
return ret;
/* Spur info is available only from EEPROM versions
* greater than 5.3, but the EEPROM routines will use
* static values for older versions */
if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
ath5k_hw_set_spur_mitigation_filter(ah,
channel);
}
/*Enable/disable 802.11b mode on 5111
(enable 2111 frequency converter + CCK)*/
if (ah->ah_radio == AR5K_RF5111) {
if (mode == AR5K_MODE_11B)
AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
AR5K_TXCFG_B_MODE);
else
AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
AR5K_TXCFG_B_MODE);
}
} else {
/*
* For 5210 we do all initialization using
* initvals, so we don't have to modify
* any settings (5210 also only supports
* a/aturbo modes)
*/
mdelay(1);
/* Disable phy and wait */
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
mdelay(1);
}
/* Set channel on PHY */
ret = ath5k_hw_channel(ah, channel);
if (ret)
return ret;
/*
* Enable the PHY and wait until completion
* This includes BaseBand and Synthesizer
* activation.
*/
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
/*
* On 5211+ read activation -> rx delay
* and use it.
*
* TODO: Half/quarter rate support
*/
if (ah->ah_version != AR5K_AR5210) {
u32 delay;
delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
AR5K_PHY_RX_DELAY_M;
delay = (channel->hw_value & CHANNEL_CCK) ?
((delay << 2) / 22) : (delay / 10);
udelay(100 + (2 * delay));
} else {
mdelay(1);
}
/*
* Perform ADC test to see if baseband is ready
* Set TX hold and check ADC test register
*/
phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
for (i = 0; i <= 20; i++) {
if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
break;
udelay(200);
}
ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
/*
* Start automatic gain control calibration
*
* During AGC calibration RX path is re-routed to
* a power detector so we don't receive anything.
*
* This method is used to calibrate some static offsets
* used together with on-the fly I/Q calibration (the
* one performed via ath5k_hw_phy_calibrate), which doesn't
* interrupt rx path.
*
* While rx path is re-routed to the power detector we also
* start a noise floor calibration to measure the
* card's noise floor (the noise we measure when we are not
* transmitting or receiving anything).
*
* If we are in a noisy environment, AGC calibration may time
* out and/or noise floor calibration might timeout.
*/
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
/* At the same time start I/Q calibration for QAM constellation
* -no need for CCK- */
ah->ah_calibration = false;
if (!(mode == AR5K_MODE_11B)) {
ah->ah_calibration = true;
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
AR5K_PHY_IQ_RUN);
}
/* Wait for gain calibration to finish (we check for I/Q calibration
* during ath5k_phy_calibrate) */
if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_CAL, 0, false)) {
ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
channel->center_freq);
}
/* Restore antenna mode */
ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
return ret;
}