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