/* * Copyright (c) 2010-2011 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/** * ar9003_hw_set_channel - set channel on single-chip device * @ah: atheros hardware structure * @chan: * * This is the function to change channel on single-chip devices, that is * for AR9300 family of chipsets. * * This function takes the channel value in MHz and sets * hardware channel value. Assumes writes have been enabled to analog bus. * * Actual Expression, * * For 2GHz channel, * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) * (freq_ref = 40MHz) * * For 5GHz channel, * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10) * (freq_ref = 40MHz/(24>>amodeRefSel)) * * For 5GHz channels which are 5MHz spaced, * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) * (freq_ref = 40MHz)
*/ staticint ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
{
u16 bMode, fracMode = 0, aModeRefSel = 0;
u32 freq, chan_frac, div, channelSel = 0, reg32 = 0; struct chan_centers centers; int loadSynthChannel;
staticvoid ar9003_hw_spur_ofdm(struct ath_hw *ah, int freq_offset, int spur_freq_sd, int spur_delta_phase, int spur_subchannel_sd, int range, int synth_freq)
{ int mask_index = 0;
/* A == B */
REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_B(ah),
AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0);
}
staticvoid ar9003_hw_spur_ofdm_work(struct ath_hw *ah, struct ath9k_channel *chan, int freq_offset, int range, int synth_freq)
{ int spur_freq_sd = 0; int spur_subchannel_sd = 0; int spur_delta_phase = 0;
if (IS_CHAN_HT40(chan)) { if (freq_offset < 0) { if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
spur_subchannel_sd = 1; else
spur_subchannel_sd = 0;
if (!AR_SREV_9561(ah))
phymode |= AR_PHY_GC_SINGLE_HT_LTF1;
/* Configure baseband for dynamic 20/40 operation */ if (IS_CHAN_HT40(chan)) {
phymode |= AR_PHY_GC_DYN2040_EN; /* Configure control (primary) channel at +-10MHz */ if (IS_CHAN_HT40PLUS(chan))
phymode |= AR_PHY_GC_DYN2040_PRI_CH;
}
/* make sure we preserve INI settings */
phymode |= REG_READ(ah, AR_PHY_GEN_CTRL); /* turn off Green Field detection for STA for now */
phymode &= ~AR_PHY_GC_GF_DETECT_EN;
REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode);
/* Configure MAC for 20/40 operation */
ath9k_hw_set11nmac2040(ah, chan);
/* global transmit timeout (25 TUs default)*/
REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); /* carrier sense timeout */
REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
}
/* * Wait for the frequency synth to settle (synth goes on * via AR_PHY_ACTIVE_EN). Read the phy active delay register. * Value is in 100ns increments.
*/
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
/* * Override INI values with chip specific configuration.
*/ staticvoid ar9003_hw_override_ini(struct ath_hw *ah)
{
u32 val;
/* * Set the RX_ABORT and RX_DIS and clear it 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));
/* * For AR9280 and above, there is a new feature that allows * Multicast search based on both MAC Address and Key ID. By default, * this feature is enabled. But since the driver is not using this * feature, we switch it off; otherwise multicast search based on * MAC addr only will fail.
*/
val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);
val |= AR_AGG_WEP_ENABLE_FIX |
AR_AGG_WEP_ENABLE |
AR_PCU_MISC_MODE2_CFP_IGNORE;
REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
staticvoid ar9003_hw_prog_ini(struct ath_hw *ah, struct ar5416IniArray *iniArr, int column)
{ unsignedint i, regWrites = 0;
/* New INI format: Array may be undefined (pre, core, post arrays) */ if (!iniArr->ia_array) return;
/* * New INI format: Pre, core, and post arrays for a given subsystem * may be modal (> 2 columns) or non-modal (2 columns). Determine if * the array is non-modal and force the column to 1.
*/ if (column >= iniArr->ia_columns)
column = 1;
for (i = 0; i < iniArr->ia_rows; i++) {
u32 reg = INI_RA(iniArr, i, 0);
u32 val = INI_RA(iniArr, i, column);
/* * For 5GHz channels requiring Fast Clock, apply * different modal values.
*/ if (IS_CHAN_A_FAST_CLOCK(ah, chan))
REG_WRITE_ARRAY(&ah->iniModesFastClock,
modesIndex, regWrites);
/* * Clock frequency initvals.
*/
REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites);
/* * JAPAN regulatory.
*/ if (chan->channel == 2484) {
ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
if (AR_SREV_9531(ah))
REG_RMW_FIELD(ah, AR_PHY_FCAL_2_0,
AR_PHY_FLC_PWR_THRESH, 0);
}
/* for short gi */
REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA,
AR_PHY_SGI_DSC_MAN, ds_coef_man);
REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA,
AR_PHY_SGI_DSC_EXP, ds_coef_exp);
}
/* * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN). * Read the phy active delay register. Value is in 100ns increments.
*/ staticvoid ar9003_hw_rfbus_done(struct ath_hw *ah)
{
u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
staticbool ar9003_hw_ani_control(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param)
{ struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ar5416AniState *aniState = &ah->ani; int m1ThreshLow, m2ThreshLow; int m1Thresh, m2Thresh; int m2CountThr, m2CountThrLow; int m1ThreshLowExt, m2ThreshLowExt; int m1ThreshExt, m2ThreshExt;
s32 value, value2;
switch (cmd & ah->ani_function) { case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ /* * 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
*/
u32 on = param ? 1 : 0;
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) goto skip_ws_det;
m1ThreshLow = on ?
aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
m2ThreshLow = on ?
aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
m1Thresh = on ?
aniState->iniDef.m1Thresh : m1Thresh_off;
m2Thresh = on ?
aniState->iniDef.m2Thresh : m2Thresh_off;
m2CountThr = on ?
aniState->iniDef.m2CountThr : m2CountThr_off;
m2CountThrLow = on ?
aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
m1ThreshLowExt = on ?
aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
m2ThreshLowExt = on ?
aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
m1ThreshExt = on ?
aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
m2ThreshExt = on ?
aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
if (on != aniState->ofdmWeakSigDetect) {
ath_dbg(common, ANI, "** ch %d: ofdm weak signal: %s=>%s\n",
chan->channel,
aniState->ofdmWeakSigDetect ? "on" : "off",
on ? "on" : "off"); if (on)
ah->stats.ast_ani_ofdmon++; else
ah->stats.ast_ani_ofdmoff++;
aniState->ofdmWeakSigDetect = on;
} break;
} case ATH9K_ANI_FIRSTEP_LEVEL:{
u32 level = param;
if (level >= ARRAY_SIZE(firstep_table)) {
ath_dbg(common, ANI, "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n",
level, ARRAY_SIZE(firstep_table)); returnfalse;
}
/* * make register setting relative to default * from INI file & cap value
*/
value = firstep_table[level] -
firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
aniState->iniDef.firstep; if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
value = ATH9K_SIG_FIRSTEP_SETTING_MIN; if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
AR_PHY_FIND_SIG_FIRSTEP,
value); /* * we need to set first step low register too * make register setting relative to default * from INI file & cap value
*/
value2 = firstep_table[level] -
firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
aniState->iniDef.firstepLow; if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN; if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
ath_dbg(common, ANI, "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n",
level, ARRAY_SIZE(cycpwrThr1_table)); returnfalse;
} /* * make register setting relative to default * from INI file & cap value
*/
value = cycpwrThr1_table[level] -
cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
aniState->iniDef.cycpwrThr1; if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
value = ATH9K_SIG_SPUR_IMM_SETTING_MIN; if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
REG_RMW_FIELD(ah, AR_PHY_TIMING5,
AR_PHY_TIMING5_CYCPWR_THR1,
value);
/* * set AR_PHY_EXT_CCA for extension channel * make register setting relative to default * from INI file & cap value
*/
value2 = cycpwrThr1_table[level] -
cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
aniState->iniDef.cycpwrThr1Ext; if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN; if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
AR_PHY_EXT_CYCPWR_THR1, value2);
if (level != aniState->spurImmunityLevel) {
ath_dbg(common, ANI, "** ch %d: level %d=>%d[def:%d] cycpwrThr1[level]=%d ini=%d\n",
chan->channel,
aniState->spurImmunityLevel,
level,
ATH9K_ANI_SPUR_IMMUNE_LVL,
value,
aniState->iniDef.cycpwrThr1);
ath_dbg(common, ANI, "** ch %d: level %d=>%d[def:%d] cycpwrThr1Ext[level]=%d ini=%d\n",
chan->channel,
aniState->spurImmunityLevel,
level,
ATH9K_ANI_SPUR_IMMUNE_LVL,
value2,
aniState->iniDef.cycpwrThr1Ext); if (level > aniState->spurImmunityLevel)
ah->stats.ast_ani_spurup++; elseif (level < aniState->spurImmunityLevel)
ah->stats.ast_ani_spurdown++;
aniState->spurImmunityLevel = level;
} break;
} case ATH9K_ANI_MRC_CCK:{ /* * is_on == 1 means MRC CCK ON (default, less noise imm) * is_on == 0 means MRC CCK is OFF (more noise imm)
*/ bool is_on = param ? 1 : 0;
/* * 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.
*/ staticvoid ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
{ struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ath9k_ani_default *iniDef;
u32 val;
/* these levels just got reset to defaults by the INI */
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
aniState->ofdmWeakSigDetect = true;
aniState->mrcCCK = true;
}
/* * For 5GHz channels requiring Fast Clock, apply * different modal values.
*/ if (IS_CHAN_A_FAST_CLOCK(ah, chan))
REG_WRITE_ARRAY(&ah->iniModesFastClock, modesIndex, regWrites);
if (AR_SREV_9565(ah))
REG_WRITE_ARRAY(&ah->iniModesFastClock, 1, regWrites);
/* * JAPAN regulatory.
*/ if (chan->channel == 2484)
ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
/* on AR93xx and newer, count = 0 will make the chip send * spectral samples endlessly. Check if this really was intended, * and fix otherwise.
*/
count = param->count; if (param->endless)
count = 0; elseif (param->count == 0)
count = 1;
if (param->short_repeat)
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); else
REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
/* * Baseband Watchdog signatures: * * 0x04000539: BB hang when operating in HT40 DFS Channel. * Full chip reset is not required, but a recovery * mechanism is needed. * * 0x1300000a: Related to CAC deafness. * Chip reset is not required. * * 0x0400000a: Related to CAC deafness. * Full chip reset is required. * * 0x04000b09: RX state machine gets into an illegal state * when a packet with unsupported rate is received. * Full chip reset is required and PHY_RESTART has * to be disabled. * * 0x04000409: Packet stuck on receive. * Full chip reset is required for all chips except * AR9340, AR9531 and AR9561.
*/
/* * ar9003_hw_bb_watchdog_check(): Returns true if a chip reset is required.
*/ bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah)
{
u32 val;
switch(ah->bb_watchdog_last_status) { case 0x04000539:
val = REG_READ(ah, AR_PHY_RADAR_0);
val &= (~AR_PHY_RADAR_0_FIRPWR);
val |= SM(0x7f, AR_PHY_RADAR_0_FIRPWR);
REG_WRITE(ah, AR_PHY_RADAR_0, val);
udelay(1);
val = REG_READ(ah, AR_PHY_RADAR_0);
val &= ~AR_PHY_RADAR_0_FIRPWR;
val |= SM(AR9300_DFS_FIRPWR, AR_PHY_RADAR_0_FIRPWR);
REG_WRITE(ah, AR_PHY_RADAR_0, val);
returnfalse; case 0x1300000a: returnfalse; case 0x0400000a: case 0x04000b09: returntrue; case 0x04000409: if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) returnfalse; else returntrue; default: /* * For any other unknown signatures, do a * full chip reset.
*/ returntrue;
}
}
EXPORT_SYMBOL(ar9003_hw_bb_watchdog_check);
/* bound limit to 10 secs */ if (idle_tmo_ms > 10000)
idle_tmo_ms = 10000;
/* * The time unit for watchdog event is 2^15 44/88MHz cycles. * * For HT20 we have a time unit of 2^15/44 MHz = .74 ms per tick * For HT40 we have a time unit of 2^15/88 MHz = .37 ms per tick * * Given we use fast clock now in 5 GHz, these time units should * be common for both 2 GHz and 5 GHz.
*/
idle_count = (100 * idle_tmo_ms) / 74; if (ah->curchan && IS_CHAN_HT40(ah->curchan))
idle_count = (100 * idle_tmo_ms) / 37;
/* * enable watchdog in non-IDLE mode, disable in IDLE mode, * set idle time-out.
*/
REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
AR_PHY_WATCHDOG_IDLE_MASK |
(AR_PHY_WATCHDOG_NON_IDLE_MASK & (idle_count << 2)));
void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
{ /* * we want to avoid printing in ISR context so we save the * watchdog status to be printed later in bottom half context.
*/
ah->bb_watchdog_last_status = REG_READ(ah, AR_PHY_WATCHDOG_STATUS);
/* * the watchdog timer should reset on status read but to be sure * sure we write 0 to the watchdog status bit.
*/
REG_WRITE(ah, AR_PHY_WATCHDOG_STATUS,
ah->bb_watchdog_last_status & ~AR_PHY_WATCHDOG_STATUS_CLR);
}
/* While receiving unsupported rate frame rx state machine * gets into a state 0xb and if phy_restart happens in that * state, BB would go hang. If RXSM is in 0xb state after * first bb panic, ensure to disable the phy_restart.
*/
result = MS(ah->bb_watchdog_last_status, AR_PHY_WATCHDOG_RX_OFDM_SM);
if ((result == 0xb) || ah->bb_hang_rx_ofdm) {
ah->bb_hang_rx_ofdm = true;
val = REG_READ(ah, AR_PHY_RESTART);
val &= ~AR_PHY_RESTART_ENA;
REG_WRITE(ah, AR_PHY_RESTART, val);
}
}
EXPORT_SYMBOL(ar9003_hw_disable_phy_restart);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.