Home | History | Annotate | Line # | Download | only in ar5212
      1 /*
      2  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
      3  * Copyright (c) 2002-2008 Atheros Communications, Inc.
      4  *
      5  * Permission to use, copy, modify, and/or distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  *
     17  * $Id: ar5112.c,v 1.1.1.1 2008/12/11 04:46:37 alc Exp $
     18  */
     19 #include "opt_ah.h"
     20 
     21 #include "ah.h"
     22 #include "ah_internal.h"
     23 
     24 #include "ah_eeprom_v3.h"
     25 
     26 #include "ar5212/ar5212.h"
     27 #include "ar5212/ar5212reg.h"
     28 #include "ar5212/ar5212phy.h"
     29 
     30 #define AH_5212_5112
     31 #include "ar5212/ar5212.ini"
     32 
     33 #define	N(a)	(sizeof(a)/sizeof(a[0]))
     34 
     35 struct ar5112State {
     36 	RF_HAL_FUNCS	base;		/* public state, must be first */
     37 	uint16_t	pcdacTable[PWR_TABLE_SIZE];
     38 
     39 	uint32_t	Bank1Data[N(ar5212Bank1_5112)];
     40 	uint32_t	Bank2Data[N(ar5212Bank2_5112)];
     41 	uint32_t	Bank3Data[N(ar5212Bank3_5112)];
     42 	uint32_t	Bank6Data[N(ar5212Bank6_5112)];
     43 	uint32_t	Bank7Data[N(ar5212Bank7_5112)];
     44 };
     45 #define	AR5112(ah)	((struct ar5112State *) AH5212(ah)->ah_rfHal)
     46 
     47 static	void ar5212GetLowerUpperIndex(uint16_t v,
     48 		uint16_t *lp, uint16_t listSize,
     49 		uint32_t *vlo, uint32_t *vhi);
     50 static HAL_BOOL getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs,
     51 		int16_t *power, int16_t maxPower, int16_t *retVals);
     52 static int16_t getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4,
     53 		uint16_t retVals[]);
     54 static int16_t getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4,
     55 		int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid);
     56 static int16_t interpolate_signed(uint16_t target,
     57 		uint16_t srcLeft, uint16_t srcRight,
     58 		int16_t targetLeft, int16_t targetRight);
     59 
     60 extern	void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
     61 		uint32_t numBits, uint32_t firstBit, uint32_t column);
     62 
     63 static void
     64 ar5112WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
     65 	int writes)
     66 {
     67 	HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5112, modesIndex, writes);
     68 	HAL_INI_WRITE_ARRAY(ah, ar5212Common_5112, 1, writes);
     69 	HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5112, freqIndex, writes);
     70 }
     71 
     72 /*
     73  * Take the MHz channel value and set the Channel value
     74  *
     75  * ASSUMES: Writes enabled to analog bus
     76  */
     77 static HAL_BOOL
     78 ar5112SetChannel(struct ath_hal *ah,  HAL_CHANNEL_INTERNAL *chan)
     79 {
     80 	uint32_t channelSel  = 0;
     81 	uint32_t bModeSynth  = 0;
     82 	uint32_t aModeRefSel = 0;
     83 	uint32_t reg32       = 0;
     84 	uint16_t freq;
     85 
     86 	OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel);
     87 
     88 	if (chan->channel < 4800) {
     89 		uint32_t txctl;
     90 
     91 		if (((chan->channel - 2192) % 5) == 0) {
     92 			channelSel = ((chan->channel - 672) * 2 - 3040)/10;
     93 			bModeSynth = 0;
     94 		} else if (((chan->channel - 2224) % 5) == 0) {
     95 			channelSel = ((chan->channel - 704) * 2 - 3040) / 10;
     96 			bModeSynth = 1;
     97 		} else {
     98 			HALDEBUG(ah, HAL_DEBUG_ANY,
     99 			    "%s: invalid channel %u MHz\n",
    100 			    __func__, chan->channel);
    101 			return AH_FALSE;
    102 		}
    103 
    104 		channelSel = (channelSel << 2) & 0xff;
    105 		channelSel = ath_hal_reverseBits(channelSel, 8);
    106 
    107 		txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
    108 		if (chan->channel == 2484) {
    109 			/* Enable channel spreading for channel 14 */
    110 			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
    111 				txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
    112 		} else {
    113 			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
    114 				txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
    115 		}
    116 	} else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) {
    117 		freq = chan->channel - 2; /* Align to even 5MHz raster */
    118 		channelSel = ath_hal_reverseBits(
    119 			(uint32_t)(((freq - 4800)*10)/25 + 1), 8);
    120             	aModeRefSel = ath_hal_reverseBits(0, 2);
    121 	} else if ((chan->channel % 20) == 0 && chan->channel >= 5120) {
    122 		channelSel = ath_hal_reverseBits(
    123 			((chan->channel - 4800) / 20 << 2), 8);
    124 		aModeRefSel = ath_hal_reverseBits(3, 2);
    125 	} else if ((chan->channel % 10) == 0) {
    126 		channelSel = ath_hal_reverseBits(
    127 			((chan->channel - 4800) / 10 << 1), 8);
    128 		aModeRefSel = ath_hal_reverseBits(2, 2);
    129 	} else if ((chan->channel % 5) == 0) {
    130 		channelSel = ath_hal_reverseBits(
    131 			(chan->channel - 4800) / 5, 8);
    132 		aModeRefSel = ath_hal_reverseBits(1, 2);
    133 	} else {
    134 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
    135 		    __func__, chan->channel);
    136 		return AH_FALSE;
    137 	}
    138 
    139 	reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
    140 			(1 << 12) | 0x1;
    141 	OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
    142 
    143 	reg32 >>= 8;
    144 	OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
    145 
    146 	AH_PRIVATE(ah)->ah_curchan = chan;
    147 	return AH_TRUE;
    148 }
    149 
    150 /*
    151  * Return a reference to the requested RF Bank.
    152  */
    153 static uint32_t *
    154 ar5112GetRfBank(struct ath_hal *ah, int bank)
    155 {
    156 	struct ar5112State *priv = AR5112(ah);
    157 
    158 	HALASSERT(priv != AH_NULL);
    159 	switch (bank) {
    160 	case 1: return priv->Bank1Data;
    161 	case 2: return priv->Bank2Data;
    162 	case 3: return priv->Bank3Data;
    163 	case 6: return priv->Bank6Data;
    164 	case 7: return priv->Bank7Data;
    165 	}
    166 	HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
    167 	    __func__, bank);
    168 	return AH_NULL;
    169 }
    170 
    171 /*
    172  * Reads EEPROM header info from device structure and programs
    173  * all rf registers
    174  *
    175  * REQUIRES: Access to the analog rf device
    176  */
    177 static HAL_BOOL
    178 ar5112SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan,
    179 	uint16_t modesIndex, uint16_t *rfXpdGain)
    180 {
    181 #define	RF_BANK_SETUP(_priv, _ix, _col) do {				    \
    182 	int i;								    \
    183 	for (i = 0; i < N(ar5212Bank##_ix##_5112); i++)			    \
    184 		(_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5112[i][_col];\
    185 } while (0)
    186 	struct ath_hal_5212 *ahp = AH5212(ah);
    187 	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
    188 	uint16_t rfXpdSel, gainI;
    189 	uint16_t ob5GHz = 0, db5GHz = 0;
    190 	uint16_t ob2GHz = 0, db2GHz = 0;
    191 	struct ar5112State *priv = AR5112(ah);
    192 	GAIN_VALUES *gv = &ahp->ah_gainValues;
    193 	int regWrites = 0;
    194 
    195 	HALASSERT(priv);
    196 
    197 	/* Setup rf parameters */
    198 	switch (chan->channelFlags & CHANNEL_ALL) {
    199 	case CHANNEL_A:
    200 	case CHANNEL_T:
    201 		if (chan->channel > 4000 && chan->channel < 5260) {
    202 			ob5GHz = ee->ee_ob1;
    203 			db5GHz = ee->ee_db1;
    204 		} else if (chan->channel >= 5260 && chan->channel < 5500) {
    205 			ob5GHz = ee->ee_ob2;
    206 			db5GHz = ee->ee_db2;
    207 		} else if (chan->channel >= 5500 && chan->channel < 5725) {
    208 			ob5GHz = ee->ee_ob3;
    209 			db5GHz = ee->ee_db3;
    210 		} else if (chan->channel >= 5725) {
    211 			ob5GHz = ee->ee_ob4;
    212 			db5GHz = ee->ee_db4;
    213 		} else {
    214 			/* XXX else */
    215 		}
    216 		rfXpdSel = ee->ee_xpd[headerInfo11A];
    217 		gainI = ee->ee_gainI[headerInfo11A];
    218 		break;
    219 	case CHANNEL_B:
    220 		ob2GHz = ee->ee_ob2GHz[0];
    221 		db2GHz = ee->ee_db2GHz[0];
    222 		rfXpdSel = ee->ee_xpd[headerInfo11B];
    223 		gainI = ee->ee_gainI[headerInfo11B];
    224 		break;
    225 	case CHANNEL_G:
    226 	case CHANNEL_108G:
    227 		ob2GHz = ee->ee_ob2GHz[1];
    228 		db2GHz = ee->ee_ob2GHz[1];
    229 		rfXpdSel = ee->ee_xpd[headerInfo11G];
    230 		gainI = ee->ee_gainI[headerInfo11G];
    231 		break;
    232 	default:
    233 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
    234 		    __func__, chan->channelFlags);
    235 		return AH_FALSE;
    236 	}
    237 
    238 	/* Setup Bank 1 Write */
    239 	RF_BANK_SETUP(priv, 1, 1);
    240 
    241 	/* Setup Bank 2 Write */
    242 	RF_BANK_SETUP(priv, 2, modesIndex);
    243 
    244 	/* Setup Bank 3 Write */
    245 	RF_BANK_SETUP(priv, 3, modesIndex);
    246 
    247 	/* Setup Bank 6 Write */
    248 	RF_BANK_SETUP(priv, 6, modesIndex);
    249 
    250 	ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdSel,     1, 302, 0);
    251 
    252 	ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[0], 2, 270, 0);
    253 	ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[1], 2, 257, 0);
    254 
    255 	if (IS_CHAN_OFDM(chan)) {
    256 		ar5212ModifyRfBuffer(priv->Bank6Data,
    257 			gv->currStep->paramVal[GP_PWD_138], 1, 168, 3);
    258 		ar5212ModifyRfBuffer(priv->Bank6Data,
    259 			gv->currStep->paramVal[GP_PWD_137], 1, 169, 3);
    260 		ar5212ModifyRfBuffer(priv->Bank6Data,
    261 			gv->currStep->paramVal[GP_PWD_136], 1, 170, 3);
    262 		ar5212ModifyRfBuffer(priv->Bank6Data,
    263 			gv->currStep->paramVal[GP_PWD_132], 1, 174, 3);
    264 		ar5212ModifyRfBuffer(priv->Bank6Data,
    265 			gv->currStep->paramVal[GP_PWD_131], 1, 175, 3);
    266 		ar5212ModifyRfBuffer(priv->Bank6Data,
    267 			gv->currStep->paramVal[GP_PWD_130], 1, 176, 3);
    268 	}
    269 
    270 	/* Only the 5 or 2 GHz OB/DB need to be set for a mode */
    271 	if (IS_CHAN_2GHZ(chan)) {
    272 		ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 287, 0);
    273 		ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 290, 0);
    274 	} else {
    275 		ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 279, 0);
    276 		ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 282, 0);
    277 	}
    278 
    279 	/* Lower synth voltage for X112 Rev 2.0 only */
    280 	if (IS_RADX112_REV2(ah)) {
    281 		/* Non-Reversed analyg registers - so values are pre-reversed */
    282 		ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 90, 2);
    283 		ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 92, 2);
    284 		ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 94, 2);
    285 		ar5212ModifyRfBuffer(priv->Bank6Data, 2, 1, 254, 2);
    286 	}
    287 
    288     /* Decrease Power Consumption for 5312/5213 and up */
    289     if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) {
    290         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 281, 1);
    291         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 1, 3);
    292         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 3, 3);
    293         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 139, 3);
    294         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 140, 3);
    295     }
    296 
    297 	/* Setup Bank 7 Setup */
    298 	RF_BANK_SETUP(priv, 7, modesIndex);
    299 	if (IS_CHAN_OFDM(chan))
    300 		ar5212ModifyRfBuffer(priv->Bank7Data,
    301 			gv->currStep->paramVal[GP_MIXGAIN_OVR], 2, 37, 0);
    302 
    303 	ar5212ModifyRfBuffer(priv->Bank7Data, gainI, 6, 14, 0);
    304 
    305 	/* Adjust params for Derby TX power control */
    306 	if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) {
    307         	uint32_t	rfDelay, rfPeriod;
    308 
    309         	rfDelay = 0xf;
    310         	rfPeriod = (IS_CHAN_HALF_RATE(chan)) ?  0x8 : 0xf;
    311         	ar5212ModifyRfBuffer(priv->Bank7Data, rfDelay, 4, 58, 0);
    312         	ar5212ModifyRfBuffer(priv->Bank7Data, rfPeriod, 4, 70, 0);
    313 	}
    314 
    315 #ifdef notyet
    316 	/* Analog registers are setup - EAR can modify */
    317 	if (ar5212IsEarEngaged(pDev, chan))
    318 		uint32_t modifier;
    319 		ar5212EarModify(pDev, EAR_LC_RF_WRITE, chan, &modifier);
    320 #endif
    321 	/* Write Analog registers */
    322 	HAL_INI_WRITE_BANK(ah, ar5212Bank1_5112, priv->Bank1Data, regWrites);
    323 	HAL_INI_WRITE_BANK(ah, ar5212Bank2_5112, priv->Bank2Data, regWrites);
    324 	HAL_INI_WRITE_BANK(ah, ar5212Bank3_5112, priv->Bank3Data, regWrites);
    325 	HAL_INI_WRITE_BANK(ah, ar5212Bank6_5112, priv->Bank6Data, regWrites);
    326 	HAL_INI_WRITE_BANK(ah, ar5212Bank7_5112, priv->Bank7Data, regWrites);
    327 
    328 	/* Now that we have reprogrammed rfgain value, clear the flag. */
    329 	ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
    330 	return AH_TRUE;
    331 #undef	RF_BANK_SETUP
    332 }
    333 
    334 /*
    335  * Read the transmit power levels from the structures taken from EEPROM
    336  * Interpolate read transmit power values for this channel
    337  * Organize the transmit power values into a table for writing into the hardware
    338  */
    339 static HAL_BOOL
    340 ar5112SetPowerTable(struct ath_hal *ah,
    341 	int16_t *pPowerMin, int16_t *pPowerMax, HAL_CHANNEL_INTERNAL *chan,
    342 	uint16_t *rfXpdGain)
    343 {
    344 	struct ath_hal_5212 *ahp = AH5212(ah);
    345 	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
    346 	uint32_t numXpdGain = IS_RADX112_REV2(ah) ? 2 : 1;
    347 	uint32_t    xpdGainMask = 0;
    348 	int16_t     powerMid, *pPowerMid = &powerMid;
    349 
    350 	const EXPN_DATA_PER_CHANNEL_5112 *pRawCh;
    351 	const EEPROM_POWER_EXPN_5112     *pPowerExpn = AH_NULL;
    352 
    353 	uint32_t    ii, jj, kk;
    354 	int16_t     minPwr_t4, maxPwr_t4, Pmin, Pmid;
    355 
    356 	uint32_t    chan_idx_L = 0, chan_idx_R = 0;
    357 	uint16_t    chan_L, chan_R;
    358 
    359 	int16_t     pwr_table0[64];
    360 	int16_t     pwr_table1[64];
    361 	uint16_t    pcdacs[10];
    362 	int16_t     powers[10];
    363 	uint16_t    numPcd;
    364 	int16_t     powTableLXPD[2][64];
    365 	int16_t     powTableHXPD[2][64];
    366 	int16_t     tmpPowerTable[64];
    367 	uint16_t    xgainList[2];
    368 	uint16_t    xpdMask;
    369 
    370 	switch (chan->channelFlags & CHANNEL_ALL) {
    371 	case CHANNEL_A:
    372 	case CHANNEL_T:
    373 		pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11A];
    374 		xpdGainMask = ee->ee_xgain[headerInfo11A];
    375 		break;
    376 	case CHANNEL_B:
    377 		pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11B];
    378 		xpdGainMask = ee->ee_xgain[headerInfo11B];
    379 		break;
    380 	case CHANNEL_G:
    381 	case CHANNEL_108G:
    382 		pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11G];
    383 		xpdGainMask = ee->ee_xgain[headerInfo11G];
    384 		break;
    385 	default:
    386 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown channel flags 0x%x\n",
    387 		    __func__, chan->channelFlags & CHANNEL_ALL);
    388 		return AH_FALSE;
    389 	}
    390 
    391 	if ((xpdGainMask & pPowerExpn->xpdMask) < 1) {
    392 		HALDEBUG(ah, HAL_DEBUG_ANY,
    393 		    "%s: desired xpdGainMask 0x%x not supported by "
    394 		    "calibrated xpdMask 0x%x\n", __func__,
    395 		    xpdGainMask, pPowerExpn->xpdMask);
    396 		return AH_FALSE;
    397 	}
    398 
    399 	maxPwr_t4 = (int16_t)(2*(*pPowerMax));	/* pwr_t2 -> pwr_t4 */
    400 	minPwr_t4 = (int16_t)(2*(*pPowerMin));	/* pwr_t2 -> pwr_t4 */
    401 
    402 	xgainList[0] = 0xDEAD;
    403 	xgainList[1] = 0xDEAD;
    404 
    405 	kk = 0;
    406 	xpdMask = pPowerExpn->xpdMask;
    407 	for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) {
    408 		if (((xpdMask >> jj) & 1) > 0) {
    409 			if (kk > 1) {
    410 				HALDEBUG(ah, HAL_DEBUG_ANY,
    411 				    "A maximum of 2 xpdGains supported"
    412 				    "in pExpnPower data\n");
    413 				return AH_FALSE;
    414 			}
    415 			xgainList[kk++] = (uint16_t)jj;
    416 		}
    417 	}
    418 
    419 	ar5212GetLowerUpperIndex(chan->channel, &pPowerExpn->pChannels[0],
    420 		pPowerExpn->numChannels, &chan_idx_L, &chan_idx_R);
    421 
    422 	kk = 0;
    423 	for (ii = chan_idx_L; ii <= chan_idx_R; ii++) {
    424 		pRawCh = &(pPowerExpn->pDataPerChannel[ii]);
    425 		if (xgainList[1] == 0xDEAD) {
    426 			jj = xgainList[0];
    427 			numPcd = pRawCh->pDataPerXPD[jj].numPcdacs;
    428 			OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0],
    429 				numPcd * sizeof(uint16_t));
    430 			OS_MEMCPY(&powers[0], &pRawCh->pDataPerXPD[jj].pwr_t4[0],
    431 				numPcd * sizeof(int16_t));
    432 			if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0],
    433 				pRawCh->maxPower_t4, &tmpPowerTable[0])) {
    434 				return AH_FALSE;
    435 			}
    436 			OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0],
    437 				64*sizeof(int16_t));
    438 		} else {
    439 			jj = xgainList[0];
    440 			numPcd = pRawCh->pDataPerXPD[jj].numPcdacs;
    441 			OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0],
    442 				numPcd*sizeof(uint16_t));
    443 			OS_MEMCPY(&powers[0],
    444 				&pRawCh->pDataPerXPD[jj].pwr_t4[0],
    445 				numPcd*sizeof(int16_t));
    446 			if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0],
    447 				pRawCh->maxPower_t4, &tmpPowerTable[0])) {
    448 				return AH_FALSE;
    449 			}
    450 			OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0],
    451 				64 * sizeof(int16_t));
    452 
    453 			jj = xgainList[1];
    454 			numPcd = pRawCh->pDataPerXPD[jj].numPcdacs;
    455 			OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0],
    456 				numPcd * sizeof(uint16_t));
    457 			OS_MEMCPY(&powers[0],
    458 				&pRawCh->pDataPerXPD[jj].pwr_t4[0],
    459 				numPcd * sizeof(int16_t));
    460 			if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0],
    461 				pRawCh->maxPower_t4, &tmpPowerTable[0])) {
    462 				return AH_FALSE;
    463 			}
    464 			OS_MEMCPY(&powTableHXPD[kk][0], &tmpPowerTable[0],
    465 				64 * sizeof(int16_t));
    466 		}
    467 		kk++;
    468 	}
    469 
    470 	chan_L = pPowerExpn->pChannels[chan_idx_L];
    471 	chan_R = pPowerExpn->pChannels[chan_idx_R];
    472 	kk = chan_idx_R - chan_idx_L;
    473 
    474 	if (xgainList[1] == 0xDEAD) {
    475 		for (jj = 0; jj < 64; jj++) {
    476 			pwr_table0[jj] = interpolate_signed(
    477 				chan->channel, chan_L, chan_R,
    478 				powTableLXPD[0][jj], powTableLXPD[kk][jj]);
    479 		}
    480 		Pmin = getPminAndPcdacTableFromPowerTable(&pwr_table0[0],
    481 				ahp->ah_pcdacTable);
    482 		*pPowerMin = (int16_t) (Pmin / 2);
    483 		*pPowerMid = (int16_t) (pwr_table0[63] / 2);
    484 		*pPowerMax = (int16_t) (pwr_table0[63] / 2);
    485 		rfXpdGain[0] = xgainList[0];
    486 		rfXpdGain[1] = rfXpdGain[0];
    487 	} else {
    488 		for (jj = 0; jj < 64; jj++) {
    489 			pwr_table0[jj] = interpolate_signed(
    490 				chan->channel, chan_L, chan_R,
    491 				powTableLXPD[0][jj], powTableLXPD[kk][jj]);
    492 			pwr_table1[jj] = interpolate_signed(
    493 				chan->channel, chan_L, chan_R,
    494 				powTableHXPD[0][jj], powTableHXPD[kk][jj]);
    495 		}
    496 		if (numXpdGain == 2) {
    497 			Pmin = getPminAndPcdacTableFromTwoPowerTables(
    498 				&pwr_table0[0], &pwr_table1[0],
    499 				ahp->ah_pcdacTable, &Pmid);
    500 			*pPowerMin = (int16_t) (Pmin / 2);
    501 			*pPowerMid = (int16_t) (Pmid / 2);
    502 			*pPowerMax = (int16_t) (pwr_table0[63] / 2);
    503 			rfXpdGain[0] = xgainList[0];
    504 			rfXpdGain[1] = xgainList[1];
    505 		} else if (minPwr_t4 <= pwr_table1[63] &&
    506 			   maxPwr_t4 <= pwr_table1[63]) {
    507 			Pmin = getPminAndPcdacTableFromPowerTable(
    508 				&pwr_table1[0], ahp->ah_pcdacTable);
    509 			rfXpdGain[0] = xgainList[1];
    510 			rfXpdGain[1] = rfXpdGain[0];
    511 			*pPowerMin = (int16_t) (Pmin / 2);
    512 			*pPowerMid = (int16_t) (pwr_table1[63] / 2);
    513 			*pPowerMax = (int16_t) (pwr_table1[63] / 2);
    514 		} else {
    515 			Pmin = getPminAndPcdacTableFromPowerTable(
    516 				&pwr_table0[0], ahp->ah_pcdacTable);
    517 			rfXpdGain[0] = xgainList[0];
    518 			rfXpdGain[1] = rfXpdGain[0];
    519 			*pPowerMin = (int16_t) (Pmin/2);
    520 			*pPowerMid = (int16_t) (pwr_table0[63] / 2);
    521 			*pPowerMax = (int16_t) (pwr_table0[63] / 2);
    522 		}
    523 	}
    524 
    525 	/*
    526 	 * Move 5112 rates to match power tables where the max
    527 	 * power table entry corresponds with maxPower.
    528 	 */
    529 	HALASSERT(*pPowerMax <= PCDAC_STOP);
    530 	ahp->ah_txPowerIndexOffset = PCDAC_STOP - *pPowerMax;
    531 
    532 	return AH_TRUE;
    533 }
    534 
    535 /*
    536  * Returns interpolated or the scaled up interpolated value
    537  */
    538 static int16_t
    539 interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
    540 	int16_t targetLeft, int16_t targetRight)
    541 {
    542 	int16_t rv;
    543 
    544 	if (srcRight != srcLeft) {
    545 		rv = ((target - srcLeft)*targetRight +
    546 		      (srcRight - target)*targetLeft) / (srcRight - srcLeft);
    547 	} else {
    548 		rv = targetLeft;
    549 	}
    550 	return rv;
    551 }
    552 
    553 /*
    554  * Return indices surrounding the value in sorted integer lists.
    555  *
    556  * NB: the input list is assumed to be sorted in ascending order
    557  */
    558 static void
    559 ar5212GetLowerUpperIndex(uint16_t v, uint16_t *lp, uint16_t listSize,
    560                           uint32_t *vlo, uint32_t *vhi)
    561 {
    562 	uint32_t target = v;
    563 	uint16_t *ep = lp+listSize;
    564 	uint16_t *tp;
    565 
    566 	/*
    567 	 * Check first and last elements for out-of-bounds conditions.
    568 	 */
    569 	if (target < lp[0]) {
    570 		*vlo = *vhi = 0;
    571 		return;
    572 	}
    573 	if (target >= ep[-1]) {
    574 		*vlo = *vhi = listSize - 1;
    575 		return;
    576 	}
    577 
    578 	/* look for value being near or between 2 values in list */
    579 	for (tp = lp; tp < ep; tp++) {
    580 		/*
    581 		 * If value is close to the current value of the list
    582 		 * then target is not between values, it is one of the values
    583 		 */
    584 		if (*tp == target) {
    585 			*vlo = *vhi = tp - lp;
    586 			return;
    587 		}
    588 		/*
    589 		 * Look for value being between current value and next value
    590 		 * if so return these 2 values
    591 		 */
    592 		if (target < tp[1]) {
    593 			*vlo = tp - lp;
    594 			*vhi = *vlo + 1;
    595 			return;
    596 		}
    597 	}
    598 }
    599 
    600 static HAL_BOOL
    601 getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs, int16_t *power, int16_t maxPower, int16_t *retVals)
    602 {
    603 	uint16_t    ii;
    604 	uint16_t    idxL = 0;
    605 	uint16_t    idxR = 1;
    606 
    607 	if (numPcdacs < 2) {
    608 		HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
    609 		     "%s: at least 2 pcdac values needed [%d]\n",
    610 		     __func__, numPcdacs);
    611 		return AH_FALSE;
    612 	}
    613 	for (ii = 0; ii < 64; ii++) {
    614 		if (ii>pcdacs[idxR] && idxR < numPcdacs-1) {
    615 			idxL++;
    616 			idxR++;
    617 		}
    618 		retVals[ii] = interpolate_signed(ii,
    619 			pcdacs[idxL], pcdacs[idxR], power[idxL], power[idxR]);
    620 		if (retVals[ii] >= maxPower) {
    621 			while (ii < 64)
    622 				retVals[ii++] = maxPower;
    623 		}
    624 	}
    625 	return AH_TRUE;
    626 }
    627 
    628 /*
    629  * Takes a single calibration curve and creates a power table.
    630  * Adjusts the new power table so the max power is relative
    631  * to the maximum index in the power table.
    632  *
    633  * WARNING: rates must be adjusted for this relative power table
    634  */
    635 static int16_t
    636 getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4, uint16_t retVals[])
    637 {
    638     int16_t ii, jj, jjMax;
    639     int16_t pMin, currPower, pMax;
    640 
    641     /* If the spread is > 31.5dB, keep the upper 31.5dB range */
    642     if ((pwrTableT4[63] - pwrTableT4[0]) > 126) {
    643         pMin = pwrTableT4[63] - 126;
    644     } else {
    645         pMin = pwrTableT4[0];
    646     }
    647 
    648     pMax = pwrTableT4[63];
    649     jjMax = 63;
    650 
    651     /* Search for highest pcdac 0.25dB below maxPower */
    652     while ((pwrTableT4[jjMax] > (pMax - 1) ) && (jjMax >= 0)) {
    653         jjMax--;
    654     }
    655 
    656     jj = jjMax;
    657     currPower = pMax;
    658     for (ii = 63; ii >= 0; ii--) {
    659         while ((jj < 64) && (jj > 0) && (pwrTableT4[jj] >= currPower)) {
    660             jj--;
    661         }
    662         if (jj == 0) {
    663             while (ii >= 0) {
    664                 retVals[ii] = retVals[ii + 1];
    665                 ii--;
    666             }
    667             break;
    668         }
    669         retVals[ii] = jj;
    670         currPower -= 2;  // corresponds to a 0.5dB step
    671     }
    672     return pMin;
    673 }
    674 
    675 /*
    676  * Combines the XPD curves from two calibration sets into a single
    677  * power table and adjusts the power table so the max power is relative
    678  * to the maximum index in the power table
    679  *
    680  * WARNING: rates must be adjusted for this relative power table
    681  */
    682 static int16_t
    683 getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4,
    684 	int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid)
    685 {
    686     int16_t     ii, jj, jjMax;
    687     int16_t     pMin, pMax, currPower;
    688     int16_t     *pwrTableT4;
    689     uint16_t    msbFlag = 0x40;  // turns on the 7th bit of the pcdac
    690 
    691     /* If the spread is > 31.5dB, keep the upper 31.5dB range */
    692     if ((pwrTableLXpdT4[63] - pwrTableHXpdT4[0]) > 126) {
    693         pMin = pwrTableLXpdT4[63] - 126;
    694     } else {
    695         pMin = pwrTableHXpdT4[0];
    696     }
    697 
    698     pMax = pwrTableLXpdT4[63];
    699     jjMax = 63;
    700     /* Search for highest pcdac 0.25dB below maxPower */
    701     while ((pwrTableLXpdT4[jjMax] > (pMax - 1) ) && (jjMax >= 0)){
    702         jjMax--;
    703     }
    704 
    705     *pMid = pwrTableHXpdT4[63];
    706     jj = jjMax;
    707     ii = 63;
    708     currPower = pMax;
    709     pwrTableT4 = &(pwrTableLXpdT4[0]);
    710     while (ii >= 0) {
    711         if ((currPower <= *pMid) || ( (jj == 0) && (msbFlag == 0x40))){
    712             msbFlag = 0x00;
    713             pwrTableT4 = &(pwrTableHXpdT4[0]);
    714             jj = 63;
    715         }
    716         while ((jj > 0) && (pwrTableT4[jj] >= currPower)) {
    717             jj--;
    718         }
    719         if ((jj == 0) && (msbFlag == 0x00)) {
    720             while (ii >= 0) {
    721                 retVals[ii] = retVals[ii+1];
    722                 ii--;
    723             }
    724             break;
    725         }
    726         retVals[ii] = jj | msbFlag;
    727         currPower -= 2;  // corresponds to a 0.5dB step
    728         ii--;
    729     }
    730     return pMin;
    731 }
    732 
    733 static int16_t
    734 ar5112GetMinPower(struct ath_hal *ah, const EXPN_DATA_PER_CHANNEL_5112 *data)
    735 {
    736 	int i, minIndex;
    737 	int16_t minGain,minPwr,minPcdac,retVal;
    738 
    739 	/* Assume NUM_POINTS_XPD0 > 0 */
    740 	minGain = data->pDataPerXPD[0].xpd_gain;
    741 	for (minIndex=0,i=1; i<NUM_XPD_PER_CHANNEL; i++) {
    742 		if (data->pDataPerXPD[i].xpd_gain < minGain) {
    743 			minIndex = i;
    744 			minGain = data->pDataPerXPD[i].xpd_gain;
    745 		}
    746 	}
    747 	minPwr = data->pDataPerXPD[minIndex].pwr_t4[0];
    748 	minPcdac = data->pDataPerXPD[minIndex].pcdac[0];
    749 	for (i=1; i<NUM_POINTS_XPD0; i++) {
    750 		if (data->pDataPerXPD[minIndex].pwr_t4[i] < minPwr) {
    751 			minPwr = data->pDataPerXPD[minIndex].pwr_t4[i];
    752 			minPcdac = data->pDataPerXPD[minIndex].pcdac[i];
    753 		}
    754 	}
    755 	retVal = minPwr - (minPcdac*2);
    756 	return(retVal);
    757 }
    758 
    759 static HAL_BOOL
    760 ar5112GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan,
    761 	int16_t *maxPow, int16_t *minPow)
    762 {
    763 	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
    764 	int numChannels=0,i,last;
    765 	int totalD, totalF,totalMin;
    766 	const EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL;
    767 	const EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL;
    768 
    769 	*maxPow = 0;
    770 	if (IS_CHAN_A(chan)) {
    771 		powerArray = ee->ee_modePowerArray5112;
    772 		data = powerArray[headerInfo11A].pDataPerChannel;
    773 		numChannels = powerArray[headerInfo11A].numChannels;
    774 	} else if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) {
    775 		/* XXX - is this correct? Should we also use the same power for turbo G? */
    776 		powerArray = ee->ee_modePowerArray5112;
    777 		data = powerArray[headerInfo11G].pDataPerChannel;
    778 		numChannels = powerArray[headerInfo11G].numChannels;
    779 	} else if (IS_CHAN_B(chan)) {
    780 		powerArray = ee->ee_modePowerArray5112;
    781 		data = powerArray[headerInfo11B].pDataPerChannel;
    782 		numChannels = powerArray[headerInfo11B].numChannels;
    783 	} else {
    784 		return (AH_TRUE);
    785 	}
    786 	/* Make sure the channel is in the range of the TP values
    787 	 *  (freq piers)
    788 	 */
    789 	if (numChannels < 1)
    790 		return(AH_FALSE);
    791 
    792 	if ((chan->channel < data[0].channelValue) ||
    793 	    (chan->channel > data[numChannels-1].channelValue)) {
    794 		if (chan->channel < data[0].channelValue) {
    795 			*maxPow = data[0].maxPower_t4;
    796 			*minPow = ar5112GetMinPower(ah, &data[0]);
    797 			return(AH_TRUE);
    798 		} else {
    799 			*maxPow = data[numChannels - 1].maxPower_t4;
    800 			*minPow = ar5112GetMinPower(ah, &data[numChannels - 1]);
    801 			return(AH_TRUE);
    802 		}
    803 	}
    804 
    805 	/* Linearly interpolate the power value now */
    806 	for (last=0,i=0;
    807 	     (i<numChannels) && (chan->channel > data[i].channelValue);
    808 	     last=i++);
    809 	totalD = data[i].channelValue - data[last].channelValue;
    810 	if (totalD > 0) {
    811 		totalF = data[i].maxPower_t4 - data[last].maxPower_t4;
    812 		*maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + data[last].maxPower_t4*totalD)/totalD);
    813 
    814 		totalMin = ar5112GetMinPower(ah,&data[i]) - ar5112GetMinPower(ah, &data[last]);
    815 		*minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + ar5112GetMinPower(ah, &data[last])*totalD)/totalD);
    816 		return (AH_TRUE);
    817 	} else {
    818 		if (chan->channel == data[i].channelValue) {
    819 			*maxPow = data[i].maxPower_t4;
    820 			*minPow = ar5112GetMinPower(ah, &data[i]);
    821 			return(AH_TRUE);
    822 		} else
    823 			return(AH_FALSE);
    824 	}
    825 }
    826 
    827 /*
    828  * Free memory for analog bank scratch buffers
    829  */
    830 static void
    831 ar5112RfDetach(struct ath_hal *ah)
    832 {
    833 	struct ath_hal_5212 *ahp = AH5212(ah);
    834 
    835 	HALASSERT(ahp->ah_rfHal != AH_NULL);
    836 	ath_hal_free(ahp->ah_rfHal);
    837 	ahp->ah_rfHal = AH_NULL;
    838 }
    839 
    840 /*
    841  * Allocate memory for analog bank scratch buffers
    842  * Scratch Buffer will be reinitialized every reset so no need to zero now
    843  */
    844 static HAL_BOOL
    845 ar5112RfAttach(struct ath_hal *ah, HAL_STATUS *status)
    846 {
    847 	struct ath_hal_5212 *ahp = AH5212(ah);
    848 	struct ar5112State *priv;
    849 
    850 	HALASSERT(ah->ah_magic == AR5212_MAGIC);
    851 
    852 	HALASSERT(ahp->ah_rfHal == AH_NULL);
    853 	priv = ath_hal_malloc(sizeof(struct ar5112State));
    854 	if (priv == AH_NULL) {
    855 		HALDEBUG(ah, HAL_DEBUG_ANY,
    856 		    "%s: cannot allocate private state\n", __func__);
    857 		*status = HAL_ENOMEM;		/* XXX */
    858 		return AH_FALSE;
    859 	}
    860 	priv->base.rfDetach		= ar5112RfDetach;
    861 	priv->base.writeRegs		= ar5112WriteRegs;
    862 	priv->base.getRfBank		= ar5112GetRfBank;
    863 	priv->base.setChannel		= ar5112SetChannel;
    864 	priv->base.setRfRegs		= ar5112SetRfRegs;
    865 	priv->base.setPowerTable	= ar5112SetPowerTable;
    866 	priv->base.getChannelMaxMinPower = ar5112GetChannelMaxMinPower;
    867 	priv->base.getNfAdjust		= ar5212GetNfAdjust;
    868 
    869 	ahp->ah_pcdacTable = priv->pcdacTable;
    870 	ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
    871 	ahp->ah_rfHal = &priv->base;
    872 
    873 	return AH_TRUE;
    874 }
    875 
    876 static HAL_BOOL
    877 ar5112Probe(struct ath_hal *ah)
    878 {
    879 	return IS_RAD5112(ah);
    880 }
    881 AH_RF(RF5112, ar5112Probe, ar5112RfAttach);
    882