Path: blob/main/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"22#include "ah_devid.h"2324#include "ar5212/ar5212.h"25#include "ar5212/ar5212reg.h"26#include "ar5212/ar5212phy.h"2728#include "ah_eeprom_v3.h"2930static const GAIN_OPTIMIZATION_LADDER gainLadder = {319, /* numStepsInLadder */324, /* defaultStepNum */33{ { {4, 1, 1, 1}, 6, "FG8"},34{ {4, 0, 1, 1}, 4, "FG7"},35{ {3, 1, 1, 1}, 3, "FG6"},36{ {4, 0, 0, 1}, 1, "FG5"},37{ {4, 1, 1, 0}, 0, "FG4"}, /* noJack */38{ {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */39{ {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */40{ {4, 0, 0, 0}, -4, "FG1"}, /* noJack */41{ {2, 1, 1, 0}, -6, "FG0"} /* clip2 */42}43};4445static const GAIN_OPTIMIZATION_LADDER gainLadder5112 = {468, /* numStepsInLadder */471, /* defaultStepNum */48{ { {3, 0,0,0, 0,0,0}, 6, "FG7"}, /* most fixed gain */49{ {2, 0,0,0, 0,0,0}, 0, "FG6"},50{ {1, 0,0,0, 0,0,0}, -3, "FG5"},51{ {0, 0,0,0, 0,0,0}, -6, "FG4"},52{ {0, 1,1,0, 0,0,0}, -8, "FG3"},53{ {0, 1,1,0, 1,1,0}, -10, "FG2"},54{ {0, 1,0,1, 1,1,0}, -13, "FG1"},55{ {0, 1,0,1, 1,0,1}, -16, "FG0"}, /* least fixed gain */56}57};5859/*60* Initialize the gain structure to good values61*/62void63ar5212InitializeGainValues(struct ath_hal *ah)64{65struct ath_hal_5212 *ahp = AH5212(ah);66GAIN_VALUES *gv = &ahp->ah_gainValues;6768/* initialize gain optimization values */69if (IS_RAD5112_ANY(ah)) {70gv->currStepNum = gainLadder5112.defaultStepNum;71gv->currStep =72&gainLadder5112.optStep[gainLadder5112.defaultStepNum];73gv->active = AH_TRUE;74gv->loTrig = 20;75gv->hiTrig = 85;76} else {77gv->currStepNum = gainLadder.defaultStepNum;78gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum];79gv->active = AH_TRUE;80gv->loTrig = 20;81gv->hiTrig = 35;82}83}8485#define MAX_ANALOG_START 319 /* XXX */8687/*88* Find analog bits of given parameter data and return a reversed value89*/90static uint32_t91ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits, uint32_t firstBit, uint32_t column)92{93uint32_t reg32 = 0, mask, arrayEntry, lastBit;94uint32_t bitPosition, bitsShifted;95int32_t bitsLeft;9697HALASSERT(column <= 3);98HALASSERT(numBits <= 32);99HALASSERT(firstBit + numBits <= MAX_ANALOG_START);100101arrayEntry = (firstBit - 1) / 8;102bitPosition = (firstBit - 1) % 8;103bitsLeft = numBits;104bitsShifted = 0;105while (bitsLeft > 0) {106lastBit = (bitPosition + bitsLeft > 8) ?107(8) : (bitPosition + bitsLeft);108mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<109(column * 8);110reg32 |= (((rfBuf[arrayEntry] & mask) >> (column * 8)) >>111bitPosition) << bitsShifted;112bitsShifted += lastBit - bitPosition;113bitsLeft -= (8 - bitPosition);114bitPosition = 0;115arrayEntry++;116}117reg32 = ath_hal_reverseBits(reg32, numBits);118return reg32;119}120121static HAL_BOOL122ar5212InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)123{124uint32_t gStep, g, mixOvr;125uint32_t L1, L2, L3, L4;126127if (IS_RAD5112_ANY(ah)) {128mixOvr = ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0);129L1 = 0;130L2 = 107;131L3 = 0;132L4 = 107;133if (mixOvr == 1) {134L2 = 83;135L4 = 83;136gv->hiTrig = 55;137}138} else {139gStep = ar5212GetRfField(ar5212GetRfBank(ah, 7), 6, 37, 0);140141L1 = 0;142L2 = (gStep == 0x3f) ? 50 : gStep + 4;143L3 = (gStep != 0x3f) ? 0x40 : L1;144L4 = L3 + 50;145146gv->loTrig = L1 + (gStep == 0x3f ? DYN_ADJ_LO_MARGIN : 0);147/* never adjust if != 0x3f */148gv->hiTrig = L4 - (gStep == 0x3f ? DYN_ADJ_UP_MARGIN : -5);149}150g = gv->currGain;151152return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4));153}154155/*156* Enable the probe gain check on the next packet157*/158void159ar5212RequestRfgain(struct ath_hal *ah)160{161struct ath_hal_5212 *ahp = AH5212(ah);162uint32_t probePowerIndex;163164/* Enable the gain readback probe */165probePowerIndex = ahp->ah_ofdmTxPower + ahp->ah_txPowerIndexOffset;166OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE,167SM(probePowerIndex, AR_PHY_PAPD_PROBE_POWERTX)168| AR_PHY_PAPD_PROBE_NEXT_TX);169170ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED;171}172173/*174* Check to see if our readback gain level sits within the linear175* region of our current variable attenuation window176*/177static HAL_BOOL178ar5212IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv)179{180return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);181}182183/*184* Move the rabbit ears in the correct direction.185*/186static int32_t187ar5212AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv)188{189const GAIN_OPTIMIZATION_LADDER *gl;190191if (IS_RAD5112_ANY(ah))192gl = &gainLadder5112;193else194gl = &gainLadder;195gv->currStep = &gl->optStep[gv->currStepNum];196if (gv->currGain >= gv->hiTrig) {197if (gv->currStepNum == 0) {198HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Max gain limit.\n",199__func__);200return -1;201}202HALDEBUG(ah, HAL_DEBUG_RFPARAM,203"%s: Adding gain: currG=%d [%s] --> ",204__func__, gv->currGain, gv->currStep->stepName);205gv->targetGain = gv->currGain;206while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) {207gv->targetGain -= 2 * (gl->optStep[--(gv->currStepNum)].stepGain -208gv->currStep->stepGain);209gv->currStep = &gl->optStep[gv->currStepNum];210}211HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",212gv->targetGain, gv->currStep->stepName);213return 1;214}215if (gv->currGain <= gv->loTrig) {216if (gv->currStepNum == gl->numStepsInLadder-1) {217HALDEBUG(ah, HAL_DEBUG_RFPARAM,218"%s: Min gain limit.\n", __func__);219return -2;220}221HALDEBUG(ah, HAL_DEBUG_RFPARAM,222"%s: Deducting gain: currG=%d [%s] --> ",223__func__, gv->currGain, gv->currStep->stepName);224gv->targetGain = gv->currGain;225while (gv->targetGain <= gv->loTrig &&226gv->currStepNum < (gl->numStepsInLadder - 1)) {227gv->targetGain -= 2 *228(gl->optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain);229gv->currStep = &gl->optStep[gv->currStepNum];230}231HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",232gv->targetGain, gv->currStep->stepName);233return 2;234}235return 0; /* caller didn't call needAdjGain first */236}237238/*239* Read rf register to determine if gainF needs correction240*/241static uint32_t242ar5212GetGainFCorrection(struct ath_hal *ah)243{244struct ath_hal_5212 *ahp = AH5212(ah);245uint32_t correction;246247HALASSERT(IS_RADX112_REV2(ah));248249correction = 0;250if (ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0) == 1) {251const GAIN_VALUES *gv = &ahp->ah_gainValues;252uint32_t mixGain = gv->currStep->paramVal[0];253uint32_t gainStep =254ar5212GetRfField(ar5212GetRfBank(ah, 7), 4, 32, 0);255switch (mixGain) {256case 0 :257correction = 0;258break;259case 1 :260correction = gainStep;261break;262case 2 :263correction = 2 * gainStep - 5;264break;265case 3 :266correction = 2 * gainStep;267break;268}269}270return correction;271}272273/*274* Exported call to check for a recent gain reading and return275* the current state of the thermal calibration gain engine.276*/277HAL_RFGAIN278ar5212GetRfgain(struct ath_hal *ah)279{280struct ath_hal_5212 *ahp = AH5212(ah);281GAIN_VALUES *gv = &ahp->ah_gainValues;282uint32_t rddata, probeType;283284/* NB: beware of touching the BB when PHY is powered down */285if (!gv->active || !ahp->ah_phyPowerOn)286return HAL_RFGAIN_INACTIVE;287288if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) {289/* Caller had asked to setup a new reading. Check it. */290rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE);291292if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) {293/* bit got cleared, we have a new reading. */294gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S;295probeType = MS(rddata, AR_PHY_PAPD_PROBE_TYPE);296if (probeType == AR_PHY_PAPD_PROBE_TYPE_CCK) {297const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;298299HALASSERT(IS_RAD5112_ANY(ah));300HALASSERT(ah->ah_magic == AR5212_MAGIC);301if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2)302gv->currGain += ee->ee_cckOfdmGainDelta;303else304gv->currGain += PHY_PROBE_CCK_CORRECTION;305}306if (IS_RADX112_REV2(ah)) {307uint32_t correct = ar5212GetGainFCorrection(ah);308if (gv->currGain >= correct)309gv->currGain -= correct;310else311gv->currGain = 0;312}313/* inactive by default */314ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;315316if (!ar5212InvalidGainReadback(ah, gv) &&317ar5212IsGainAdjustNeeded(ah, gv) &&318ar5212AdjustGain(ah, gv) > 0) {319/*320* Change needed. Copy ladder info321* into eeprom info.322*/323ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE;324/* for ap51 */325ahp->ah_cwCalRequire = AH_TRUE;326/* Request IQ recalibration for temperature change */327ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;328}329}330}331return ahp->ah_rfgainState;332}333334335