Commit 6f3b414a authored by Nick Kossifidis's avatar Nick Kossifidis Committed by John W. Linville

ath5k: Update gain_F calibration code and add documentation

 * Update and cleanup rf gain optimization code

 * Add comments and refferences to docs and use sane function names

 * Use only step index on ath5k_gain, no need to have a pointer to
   the current step since we can determine te step from it's index,
   this also allows us to put all other structs on rfgain.h and cleanup
   ath5k.h a little

 * No need for ah_rfgain variable, we use ah_gain.g_state for everything

 * Tested on RF2112B chip but gain_F calibration is not yet done
   (we will finish this on the next patch where we'll rewrite rf-buffer
   handling)

 * Use initial rf gain settings for 2316 and 2317 SoCs introduced on a previous patch

 It seems big but it's mostly cleanup, very few functional changes have been made on phy.c
Signed-off-by: default avatarNick Kossifidis <mickflemm@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 33a31826
...@@ -649,49 +649,21 @@ struct ath5k_beacon_state { ...@@ -649,49 +649,21 @@ struct ath5k_beacon_state {
enum ath5k_rfgain { enum ath5k_rfgain {
AR5K_RFGAIN_INACTIVE = 0, AR5K_RFGAIN_INACTIVE = 0,
AR5K_RFGAIN_ACTIVE,
AR5K_RFGAIN_READ_REQUESTED, AR5K_RFGAIN_READ_REQUESTED,
AR5K_RFGAIN_NEED_CHANGE, AR5K_RFGAIN_NEED_CHANGE,
}; };
#define AR5K_GAIN_CRN_FIX_BITS_5111 4
#define AR5K_GAIN_CRN_FIX_BITS_5112 7
#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112
#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15
#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20
#define AR5K_GAIN_CCK_PROBE_CORR 5
#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15
#define AR5K_GAIN_STEP_COUNT 10
#define AR5K_GAIN_PARAM_TX_CLIP 0
#define AR5K_GAIN_PARAM_PD_90 1
#define AR5K_GAIN_PARAM_PD_84 2
#define AR5K_GAIN_PARAM_GAIN_SEL 3
#define AR5K_GAIN_PARAM_MIX_ORN 0
#define AR5K_GAIN_PARAM_PD_138 1
#define AR5K_GAIN_PARAM_PD_137 2
#define AR5K_GAIN_PARAM_PD_136 3
#define AR5K_GAIN_PARAM_PD_132 4
#define AR5K_GAIN_PARAM_PD_131 5
#define AR5K_GAIN_PARAM_PD_130 6
#define AR5K_GAIN_CHECK_ADJUST(_g) \
((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
struct ath5k_gain_opt_step {
s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
s32 gos_gain;
};
struct ath5k_gain { struct ath5k_gain {
u32 g_step_idx; u8 g_step_idx;
u32 g_current; u8 g_current;
u32 g_target; u8 g_target;
u32 g_low; u8 g_low;
u32 g_high; u8 g_high;
u32 g_f_corr; u8 g_f_corr;
u32 g_active; u8 g_state;
const struct ath5k_gain_opt_step *g_step;
}; };
/********************\ /********************\
COMMON DEFINITIONS COMMON DEFINITIONS
\********************/ \********************/
...@@ -1053,7 +1025,6 @@ struct ath5k_hw { ...@@ -1053,7 +1025,6 @@ struct ath5k_hw {
bool ah_running; bool ah_running;
bool ah_single_chip; bool ah_single_chip;
bool ah_combined_mic; bool ah_combined_mic;
enum ath5k_rfgain ah_rf_gain;
u32 ah_mac_srev; u32 ah_mac_srev;
u16 ah_mac_version; u16 ah_mac_version;
...@@ -1262,9 +1233,9 @@ extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_cha ...@@ -1262,9 +1233,9 @@ extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_cha
/* Initialize RF */ /* Initialize RF */
extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq); extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah); extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah); extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
/* PHY/RF channel functions */ /* PHY/RF channel functions */
extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
......
...@@ -331,7 +331,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ...@@ -331,7 +331,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
ath5k_hw_set_associd(ah, ah->ah_bssid, 0); ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
ath5k_hw_set_opmode(ah); ath5k_hw_set_opmode(ah);
ath5k_hw_set_rfgain_opt(ah); ath5k_hw_rfgain_opt_init(ah);
return ah; return ah;
err_free: err_free:
......
...@@ -2518,7 +2518,7 @@ ath5k_calibrate(unsigned long data) ...@@ -2518,7 +2518,7 @@ ath5k_calibrate(unsigned long data)
ieee80211_frequency_to_channel(sc->curchan->center_freq), ieee80211_frequency_to_channel(sc->curchan->center_freq),
sc->curchan->hw_value); sc->curchan->hw_value);
if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) { if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
/* /*
* Rfgain is out of bounds, reset the chip * Rfgain is out of bounds, reset the chip
* to load new gain values. * to load new gain values.
......
...@@ -78,10 +78,104 @@ static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits, ...@@ -78,10 +78,104 @@ static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits,
return data; return data;
} }
static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) /**********************\
* RF Gain optimization *
\**********************/
/*
* This code is used to optimize rf gain on different environments
* (temprature mostly) based on feedback from a power detector.
*
* It's only used on RF5111 and RF5112, later RF chips seem to have
* auto adjustment on hw -notice they have a much smaller BANK 7 and
* no gain optimization ladder-.
*
* For more infos check out this patent doc
* http://www.freepatentsonline.com/7400691.html
*
* This paper describes power drops as seen on the receiver due to
* probe packets
* http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
* %20of%20Power%20Control.pdf
*
* And this is the MadWiFi bug entry related to the above
* http://madwifi-project.org/ticket/1659
* with various measurements and diagrams
*
* TODO: Deal with power drops due to probes by setting an apropriate
* tx power on the probe packets ! Make this part of the calibration process.
*/
/* Initialize ah_gain durring attach */
int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
{
/* Initialize the gain optimization values */
switch (ah->ah_radio) {
case AR5K_RF5111:
ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
ah->ah_gain.g_low = 20;
ah->ah_gain.g_high = 35;
ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
break;
case AR5K_RF5112:
ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
ah->ah_gain.g_low = 20;
ah->ah_gain.g_high = 85;
ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
break;
default:
return -EINVAL;
}
return 0;
}
/* Schedule a gain probe check on the next transmited packet.
* That means our next packet is going to be sent with lower
* tx power and a Peak to Average Power Detector (PAPD) will try
* to measure the gain.
*
* TODO: Use propper tx power setting for the probe packet so
* that we don't observe a serious power drop on the receiver
*
* XXX: How about forcing a tx packet (bypassing PCU arbitrator etc)
* just after we enable the probe so that we don't mess with
* standard traffic ? Maybe it's time to use sw interrupts and
* a probe tasklet !!!
*/
static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
{
/* Skip if gain calibration is inactive or
* we already handle a probe request */
if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
return;
ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
AR5K_PHY_PAPD_PROBE_TXPOWER) |
AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
}
/* Calculate gain_F measurement correction
* based on the current step for RF5112 rev. 2 */
static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
{ {
u32 mix, step; u32 mix, step;
u32 *rf; u32 *rf;
const struct ath5k_gain_opt *go;
const struct ath5k_gain_opt_step *g_step;
/* Only RF5112 Rev. 2 supports it */
if ((ah->ah_radio != AR5K_RF5112) ||
(ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
return 0;
go = &rfgain_opt_5112;
g_step = &go->go_step[ah->ah_gain.g_step_idx];
if (ah->ah_rf_banks == NULL) if (ah->ah_rf_banks == NULL)
return 0; return 0;
...@@ -89,11 +183,15 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) ...@@ -89,11 +183,15 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
rf = ah->ah_rf_banks; rf = ah->ah_rf_banks;
ah->ah_gain.g_f_corr = 0; ah->ah_gain.g_f_corr = 0;
/* No VGA (Variable Gain Amplifier) override, skip */
if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1) if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1)
return 0; return 0;
/* Mix gain stepping */
step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false); step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false);
mix = ah->ah_gain.g_step->gos_param[0];
/* Mix gain override */
mix = g_step->gos_param[0];
switch (mix) { switch (mix) {
case 3: case 3:
...@@ -113,9 +211,13 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) ...@@ -113,9 +211,13 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
return ah->ah_gain.g_f_corr; return ah->ah_gain.g_f_corr;
} }
static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) /* Check if current gain_F measurement is in the range of our
* power detector windows. If we get a measurement outside range
* we know it's not accurate (detectors can't measure anything outside
* their detection window) so we must ignore it */
static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
{ {
u32 step, mix, level[4]; u32 step, mix_ovr, level[4];
u32 *rf; u32 *rf;
if (ah->ah_rf_banks == NULL) if (ah->ah_rf_banks == NULL)
...@@ -127,20 +229,20 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) ...@@ -127,20 +229,20 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0, step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0,
false); false);
level[0] = 0; level[0] = 0;
level[1] = (step == 0x3f) ? 0x32 : step + 4; level[1] = (step == 63) ? 50 : step + 4;
level[2] = (step != 0x3f) ? 0x40 : level[0]; level[2] = (step != 63) ? 64 : level[0];
level[3] = level[2] + 0x32; level[3] = level[2] + 50 ;
ah->ah_gain.g_high = level[3] - ah->ah_gain.g_high = level[3] -
(step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
ah->ah_gain.g_low = level[0] + ah->ah_gain.g_low = level[0] +
(step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
} else { } else {
mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, mix_ovr = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0,
false); false);
level[0] = level[2] = 0; level[0] = level[2] = 0;
if (mix == 1) { if (mix_ovr == 1) {
level[1] = level[3] = 83; level[1] = level[3] = 83;
} else { } else {
level[1] = level[3] = 107; level[1] = level[3] = 107;
...@@ -154,9 +256,12 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) ...@@ -154,9 +256,12 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
ah->ah_gain.g_current <= level[3]); ah->ah_gain.g_current <= level[3]);
} }
static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) /* Perform gain_F adjustment by choosing the right set
* of parameters from rf gain optimization ladder */
static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
{ {
const struct ath5k_gain_opt *go; const struct ath5k_gain_opt *go;
const struct ath5k_gain_opt_step *g_step;
int ret = 0; int ret = 0;
switch (ah->ah_radio) { switch (ah->ah_radio) {
...@@ -170,35 +275,39 @@ static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) ...@@ -170,35 +275,39 @@ static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah)
return 0; return 0;
} }
ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx]; g_step = &go->go_step[ah->ah_gain.g_step_idx];
if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
/* Reached maximum */
if (ah->ah_gain.g_step_idx == 0) if (ah->ah_gain.g_step_idx == 0)
return -1; return -1;
for (ah->ah_gain.g_target = ah->ah_gain.g_current; for (ah->ah_gain.g_target = ah->ah_gain.g_current;
ah->ah_gain.g_target >= ah->ah_gain.g_high && ah->ah_gain.g_target >= ah->ah_gain.g_high &&
ah->ah_gain.g_step_idx > 0; ah->ah_gain.g_step_idx > 0;
ah->ah_gain.g_step = g_step = &go->go_step[ah->ah_gain.g_step_idx])
&go->go_step[ah->ah_gain.g_step_idx])
ah->ah_gain.g_target -= 2 * ah->ah_gain.g_target -= 2 *
(go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
ah->ah_gain.g_step->gos_gain); g_step->gos_gain);
ret = 1; ret = 1;
goto done; goto done;
} }
if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
/* Reached minimum */
if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
return -2; return -2;
for (ah->ah_gain.g_target = ah->ah_gain.g_current; for (ah->ah_gain.g_target = ah->ah_gain.g_current;
ah->ah_gain.g_target <= ah->ah_gain.g_low && ah->ah_gain.g_target <= ah->ah_gain.g_low &&
ah->ah_gain.g_step_idx < go->go_steps_count-1; ah->ah_gain.g_step_idx < go->go_steps_count-1;
ah->ah_gain.g_step = g_step = &go->go_step[ah->ah_gain.g_step_idx])
&go->go_step[ah->ah_gain.g_step_idx])
ah->ah_gain.g_target -= 2 * ah->ah_gain.g_target -= 2 *
(go->go_step[++ah->ah_gain.g_step_idx].gos_gain - (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
ah->ah_gain.g_step->gos_gain); g_step->gos_gain);
ret = 2; ret = 2;
goto done; goto done;
...@@ -213,6 +322,135 @@ done: ...@@ -213,6 +322,135 @@ done:
return ret; return ret;
} }
/* Main callback for thermal rf gain calibration engine
* Check for a new gain reading and schedule an adjustment
* if needed.
*
* TODO: Use sw interrupt to schedule reset if gain_F needs
* adjustment */
enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
{
u32 data, type;
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
ATH5K_TRACE(ah->ah_sc);
if (ah->ah_rf_banks == NULL ||
ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
return AR5K_RFGAIN_INACTIVE;
/* No check requested, either engine is inactive
* or an adjustment is already requested */
if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
goto done;
/* Read the PAPD (Peak to Average Power Detector)
* register */
data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
/* No probe is scheduled, read gain_F measurement */
if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
/* If tx packet is CCK correct the gain_F measurement
* by cck ofdm gain delta */
if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
ah->ah_gain.g_current +=
ee->ee_cck_ofdm_gain_delta;
else
ah->ah_gain.g_current +=
AR5K_GAIN_CCK_PROBE_CORR;
}
/* Further correct gain_F measurement for
* RF5112A radios */
if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
ath5k_hw_rf_gainf_corr(ah);
ah->ah_gain.g_current =
ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
0;
}
/* Check if measurement is ok and if we need
* to adjust gain, schedule a gain adjustment,
* else switch back to the acive state */
if (ath5k_hw_rf_check_gainf_readback(ah) &&
AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
ath5k_hw_rf_gainf_adjust(ah)) {
ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
} else {
ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
}
}
done:
return ah->ah_gain.g_state;
}
/* 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)
{
const struct ath5k_ini_rfgain *ath5k_rfg;
unsigned int i, size;
switch (ah->ah_radio) {
case AR5K_RF5111:
ath5k_rfg = rfgain_5111;
size = ARRAY_SIZE(rfgain_5111);
break;
case AR5K_RF5112:
ath5k_rfg = rfgain_5112;
size = ARRAY_SIZE(rfgain_5112);
break;
case AR5K_RF2413:
ath5k_rfg = rfgain_2413;
size = ARRAY_SIZE(rfgain_2413);
break;
case AR5K_RF2316:
ath5k_rfg = rfgain_2316;
size = ARRAY_SIZE(rfgain_2316);
break;
case AR5K_RF5413:
ath5k_rfg = rfgain_5413;
size = ARRAY_SIZE(rfgain_5413);
break;
case AR5K_RF2317:
case AR5K_RF2425:
ath5k_rfg = rfgain_2425;
size = ARRAY_SIZE(rfgain_2425);
break;
default:
return -EINVAL;
}
switch (freq) {
case AR5K_INI_RFGAIN_2GHZ:
case AR5K_INI_RFGAIN_5GHZ:
break;
default:
return -EINVAL;
}
for (i = 0; i < size; i++) {
AR5K_REG_WAIT(i);
ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
(u32)ath5k_rfg[i].rfg_register);
}
return 0;
}
/********************\
* RF Registers setup *
\********************/
/* /*
* Read EEPROM Calibration data, modify RF Banks and Initialize RF5111 * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111
*/ */
...@@ -311,6 +549,8 @@ static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah, ...@@ -311,6 +549,8 @@ static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah,
ath5k_hw_reg_write(ah, rf[i], rfb_5111[i].rfb_ctrl_register); ath5k_hw_reg_write(ah, rf[i], rfb_5111[i].rfb_ctrl_register);
} }
ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
return 0; return 0;
} }
...@@ -407,6 +647,9 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, ...@@ -407,6 +647,9 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah,
for (i = 0; i < rf_size; i++) for (i = 0; i < rf_size; i++)
ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register); ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register);
ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
return 0; return 0;
} }
...@@ -536,125 +779,12 @@ int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, ...@@ -536,125 +779,12 @@ int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel,
} }
ret = func(ah, channel, mode); ret = func(ah, channel, mode);
if (!ret)
ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE;
return ret; return ret;
} }
int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
{
const struct ath5k_ini_rfgain *ath5k_rfg;
unsigned int i, size;
switch (ah->ah_radio) {
case AR5K_RF5111:
ath5k_rfg = rfgain_5111;
size = ARRAY_SIZE(rfgain_5111);
break;
case AR5K_RF5112:
ath5k_rfg = rfgain_5112;
size = ARRAY_SIZE(rfgain_5112);
break;
case AR5K_RF5413:
ath5k_rfg = rfgain_5413;
size = ARRAY_SIZE(rfgain_5413);
break;
case AR5K_RF2413:
ath5k_rfg = rfgain_2413;
size = ARRAY_SIZE(rfgain_2413);
break;
case AR5K_RF2425:
ath5k_rfg = rfgain_2425;
size = ARRAY_SIZE(rfgain_2425);
break;
default:
return -EINVAL;
}
switch (freq) {
case AR5K_INI_RFGAIN_2GHZ:
case AR5K_INI_RFGAIN_5GHZ:
break;
default:
return -EINVAL;
}
for (i = 0; i < size; i++) {
AR5K_REG_WAIT(i);
ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
(u32)ath5k_rfg[i].rfg_register);
}
return 0;
}
enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah)
{
u32 data, type;
ATH5K_TRACE(ah->ah_sc);
if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active ||
ah->ah_version <= AR5K_AR5211)
return AR5K_RFGAIN_INACTIVE;
if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED)
goto done;
data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK)
ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR;
if (ah->ah_radio >= AR5K_RF5112) {
ath5k_hw_rfregs_gainf_corr(ah);
ah->ah_gain.g_current =
ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
0;
}
if (ath5k_hw_rfregs_gain_readback(ah) &&
AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
ath5k_hw_rfregs_gain_adjust(ah))
ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE;
}
done:
return ah->ah_rf_gain;
}
int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah)
{
/* Initialize the gain optimization values */
switch (ah->ah_radio) {
case AR5K_RF5111:
ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
ah->ah_gain.g_step =
&rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx];
ah->ah_gain.g_low = 20;
ah->ah_gain.g_high = 35;
ah->ah_gain.g_active = 1;
break;
case AR5K_RF5112:
ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
ah->ah_gain.g_step =
&rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx];
ah->ah_gain.g_low = 20;
ah->ah_gain.g_high = 85;
ah->ah_gain.g_active = 1;
break;
default:
return -EINVAL;
}
return 0;
}
/**************************\ /**************************\
PHY/RF channel functions PHY/RF channel functions
...@@ -1176,13 +1306,8 @@ done: ...@@ -1176,13 +1306,8 @@ done:
* as often as I/Q calibration.*/ * as often as I/Q calibration.*/
ath5k_hw_noise_floor_calibration(ah, channel->center_freq); ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
/* Request RF gain */ /* Initiate a gain_F calibration */
if (channel->hw_value & CHANNEL_5GHZ) { ath5k_hw_request_rfgain_probe(ah);
ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
AR5K_PHY_PAPD_PROBE_TXPOWER) |
AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED;
}
return 0; return 0;
} }
......
...@@ -441,9 +441,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ...@@ -441,9 +441,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
if (change_channel && ah->ah_rf_banks != NULL)
ath5k_hw_get_rf_gain(ah);
/*Wakeup the device*/ /*Wakeup the device*/
ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
...@@ -530,7 +527,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ...@@ -530,7 +527,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
* Write initial RF gain settings * Write initial RF gain settings
* This should work for both 5111/5112 * This should work for both 5111/5112
*/ */
ret = ath5k_hw_rfgain(ah, freq); ret = ath5k_hw_rfgain_init(ah, freq);
if (ret) if (ret)
return ret; return ret;
......
...@@ -111,6 +111,7 @@ enum ath5k_rf_regs_idx { ...@@ -111,6 +111,7 @@ enum ath5k_rf_regs_idx {
#define AR5K_RF5111_GAIN_I { 6, 29, 0 } #define AR5K_RF5111_GAIN_I { 6, 29, 0 }
#define AR5K_RF5111_PLO_SEL { 1, 4, 0 } #define AR5K_RF5111_PLO_SEL { 1, 4, 0 }
#define AR5K_RF5111_RFGAIN_SEL { 1, 36, 0 } #define AR5K_RF5111_RFGAIN_SEL { 1, 36, 0 }
#define AR5K_RF5111_RFGAIN_STEP { 6, 37, 0 }
/* Only on AR5212 BaseBand and up */ /* Only on AR5212 BaseBand and up */
#define AR5K_RF5111_WAIT_S { 5, 19, 0 } #define AR5K_RF5111_WAIT_S { 5, 19, 0 }
#define AR5K_RF5111_WAIT_I { 5, 24, 0 } #define AR5K_RF5111_WAIT_I { 5, 24, 0 }
...@@ -235,7 +236,9 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = { ...@@ -235,7 +236,9 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = {
/* BANK 7 (Common) len pos col */ /* BANK 7 (Common) len pos col */
#define AR5K_RF5112X_GAIN_I { 6, 14, 0 } #define AR5K_RF5112X_GAIN_I { 6, 14, 0 }
#define AR5K_RF5112X_MIXVGA_OVR { 1, 36, 0 }
#define AR5K_RF5112X_MIXGAIN_OVR { 2, 37, 0 } #define AR5K_RF5112X_MIXGAIN_OVR { 2, 37, 0 }
#define AR5K_RF5112X_MIXGAIN_STEP { 4, 32, 0 }
#define AR5K_RF5112X_PD_DELAY_A { 4, 58, 0 } #define AR5K_RF5112X_PD_DELAY_A { 4, 58, 0 }
#define AR5K_RF5112X_PD_DELAY_B { 4, 62, 0 } #define AR5K_RF5112X_PD_DELAY_B { 4, 62, 0 }
#define AR5K_RF5112X_PD_DELAY_XR { 4, 66, 0 } #define AR5K_RF5112X_PD_DELAY_XR { 4, 66, 0 }
......
...@@ -441,12 +441,38 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = { ...@@ -441,12 +441,38 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = {
{ AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } }, { AR5K_RF_GAIN(63), { 0x00000000, 0x000000f9 } },
}; };
#define AR5K_GAIN_CRN_FIX_BITS_5111 4
#define AR5K_GAIN_CRN_FIX_BITS_5112 7
#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112
#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15
#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20
#define AR5K_GAIN_CCK_PROBE_CORR 5
#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15
#define AR5K_GAIN_STEP_COUNT 10
/* Check if our current measurement is inside our
* current variable attenuation window */
#define AR5K_GAIN_CHECK_ADJUST(_g) \
((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
struct ath5k_gain_opt_step {
s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
s8 gos_gain;
};
struct ath5k_gain_opt { struct ath5k_gain_opt {
u32 go_default; u8 go_default;
u32 go_steps_count; u8 go_steps_count;
const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT];
}; };
/*
* Parameters on gos_param:
* 1) Tx clip PHY register
* 2) PWD 90 RF register
* 3) PWD 84 RF register
* 4) RFGainSel RF register
*/
static const struct ath5k_gain_opt rfgain_opt_5111 = { static const struct ath5k_gain_opt rfgain_opt_5111 = {
4, 4,
9, 9,
...@@ -463,6 +489,16 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = { ...@@ -463,6 +489,16 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = {
} }
}; };
/*
* Parameters on gos_param:
* 1) Mixgain ovr RF register
* 2) PWD 138 RF register
* 3) PWD 137 RF register
* 4) PWD 136 RF register
* 5) PWD 132 RF register
* 6) PWD 131 RF register
* 7) PWD 130 RF register
*/
static const struct ath5k_gain_opt rfgain_opt_5112 = { static const struct ath5k_gain_opt rfgain_opt_5112 = {
1, 1,
8, 8,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment