Home | History | Annotate | Line # | Download | only in ar5212
      1  1.1  alc /*
      2  1.1  alc  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
      3  1.1  alc  * Copyright (c) 2002-2008 Atheros Communications, Inc.
      4  1.1  alc  *
      5  1.1  alc  * Permission to use, copy, modify, and/or distribute this software for any
      6  1.1  alc  * purpose with or without fee is hereby granted, provided that the above
      7  1.1  alc  * copyright notice and this permission notice appear in all copies.
      8  1.1  alc  *
      9  1.1  alc  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  1.1  alc  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  1.1  alc  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  1.1  alc  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  1.1  alc  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  1.1  alc  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  1.1  alc  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  1.1  alc  *
     17  1.1  alc  * $Id: ar5212_rfgain.c,v 1.1.1.1 2008/12/11 04:46:43 alc Exp $
     18  1.1  alc  */
     19  1.1  alc #include "opt_ah.h"
     20  1.1  alc 
     21  1.1  alc #include "ah.h"
     22  1.1  alc #include "ah_internal.h"
     23  1.1  alc #include "ah_devid.h"
     24  1.1  alc 
     25  1.1  alc #include "ar5212/ar5212.h"
     26  1.1  alc #include "ar5212/ar5212reg.h"
     27  1.1  alc #include "ar5212/ar5212phy.h"
     28  1.1  alc 
     29  1.1  alc #include "ah_eeprom_v3.h"
     30  1.1  alc 
     31  1.1  alc static const GAIN_OPTIMIZATION_LADDER gainLadder = {
     32  1.1  alc 	9,					/* numStepsInLadder */
     33  1.1  alc 	4,					/* defaultStepNum */
     34  1.1  alc 	{ { {4, 1, 1, 1},  6, "FG8"},
     35  1.1  alc 	  { {4, 0, 1, 1},  4, "FG7"},
     36  1.1  alc 	  { {3, 1, 1, 1},  3, "FG6"},
     37  1.1  alc 	  { {4, 0, 0, 1},  1, "FG5"},
     38  1.1  alc 	  { {4, 1, 1, 0},  0, "FG4"},	/* noJack */
     39  1.1  alc 	  { {4, 0, 1, 0}, -2, "FG3"},	/* halfJack */
     40  1.1  alc 	  { {3, 1, 1, 0}, -3, "FG2"},	/* clip3 */
     41  1.1  alc 	  { {4, 0, 0, 0}, -4, "FG1"},	/* noJack */
     42  1.1  alc 	  { {2, 1, 1, 0}, -6, "FG0"} 	/* clip2 */
     43  1.1  alc 	}
     44  1.1  alc };
     45  1.1  alc 
     46  1.1  alc static const GAIN_OPTIMIZATION_LADDER gainLadder5112 = {
     47  1.1  alc 	8,					/* numStepsInLadder */
     48  1.1  alc 	1,					/* defaultStepNum */
     49  1.1  alc 	{ { {3, 0,0,0, 0,0,0},   6, "FG7"},	/* most fixed gain */
     50  1.1  alc 	  { {2, 0,0,0, 0,0,0},   0, "FG6"},
     51  1.1  alc 	  { {1, 0,0,0, 0,0,0},  -3, "FG5"},
     52  1.1  alc 	  { {0, 0,0,0, 0,0,0},  -6, "FG4"},
     53  1.1  alc 	  { {0, 1,1,0, 0,0,0},  -8, "FG3"},
     54  1.1  alc 	  { {0, 1,1,0, 1,1,0}, -10, "FG2"},
     55  1.1  alc 	  { {0, 1,0,1, 1,1,0}, -13, "FG1"},
     56  1.1  alc 	  { {0, 1,0,1, 1,0,1}, -16, "FG0"},	/* least fixed gain */
     57  1.1  alc 	}
     58  1.1  alc };
     59  1.1  alc 
     60  1.1  alc /*
     61  1.1  alc  * Initialize the gain structure to good values
     62  1.1  alc  */
     63  1.1  alc void
     64  1.1  alc ar5212InitializeGainValues(struct ath_hal *ah)
     65  1.1  alc {
     66  1.1  alc 	struct ath_hal_5212 *ahp = AH5212(ah);
     67  1.1  alc 	GAIN_VALUES *gv = &ahp->ah_gainValues;
     68  1.1  alc 
     69  1.1  alc 	/* initialize gain optimization values */
     70  1.1  alc 	if (IS_RAD5112_ANY(ah)) {
     71  1.1  alc 		gv->currStepNum = gainLadder5112.defaultStepNum;
     72  1.1  alc 		gv->currStep =
     73  1.1  alc 			&gainLadder5112.optStep[gainLadder5112.defaultStepNum];
     74  1.1  alc 		gv->active = AH_TRUE;
     75  1.1  alc 		gv->loTrig = 20;
     76  1.1  alc 		gv->hiTrig = 85;
     77  1.1  alc 	} else {
     78  1.1  alc 		gv->currStepNum = gainLadder.defaultStepNum;
     79  1.1  alc 		gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum];
     80  1.1  alc 		gv->active = AH_TRUE;
     81  1.1  alc 		gv->loTrig = 20;
     82  1.1  alc 		gv->hiTrig = 35;
     83  1.1  alc 	}
     84  1.1  alc }
     85  1.1  alc 
     86  1.1  alc #define	MAX_ANALOG_START	319		/* XXX */
     87  1.1  alc 
     88  1.1  alc /*
     89  1.1  alc  * Find analog bits of given parameter data and return a reversed value
     90  1.1  alc  */
     91  1.1  alc static uint32_t
     92  1.1  alc ar5212GetRfField(uint32_t *rfBuf, uint32_t numBits, uint32_t firstBit, uint32_t column)
     93  1.1  alc {
     94  1.1  alc 	uint32_t reg32 = 0, mask, arrayEntry, lastBit;
     95  1.1  alc 	uint32_t bitPosition, bitsShifted;
     96  1.1  alc 	int32_t bitsLeft;
     97  1.1  alc 
     98  1.1  alc 	HALASSERT(column <= 3);
     99  1.1  alc 	HALASSERT(numBits <= 32);
    100  1.1  alc 	HALASSERT(firstBit + numBits <= MAX_ANALOG_START);
    101  1.1  alc 
    102  1.1  alc 	arrayEntry = (firstBit - 1) / 8;
    103  1.1  alc 	bitPosition = (firstBit - 1) % 8;
    104  1.1  alc 	bitsLeft = numBits;
    105  1.1  alc 	bitsShifted = 0;
    106  1.1  alc 	while (bitsLeft > 0) {
    107  1.1  alc 		lastBit = (bitPosition + bitsLeft > 8) ?
    108  1.1  alc 			(8) : (bitPosition + bitsLeft);
    109  1.1  alc 		mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
    110  1.1  alc 			(column * 8);
    111  1.1  alc 		reg32 |= (((rfBuf[arrayEntry] & mask) >> (column * 8)) >>
    112  1.1  alc 			bitPosition) << bitsShifted;
    113  1.1  alc 		bitsShifted += lastBit - bitPosition;
    114  1.1  alc 		bitsLeft -= (8 - bitPosition);
    115  1.1  alc 		bitPosition = 0;
    116  1.1  alc 		arrayEntry++;
    117  1.1  alc 	}
    118  1.1  alc 	reg32 = ath_hal_reverseBits(reg32, numBits);
    119  1.1  alc 	return reg32;
    120  1.1  alc }
    121  1.1  alc 
    122  1.1  alc static HAL_BOOL
    123  1.1  alc ar5212InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)
    124  1.1  alc {
    125  1.1  alc 	uint32_t gStep, g, mixOvr;
    126  1.1  alc 	uint32_t L1, L2, L3, L4;
    127  1.1  alc 
    128  1.1  alc 	if (IS_RAD5112_ANY(ah)) {
    129  1.1  alc 		mixOvr = ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0);
    130  1.1  alc 		L1 = 0;
    131  1.1  alc 		L2 = 107;
    132  1.1  alc 		L3 = 0;
    133  1.1  alc 		L4 = 107;
    134  1.1  alc 		if (mixOvr == 1) {
    135  1.1  alc 			L2 = 83;
    136  1.1  alc 			L4 = 83;
    137  1.1  alc 			gv->hiTrig = 55;
    138  1.1  alc 		}
    139  1.1  alc 	} else {
    140  1.1  alc 		gStep = ar5212GetRfField(ar5212GetRfBank(ah, 7), 6, 37, 0);
    141  1.1  alc 
    142  1.1  alc 		L1 = 0;
    143  1.1  alc 		L2 = (gStep == 0x3f) ? 50 : gStep + 4;
    144  1.1  alc 		L3 = (gStep != 0x3f) ? 0x40 : L1;
    145  1.1  alc 		L4 = L3 + 50;
    146  1.1  alc 
    147  1.1  alc 		gv->loTrig = L1 + (gStep == 0x3f ? DYN_ADJ_LO_MARGIN : 0);
    148  1.1  alc 		/* never adjust if != 0x3f */
    149  1.1  alc 		gv->hiTrig = L4 - (gStep == 0x3f ? DYN_ADJ_UP_MARGIN : -5);
    150  1.1  alc 	}
    151  1.1  alc 	g = gv->currGain;
    152  1.1  alc 
    153  1.1  alc 	return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4));
    154  1.1  alc }
    155  1.1  alc 
    156  1.1  alc /*
    157  1.1  alc  * Enable the probe gain check on the next packet
    158  1.1  alc  */
    159  1.1  alc void
    160  1.1  alc ar5212RequestRfgain(struct ath_hal *ah)
    161  1.1  alc {
    162  1.1  alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    163  1.1  alc 	uint32_t probePowerIndex;
    164  1.1  alc 
    165  1.1  alc 	/* Enable the gain readback probe */
    166  1.1  alc 	probePowerIndex = ahp->ah_ofdmTxPower + ahp->ah_txPowerIndexOffset;
    167  1.1  alc 	OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE,
    168  1.1  alc 		  SM(probePowerIndex, AR_PHY_PAPD_PROBE_POWERTX)
    169  1.1  alc 		| AR_PHY_PAPD_PROBE_NEXT_TX);
    170  1.1  alc 
    171  1.1  alc 	ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED;
    172  1.1  alc }
    173  1.1  alc 
    174  1.1  alc /*
    175  1.1  alc  * Check to see if our readback gain level sits within the linear
    176  1.1  alc  * region of our current variable attenuation window
    177  1.1  alc  */
    178  1.1  alc static HAL_BOOL
    179  1.1  alc ar5212IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv)
    180  1.1  alc {
    181  1.1  alc 	return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);
    182  1.1  alc }
    183  1.1  alc 
    184  1.1  alc /*
    185  1.1  alc  * Move the rabbit ears in the correct direction.
    186  1.1  alc  */
    187  1.1  alc static int32_t
    188  1.1  alc ar5212AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv)
    189  1.1  alc {
    190  1.1  alc 	const GAIN_OPTIMIZATION_LADDER *gl;
    191  1.1  alc 
    192  1.1  alc 	if (IS_RAD5112_ANY(ah))
    193  1.1  alc 		gl = &gainLadder5112;
    194  1.1  alc 	else
    195  1.1  alc 		gl = &gainLadder;
    196  1.1  alc 	gv->currStep = &gl->optStep[gv->currStepNum];
    197  1.1  alc 	if (gv->currGain >= gv->hiTrig) {
    198  1.1  alc 		if (gv->currStepNum == 0) {
    199  1.1  alc 			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Max gain limit.\n",
    200  1.1  alc 			    __func__);
    201  1.1  alc 			return -1;
    202  1.1  alc 		}
    203  1.1  alc 		HALDEBUG(ah, HAL_DEBUG_RFPARAM,
    204  1.1  alc 		    "%s: Adding gain: currG=%d [%s] --> ",
    205  1.1  alc 		    __func__, gv->currGain, gv->currStep->stepName);
    206  1.1  alc 		gv->targetGain = gv->currGain;
    207  1.1  alc 		while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) {
    208  1.1  alc 			gv->targetGain -= 2 * (gl->optStep[--(gv->currStepNum)].stepGain -
    209  1.1  alc 				gv->currStep->stepGain);
    210  1.1  alc 			gv->currStep = &gl->optStep[gv->currStepNum];
    211  1.1  alc 		}
    212  1.1  alc 		HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
    213  1.1  alc 		    gv->targetGain, gv->currStep->stepName);
    214  1.1  alc 		return 1;
    215  1.1  alc 	}
    216  1.1  alc 	if (gv->currGain <= gv->loTrig) {
    217  1.1  alc 		if (gv->currStepNum == gl->numStepsInLadder-1) {
    218  1.1  alc 			HALDEBUG(ah, HAL_DEBUG_RFPARAM,
    219  1.1  alc 			    "%s: Min gain limit.\n", __func__);
    220  1.1  alc 			return -2;
    221  1.1  alc 		}
    222  1.1  alc 		HALDEBUG(ah, HAL_DEBUG_RFPARAM,
    223  1.1  alc 		    "%s: Deducting gain: currG=%d [%s] --> ",
    224  1.1  alc 		    __func__, gv->currGain, gv->currStep->stepName);
    225  1.1  alc 		gv->targetGain = gv->currGain;
    226  1.1  alc 		while (gv->targetGain <= gv->loTrig &&
    227  1.1  alc 		      gv->currStepNum < (gl->numStepsInLadder - 1)) {
    228  1.1  alc 			gv->targetGain -= 2 *
    229  1.1  alc 				(gl->optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain);
    230  1.1  alc 			gv->currStep = &gl->optStep[gv->currStepNum];
    231  1.1  alc 		}
    232  1.1  alc 		HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",
    233  1.1  alc 		    gv->targetGain, gv->currStep->stepName);
    234  1.1  alc 		return 2;
    235  1.1  alc 	}
    236  1.1  alc 	return 0;		/* caller didn't call needAdjGain first */
    237  1.1  alc }
    238  1.1  alc 
    239  1.1  alc /*
    240  1.1  alc  * Read rf register to determine if gainF needs correction
    241  1.1  alc  */
    242  1.1  alc static void
    243  1.1  alc ar5212GetGainFCorrection(struct ath_hal *ah)
    244  1.1  alc {
    245  1.1  alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    246  1.1  alc 	GAIN_VALUES *gv = &ahp->ah_gainValues;
    247  1.1  alc 
    248  1.1  alc 	HALASSERT(IS_RADX112_REV2(ah));
    249  1.1  alc 
    250  1.1  alc 	gv->gainFCorrection = 0;
    251  1.1  alc 	if (ar5212GetRfField(ar5212GetRfBank(ah, 7), 1, 36, 0) == 1) {
    252  1.1  alc 		uint32_t mixGain = gv->currStep->paramVal[0];
    253  1.1  alc 		uint32_t gainStep =
    254  1.1  alc 			ar5212GetRfField(ar5212GetRfBank(ah, 7), 4, 32, 0);
    255  1.1  alc 		switch (mixGain) {
    256  1.1  alc 		case 0 :
    257  1.1  alc 			gv->gainFCorrection = 0;
    258  1.1  alc 			break;
    259  1.1  alc 		case 1 :
    260  1.1  alc 			gv->gainFCorrection = gainStep;
    261  1.1  alc 			break;
    262  1.1  alc 		case 2 :
    263  1.1  alc 			gv->gainFCorrection = 2 * gainStep - 5;
    264  1.1  alc 			break;
    265  1.1  alc 		case 3 :
    266  1.1  alc 			gv->gainFCorrection = 2 * gainStep;
    267  1.1  alc 			break;
    268  1.1  alc 		}
    269  1.1  alc 	}
    270  1.1  alc }
    271  1.1  alc 
    272  1.1  alc /*
    273  1.1  alc  * Exported call to check for a recent gain reading and return
    274  1.1  alc  * the current state of the thermal calibration gain engine.
    275  1.1  alc  */
    276  1.1  alc HAL_RFGAIN
    277  1.1  alc ar5212GetRfgain(struct ath_hal *ah)
    278  1.1  alc {
    279  1.1  alc 	struct ath_hal_5212 *ahp = AH5212(ah);
    280  1.1  alc 	GAIN_VALUES *gv = &ahp->ah_gainValues;
    281  1.1  alc 	uint32_t rddata, probeType;
    282  1.1  alc 
    283  1.1  alc 	if (!gv->active)
    284  1.1  alc 		return HAL_RFGAIN_INACTIVE;
    285  1.1  alc 
    286  1.1  alc 	if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) {
    287  1.1  alc 		/* Caller had asked to setup a new reading. Check it. */
    288  1.1  alc 		rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE);
    289  1.1  alc 
    290  1.1  alc 		if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) {
    291  1.1  alc 			/* bit got cleared, we have a new reading. */
    292  1.1  alc 			gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S;
    293  1.1  alc 			probeType = MS(rddata, AR_PHY_PAPD_PROBE_TYPE);
    294  1.1  alc 			if (probeType == AR_PHY_PAPD_PROBE_TYPE_CCK) {
    295  1.1  alc 				const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
    296  1.1  alc 
    297  1.1  alc 				HALASSERT(IS_RAD5112_ANY(ah));
    298  1.1  alc 				HALASSERT(ah->ah_magic == AR5212_MAGIC);
    299  1.1  alc 				if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2)
    300  1.1  alc 					gv->currGain += ee->ee_cckOfdmGainDelta;
    301  1.1  alc 				else
    302  1.1  alc 					gv->currGain += PHY_PROBE_CCK_CORRECTION;
    303  1.1  alc 			}
    304  1.1  alc 			if (IS_RADX112_REV2(ah)) {
    305  1.1  alc 				ar5212GetGainFCorrection(ah);
    306  1.1  alc 				if (gv->currGain >= gv->gainFCorrection)
    307  1.1  alc 					gv->currGain -= gv->gainFCorrection;
    308  1.1  alc 				else
    309  1.1  alc 					gv->currGain = 0;
    310  1.1  alc 			}
    311  1.1  alc 			/* inactive by default */
    312  1.1  alc 			ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
    313  1.1  alc 
    314  1.1  alc 			if (!ar5212InvalidGainReadback(ah, gv) &&
    315  1.1  alc 			    ar5212IsGainAdjustNeeded(ah, gv) &&
    316  1.1  alc 			    ar5212AdjustGain(ah, gv) > 0) {
    317  1.1  alc 				/*
    318  1.1  alc 				 * Change needed. Copy ladder info
    319  1.1  alc 				 * into eeprom info.
    320  1.1  alc 				 */
    321  1.1  alc 				ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE;
    322  1.1  alc 				/* for ap51 */
    323  1.1  alc 				ahp->ah_cwCalRequire = AH_TRUE;
    324  1.1  alc 				/* Request IQ recalibration for temperature chang */
    325  1.1  alc 				ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;
    326  1.1  alc 			}
    327  1.1  alc 		}
    328  1.1  alc 	}
    329  1.1  alc 	return ahp->ah_rfgainState;
    330  1.1  alc }
    331