ath9k_ar5008_phy.c revision a734c64bff58bda2fa48c2795453e092167b0ff7
/*
* Copyright (c) 2008-2011 Atheros Communications Inc.
*
* Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
* Original from Linux kernel 3.0.1
*
* 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 "hw.h"
#include "hw-ops.h"
#include "../regd.h"
#include "ar9002_phy.h"
/* All code below is for AR5008, AR9001, AR9002 */
static const int firstep_table[] =
/* level: 0 1 2 3 4 5 6 7 8 */
{ -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
static const int cycpwrThr1_table[] =
/* level: 0 1 2 3 4 5 6 7 8 */
{ -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */
/*
* register values to turn OFDM weak signal detection OFF
*/
static const int m1ThreshLow_off = 127;
static const int m2ThreshLow_off = 127;
static const int m1Thresh_off = 127;
static const int m2Thresh_off = 127;
static const int m2CountThr_off = 31;
static const int m2CountThrLow_off = 63;
static const int m1ThreshLowExt_off = 127;
static const int m2ThreshLowExt_off = 127;
static const int m1ThreshExt_off = 127;
static const int m2ThreshExt_off = 127;
int col)
{
unsigned int i;
}
{
unsigned int r;
}
}
/**
* ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters
* @rfbuf:
* @reg32:
* @numBits:
* @firstBit:
* @column:
*
* Performs analog "swizzling" of parameters into their location.
*/
{
while (bitsLeft > 0) {
(column * 8);
bitPosition = 0;
arrayEntry++;
}
}
/*
* Fix on 2.4 GHz band for orientation sensitivity issue by increasing
* rf_pwd_icsyndiv.
*
* Theoretical Rules:
* if 2 GHz band
* if forceBiasAuto
* if synth_freq < 2412
* bias = 0
* else if 2412 <= synth_freq <= 2422
* bias = 1
* else // synth_freq > 2422
* bias = 2
* else if forceBias > 0
* bias = forceBias & 7
* else
* no change, use value from ini file
* else
* no change, invalid band
*
* 1st Mod:
* 2422 also uses value of 2
* <approved>
*
* 2nd Mod:
* Less than 2412 uses value of 0, 2412 and above uses value of 2
*/
{
unsigned int reg_writes = 0;
return;
if (synth_freq < 2412)
new_bias = 0;
else if (synth_freq < 2422)
new_bias = 1;
else
new_bias = 2;
/* pre-reverse this field */
DBG("ath9k: Force rf_pwd_icsyndiv to %1d on %4d\n",
/* swizzle rf_pwd_icsyndiv */
/* write Bank 6 with new params */
}
/**
* @ah: atheros hardware structure
* @chan:
*
* the channel value. Assumes writes enabled to analog bus and bank6 register
* cache in ah->analogBank6Data.
*/
{
u32 channelSel = 0;
u32 bModeSynth = 0;
u32 aModeRefSel = 0;
struct chan_centers centers;
if (freq < 4800) {
bModeSynth = 0;
bModeSynth = 1;
} else {
return -EINVAL;
}
if (freq == 2484) {
} else {
}
} else if ((freq % 10) == 0) {
else
} else if ((freq % 5) == 0) {
} else {
return -EINVAL;
}
reg32 =
(1 << 5) | 0x1;
return 0;
}
/**
* ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios
* @ah: atheros hardware structure
* @chan:
*
* For non single-chip solutions. Converts to baseband spur frequency given the
* input channel frequency and compute register settings below.
*/
struct ath9k_channel *chan)
{
int bb_spur = AR_NO_SPUR;
int spur_freq_sd;
int spur_delta_phase;
int denominator;
int i;
static int pilot_mask_reg[4] = {
};
static int chan_mask_reg[4] = {
};
int tmp_mask;
int cur_bb_spur;
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
if (AR_NO_SPUR == cur_bb_spur)
break;
break;
}
}
if (AR_NO_SPUR == bb_spur)
return;
cur_bin = -6000;
for (i = 0; i < 4; i++) {
int pilot_mask = 0;
int chan_mask = 0;
int bp = 0;
}
cur_bin += 100;
}
}
cur_vit_mask = 6100;
for (i = 0; i < 123; i++) {
/* workaround for gcc bug #37014 */
if (tmp_v < 75)
mask_amt = 1;
else
mask_amt = 0;
if (cur_vit_mask < 0)
else
}
cur_vit_mask -= 100;
}
}
/**
* ar5008_hw_rf_alloc_ext_banks - allocates banks for external radio programming
* @ah: atheros hardware structure
*
*/
{
if (!bank) { \
DBG("ath9k: Cannot allocate RF banks\n"); \
return -ENOMEM; \
} \
} while (0);
return 0;
}
/**
* ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
* @ah: atheros hardware struture
*/
{
#define ATH_FREE_BANK(bank) do { \
} while (0);
}
/* *
* ar5008_hw_set_rf_regs - programs rf registers based on EEPROM
* @ah: atheros hardware structure
* @chan:
* @modesIndex:
*
*
* Reads the EEPROM header info from the device structure and programs
* all rf registers. This routine requires access to the analog
* rf device. This is not required for single-chip devices.
*/
struct ath9k_channel *chan,
{
unsigned int regWrites = 0;
/*
* Software does not need to program bank data
* for single chip devices, that is AR9280 or anything
* after that.
*/
if (AR_SREV_9280_20_OR_LATER(ah))
return 1;
/* Setup rf parameters */
/* Setup Bank 0 Write */
/* Setup Bank 1 Write */
/* Setup Bank 2 Write */
/* Setup Bank 6 Write */
{
unsigned int i;
ah->analogBank6Data[i] =
}
}
if (eepMinorRev >= 2) {
if (IS_CHAN_2GHZ(chan)) {
} else {
}
}
/* Setup Bank 7 Setup */
/* Write Analog registers */
return 1;
}
struct ath9k_channel *chan)
{
else
synthDelay /= 10;
}
{
int rx_chainmask, tx_chainmask;
switch (rx_chainmask) {
case 0x5:
case 0x3:
break;
}
case 0x1:
case 0x2:
case 0x7:
break;
default:
break;
}
if (tx_chainmask == 0x5) {
}
if (AR_SREV_9100(ah))
}
{
/*
* 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.
*/
if (AR_SREV_9280_20_OR_LATER(ah)) {
if (!AR_SREV_9271(ah))
if (AR_SREV_9287_11_OR_LATER(ah))
}
if (!AR_SREV_5416_20_OR_LATER(ah) ||
return;
/*
* Disable BB clock gating
* Necessary to avoid issues on AR5416 2.0
*/
/*
* Disable RIFS search on some chips to avoid baseband
* hang issues.
*/
}
}
struct ath9k_channel *chan)
{
u32 enableDacFifo = 0;
if (AR_SREV_9285_12_OR_LATER(ah))
if (IS_CHAN_HT40(chan)) {
}
}
struct ath9k_channel *chan)
{
unsigned int i, regWrites = 0;
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;
}
/*
* Set correct baseband to analog shift setting to
* access analog chips.
*/
/* Write ADDAC shifts */
if (AR_SREV_5416_22_OR_LATER(ah)) {
} else {
struct ar5416IniArray temp;
/* For AR5416 2.0/2.1 */
/* override CLKDRV value at [row, column] = [31, 1] */
}
val &= ~AR_AN_TOP2_PWDCLKIND;
udelay(100);
}
}
if (AR_SREV_9271_10(ah))
/* Write common array parameters */
udelay(100);
}
}
if (AR_SREV_9271(ah)) {
else
}
}
/* Set TX power */
0,
/* Write analog registers */
DBG("ath9k: ar5416SetRfRegs failed\n");
return -EIO;
}
return 0;
}
{
return;
if (!AR_SREV_9280_20_OR_LATER(ah))
}
{
}
struct ath9k_channel *chan)
{
struct chan_centers centers;
if (IS_CHAN_HALF_RATE(chan))
else if (IS_CHAN_QUARTER_RATE(chan))
&ds_coef_exp);
&ds_coef_exp);
}
{
}
{
else
synthDelay /= 10;
}
{
}
}
{
if (value)
else
}
struct ath9k_channel *chan)
{
return 0x1450;
return 0x1458;
}
struct ath9k_channel *chan)
{
else
return pll;
}
struct ath9k_channel *chan)
{
else
return pll;
}
enum ath9k_ani_cmd cmd,
int param)
{
DBG("ath9k: "
"level out of range (%d > %zd)\n",
return 0;
}
break;
}
m1ThreshLow[on]);
m2ThreshLow[on]);
m2CountThr[on]);
m2CountThrLow[on]);
m1ThreshLow[on]);
m2ThreshLow[on]);
if (on)
else
if (on)
else
}
break;
}
if (high)
else
}
break;
}
case ATH9K_ANI_FIRSTEP_LEVEL:{
DBG("ath9k: "
"level out of range (%d > %zd)\n",
return 0;
}
break;
}
DBG("ath9k: "
"level out of range (%d > %zd)\n",
return 0;
}
cycpwrThr1[level]);
break;
}
case ATH9K_ANI_PRESENT:
break;
default:
return 0;
}
DBG2("ath9k: ANI parameters:\n");
DBG2(
"noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n",
DBG2(
"cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n",
DBG2(
"ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
return 1;
}
enum ath9k_ani_cmd cmd,
int param)
{
/*
* on == 1 means ofdm weak signal detection is ON
* on == 1 is the default, for less noise immunity
*
* on == 0 means ofdm weak signal detection is OFF
* on == 0 means more noise imm
*/
/*
* make register setting for default
* (weak sig detect ON) come from INI file
*/
int m1ThreshLow = on ?
int m2ThreshLow = on ?
int m2CountThr = on ?
int m2CountThrLow = on ?
int m1ThreshLowExt = on ?
int m2ThreshLowExt = on ?
int m1ThreshExt = on ?
int m2ThreshExt = on ?
if (on)
else
DBG2("ath9k: "
"** ch %d: ofdm weak signal: %s=>%s\n",
"on" : "off",
if (on)
else
}
break;
}
case ATH9K_ANI_FIRSTEP_LEVEL:{
DBG("ath9k: "
"ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%d > %zd)\n",
return 0;
}
/*
* make register setting relative to default
* from INI file & cap value
*/
value);
/*
* we need to set first step low register too
* make register setting relative to default
* from INI file & cap value
*/
DBG2("ath9k: "
"** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
DBG2("ath9k: "
"** ch %d: level %d=>%d[def:%d] firstep_low[level]=%d ini=%d\n",
}
break;
}
DBG("ath9k: "
"ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%d > %zd)\n",
return 0;
}
/*
* make register setting relative to default
* from INI file & cap value
*/
value);
/*
* set AR_PHY_EXT_CCA for extension channel
* make register setting relative to default
* from INI file & cap value
*/
DBG2("ath9k: "
"** ch %d: level %d=>%d[def:%d] cycpwrThr1[level]=%d ini=%d\n",
DBG2("ath9k: "
"** ch %d: level %d=>%d[def:%d] cycpwrThr1Ext[level]=%d ini=%d\n",
}
break;
}
case ATH9K_ANI_MRC_CCK:
/*
* You should not see this as AR5008, AR9001, AR9002
* does not have hardware support for MRC CCK.
*/
break;
case ATH9K_ANI_PRESENT:
break;
default:
return 0;
}
DBG2("ath9k: "
"ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
return 1;
}
{
return;
}
/*
* Initialize the ANI register values with default (ini) values.
* This routine is called during a (full) hardware reset after
* all the registers are initialised from the INI.
*/
{
struct ath9k_ani_default *iniDef;
DBG2("ath9k: ver %d.%d chan %d Mhz/0x%x\n",
chan->channelFlags);
/* these levels just got reset to defaults by the INI */
}
{
}
struct ath_hw_radar_conf *conf)
{
if (!conf) {
return;
}
if (conf->ext_channel)
else
}
{
}
{
};
if (modparam_force_new_ani) {
} else
if (AR_SREV_9100(ah))
else if (AR_SREV_9160_10_OR_LATER(ah))
else
}