/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2008 Atheros Communications Inc.
*
* 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 "arn_core.h"
#include "arn_hw.h"
#include "arn_reg.h"
#include "arn_phy.h"
/* We can tune this as we go by monitoring really low values */
/*
* AR5416 may return very high value (like -31 dBm), in those cases the nf
* is incorrect and we should use the static NF value. Later we can try to
* find out why they are reporting these values
*/
/* ARGSUSED */
static boolean_t
{
if (nf > ATH9K_NF_TOO_LOW) {
"%s: noise floor value detected (%d) is "
"lower than what we think is a "
"reasonable value (%d)\n",
return (B_FALSE);
}
return (B_TRUE);
}
static int16_t
{
int i, j;
for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
sort[i] = nfCalBuffer[i];
for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
}
}
}
return (nfval);
}
static void
{
int i;
for (i = 0; i < NUM_NF_READINGS; i++) {
if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
h[i].currIndex = 0;
if (h[i].invalidNFcount > 0) {
if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
} else {
h[i].invalidNFcount--;
}
} else {
h[i].privNF =
}
}
}
static void
{
if (AR_SREV_9280_10_OR_LATER(ah))
else
if (nf & 0x100)
"NF calibrated [ctl] [chain 0] is %d\n", nf));
if (AR_SREV_9280_10_OR_LATER(ah))
else
if (nf & 0x100)
"NF calibrated [ctl] [chain 1] is %d\n", nf));
if (!AR_SREV_9280(ah)) {
if (nf & 0x100)
"NF calibrated [ctl] [chain 2] is %d\n", nf));
}
if (AR_SREV_9280_10_OR_LATER(ah))
else
if (nf & 0x100)
"NF calibrated [ext] [chain 0] is %d\n", nf));
if (AR_SREV_9280_10_OR_LATER(ah))
else
if (nf & 0x100)
"NF calibrated [ext] [chain 1] is %d\n", nf));
if (!AR_SREV_9280(ah)) {
if (nf & 0x100)
"NF calibrated [ext] [chain 2] is %d\n", nf));
}
}
static boolean_t
const struct ath9k_channel *chan,
{
case CHANNEL_A:
case CHANNEL_A_HT20:
case CHANNEL_A_HT40PLUS:
case CHANNEL_A_HT40MINUS:
break;
case CHANNEL_B:
case CHANNEL_G:
case CHANNEL_G_HT20:
case CHANNEL_G_HT40PLUS:
case CHANNEL_G_HT40MINUS:
break;
default:
"%s: invalid channel flags 0x%x\n", __func__,
chan->channelFlags));
return (B_FALSE);
}
return (B_TRUE);
}
static void
struct hal_cal_list *currCal)
{
case IQ_MISMATCH_CAL:
"%s: starting IQ Mismatch Calibration\n",
__func__));
break;
case ADC_GAIN_CAL:
"%s: starting ADC Gain Calibration\n", __func__));
break;
case ADC_DC_CAL:
"%s: starting ADC DC Calibration\n", __func__));
break;
case ADC_DC_INIT_CAL:
"%s: starting Init ADC DC Calibration\n",
__func__));
break;
}
}
static void
struct hal_cal_list *currCal)
{
int i;
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
}
ahp->ah_CalSamples = 0;
}
static void
struct ath9k_channel *ichan,
struct hal_cal_list *currCal,
{
ahp->ah_CalSamples++;
if (ahp->ah_CalSamples >=
int i, numChains = 0;
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
if (rxchainmask & (1 << i))
numChains++;
}
} else {
}
}
}
}
static boolean_t
struct ath9k_channel *chan,
enum hal_cal_types calType)
{
case IQ_MISMATCH_CAL:
break;
case ADC_GAIN_CAL:
case ADC_DC_CAL:
break;
}
return (retval);
}
static void
{
int i;
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
ahp->ah_totalPowerMeasI[i] +=
ahp->ah_totalPowerMeasQ[i] +=
ahp->ah_totalIqCorrMeas[i] +=
"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
ahp->ah_totalPowerMeasQ[i],
ahp->ah_totalIqCorrMeas[i]));
}
}
static void
{
int i;
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
ahp->ah_totalAdcIOddPhase[i] +=
ahp->ah_totalAdcIEvenPhase[i] +=
ahp->ah_totalAdcQOddPhase[i] +=
ahp->ah_totalAdcQEvenPhase[i] +=
"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
"oddq=0x%08x; evenq=0x%08x;\n",
ahp->ah_CalSamples, i,
ahp->ah_totalAdcIOddPhase[i],
ahp->ah_totalAdcIEvenPhase[i],
ahp->ah_totalAdcQOddPhase[i],
ahp->ah_totalAdcQEvenPhase[i]));
}
}
static void
{
int i;
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
"oddq=0x%08x; evenq=0x%08x;\n",
ahp->ah_CalSamples, i,
ahp->ah_totalAdcDcOffsetQEvenPhase[i]));
}
}
static void
{
int iqCorrNeg, i;
for (i = 0; i < numChains; i++) {
"Starting IQ Cal and Correction for Chain %d\n",
i));
"Orignal: Chn %diq_corr_meas = 0x%08x\n",
i, ahp->ah_totalIqCorrMeas[i]));
iqCorrNeg = 0;
if (iqCorrMeas > 0x80000000) {
iqCorrNeg = 1;
}
"Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI));
"Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ));
iqCorrNeg));
if (powerMeasQ != 0) {
"Chn %d iCoff = 0x%08x\n", i, iCoff));
"Chn %d qCoff = 0x%08x\n", i, qCoff));
"New: Chn %d iCoff = 0x%08x\n", i, iCoff));
if (iqCorrNeg == 0x0)
if (qCoff > 15)
qCoff = 15;
else if (qCoff <= -16)
qCoff = 16;
"Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
iCoff);
qCoff);
"IQ Cal and Correction done for Chain %d\n",
i));
}
}
}
static void
{
for (i = 0; i < numChains; i++) {
"Starting ADC Gain Cal for Chain %d\n", i));
"Chn %d pwr_meas_odd_i = 0x%08x\n", i,
"Chn %d pwr_meas_even_i = 0x%08x\n", i,
"Chn %d pwr_meas_odd_q = 0x%08x\n", i,
"Chn %d pwr_meas_even_q = 0x%08x\n", i,
if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
((iEvenMeasOffset * 32) /
iOddMeasOffset) & 0x3f;
((qOddMeasOffset * 32) /
qEvenMeasOffset) & 0x3f;
"Chn %d gain_mismatch_i = 0x%08x\n", i,
"Chn %d gain_mismatch_q = 0x%08x\n", i,
val &= 0xfffff000;
"ADC Gain Cal done for Chain %d\n", i));
}
}
}
static void
{
for (i = 0; i < numChains; i++) {
"Starting ADC DC Offset Cal for Chain %d\n", i));
"Chn %d pwr_meas_odd_i = %d\n", i,
"Chn %d pwr_meas_even_i = %d\n", i,
"Chn %d pwr_meas_odd_q = %d\n", i,
"Chn %d pwr_meas_even_q = %d\n", i,
numSamples) & 0x1ff;
numSamples) & 0x1ff;
"Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
iDcMismatch));
"Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
qDcMismatch));
val &= 0xc0000fff;
"ADC DC Offset Cal done for Chain %d\n", i));
}
}
void
{
return;
return;
"%s: invalid channel %u/0x%x; no mapping\n",
return;
}
"%s: Calibration state incorrect, %d\n",
return;
}
return;
"%s: Resetting Cal %d state for channel %u/0x%x\n",
chan->channelFlags));
}
void
{
}
/* ARGSUSED */
void
{
struct ath9k_nfcal_hist *h;
int i, j;
};
if (AR_SREV_9280(ah))
chainmask = 0x1B;
else
chainmask = 0x3F;
#ifdef ARN_NF_PER_CHAN
#else
#endif
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val &= 0xFFFFFE00;
}
}
for (j = 0; j < 1000; j++) {
AR_PHY_AGC_CONTROL_NF) == 0)
break;
drv_usecwait(10);
}
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val &= 0xFFFFFE00;
}
}
}
{
struct ath9k_nfcal_hist *h;
"%s: NF did not complete in calibration window\n",
__func__));
nf = 0;
return (chan->rawNoiseFloor);
} else {
"%s: noise floor failed detected; "
"detected %d, threshold %d\n", __func__,
}
}
#ifdef ARN_NF_PER_CHAN
#else
#endif
return (chan->rawNoiseFloor);
}
void
{
int i, j;
if (AR_SREV_9280(ah))
else if (AR_SREV_9285(ah))
else
for (i = 0; i < NUM_NF_READINGS; i++) {
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
}
}
}
signed short
{
signed short nf;
"%s: invalid channel %u/0x%x; no mapping\n",
return (ATH_DEFAULT_NOISE_FLOOR);
}
if (ichan->rawNoiseFloor == 0) {
} else
return (nf);
}
{
"%s: invalid channel %u/0x%x; no mapping\n",
return (B_FALSE);
}
if (currCal &&
if (*isCalDone) {
}
}
}
if (longcal) {
}
}
return (B_TRUE);
}
/* AR9285 */
static inline void
{
{ 0x786c, 0 },
{ 0x7854, 0 },
{ 0x7820, 0 },
{ 0x7824, 0 },
{ 0x7868, 0 },
{ 0x783c, 0 },
{ 0x7838, 0 },
};
if (AR_SREV_9285_11(ah)) {
drv_usecwait(10);
}
for (i = 0; i < ARRAY_SIZE(regList); i++)
regVal &= (~(0x1));
drv_usecwait(30);
for (i = 6; i > 0; i--) {
drv_usecwait(1);
}
drv_usecwait(1);
regVal |= 0x1;
for (i = 0; i < ARRAY_SIZE(regList); i++)
if (AR_SREV_9285_11(ah))
}
struct ath9k_channel *chan)
{
"%s: offset calibration failed to complete in 1ms; "
"noisy environment?\n", __func__));
return (B_FALSE);
}
/* LINTED: E_CONSTANT_CONDITION */
/* LINTED: E_CONSTANT_CONDITION */
"%s: enabling ADC Gain Calibration.\n",
__func__));
}
/* LINTED: E_CONSTANT_CONDITION */
/* LINTED: E_CONSTANT_CONDITION */
"%s: enabling ADC DC Calibration.\n",
__func__));
}
/* LINTED: E_CONSTANT_CONDITION */
/* LINTED: E_CONSTANT_CONDITION */
"%s: enabling IQ Calibration.\n",
__func__));
}
if (ahp->ah_cal_list_curr)
}
return (B_TRUE);
}
};
};
};
};
};
};
};