1/*-
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
5 * Copyright (c) 2002-2008 Atheros Communications, Inc.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * $FreeBSD: releng/12.0/sys/dev/ath/ath_hal/ar5212/ar2316.c 326695 2017-12-08 15:57:29Z pfg $
20 */
21#include "opt_ah.h"
22
23#include "ah.h"
24#include "ah_internal.h"
25
26#include "ar5212/ar5212.h"
27#include "ar5212/ar5212reg.h"
28#include "ar5212/ar5212phy.h"
29
30#include "ah_eeprom_v3.h"
31
32#define AH_5212_2316
33#include "ar5212/ar5212.ini"
34
35#define	N(a)	(sizeof(a)/sizeof(a[0]))
36
37typedef	RAW_DATA_STRUCT_2413 RAW_DATA_STRUCT_2316;
38typedef RAW_DATA_PER_CHANNEL_2413 RAW_DATA_PER_CHANNEL_2316;
39#define PWR_TABLE_SIZE_2316 PWR_TABLE_SIZE_2413
40
41struct ar2316State {
42	RF_HAL_FUNCS	base;		/* public state, must be first */
43	uint16_t	pcdacTable[PWR_TABLE_SIZE_2316];
44
45	uint32_t	Bank1Data[N(ar5212Bank1_2316)];
46	uint32_t	Bank2Data[N(ar5212Bank2_2316)];
47	uint32_t	Bank3Data[N(ar5212Bank3_2316)];
48	uint32_t	Bank6Data[N(ar5212Bank6_2316)];
49	uint32_t	Bank7Data[N(ar5212Bank7_2316)];
50
51	/*
52	 * Private state for reduced stack usage.
53	 */
54	/* filled out Vpd table for all pdGains (chanL) */
55	uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL]
56			    [MAX_PWR_RANGE_IN_HALF_DB];
57	/* filled out Vpd table for all pdGains (chanR) */
58	uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL]
59			    [MAX_PWR_RANGE_IN_HALF_DB];
60	/* filled out Vpd table for all pdGains (interpolated) */
61	uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL]
62			    [MAX_PWR_RANGE_IN_HALF_DB];
63};
64#define	AR2316(ah)	((struct ar2316State *) AH5212(ah)->ah_rfHal)
65
66extern	void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
67		uint32_t numBits, uint32_t firstBit, uint32_t column);
68
69static void
70ar2316WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
71	int regWrites)
72{
73	struct ath_hal_5212 *ahp = AH5212(ah);
74
75	HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2316, modesIndex, regWrites);
76	HAL_INI_WRITE_ARRAY(ah, ar5212Common_2316, 1, regWrites);
77	HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2316, freqIndex, regWrites);
78
79	/* For AP51 */
80        if (!ahp->ah_cwCalRequire) {
81		OS_REG_WRITE(ah, 0xa358, (OS_REG_READ(ah, 0xa358) & ~0x2));
82        } else {
83		ahp->ah_cwCalRequire = AH_FALSE;
84        }
85}
86
87/*
88 * Take the MHz channel value and set the Channel value
89 *
90 * ASSUMES: Writes enabled to analog bus
91 */
92static HAL_BOOL
93ar2316SetChannel(struct ath_hal *ah,  struct ieee80211_channel *chan)
94{
95	uint16_t freq = ath_hal_gethwchannel(ah, chan);
96	uint32_t channelSel  = 0;
97	uint32_t bModeSynth  = 0;
98	uint32_t aModeRefSel = 0;
99	uint32_t reg32       = 0;
100
101	OS_MARK(ah, AH_MARK_SETCHANNEL, freq);
102
103	if (freq < 4800) {
104		uint32_t txctl;
105
106		if (((freq - 2192) % 5) == 0) {
107			channelSel = ((freq - 672) * 2 - 3040)/10;
108			bModeSynth = 0;
109		} else if (((freq - 2224) % 5) == 0) {
110			channelSel = ((freq - 704) * 2 - 3040) / 10;
111			bModeSynth = 1;
112		} else {
113			HALDEBUG(ah, HAL_DEBUG_ANY,
114			    "%s: invalid channel %u MHz\n",
115			    __func__, freq);
116			return AH_FALSE;
117		}
118
119		channelSel = (channelSel << 2) & 0xff;
120		channelSel = ath_hal_reverseBits(channelSel, 8);
121
122		txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
123		if (freq == 2484) {
124			/* Enable channel spreading for channel 14 */
125			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
126				txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
127		} else {
128			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
129				txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
130		}
131	} else if ((freq % 20) == 0 && freq >= 5120) {
132		channelSel = ath_hal_reverseBits(
133			((freq - 4800) / 20 << 2), 8);
134		aModeRefSel = ath_hal_reverseBits(3, 2);
135	} else if ((freq % 10) == 0) {
136		channelSel = ath_hal_reverseBits(
137			((freq - 4800) / 10 << 1), 8);
138		aModeRefSel = ath_hal_reverseBits(2, 2);
139	} else if ((freq % 5) == 0) {
140		channelSel = ath_hal_reverseBits(
141			(freq - 4800) / 5, 8);
142		aModeRefSel = ath_hal_reverseBits(1, 2);
143	} else {
144		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
145		    __func__, freq);
146		return AH_FALSE;
147	}
148
149	reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
150			(1 << 12) | 0x1;
151	OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
152
153	reg32 >>= 8;
154	OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
155
156	AH_PRIVATE(ah)->ah_curchan = chan;
157	return AH_TRUE;
158}
159
160/*
161 * Reads EEPROM header info from device structure and programs
162 * all rf registers
163 *
164 * REQUIRES: Access to the analog rf device
165 */
166static HAL_BOOL
167ar2316SetRfRegs(struct ath_hal *ah, const struct ieee80211_channel *chan,
168	uint16_t modesIndex, uint16_t *rfXpdGain)
169{
170#define	RF_BANK_SETUP(_priv, _ix, _col) do {				    \
171	int i;								    \
172	for (i = 0; i < N(ar5212Bank##_ix##_2316); i++)			    \
173		(_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2316[i][_col];\
174} while (0)
175	struct ath_hal_5212 *ahp = AH5212(ah);
176	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
177	uint16_t ob2GHz = 0, db2GHz = 0;
178	struct ar2316State *priv = AR2316(ah);
179	int regWrites = 0;
180
181	HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan %u/0x%x modesIndex %u\n",
182	    __func__, chan->ic_freq, chan->ic_flags, modesIndex);
183
184	HALASSERT(priv != AH_NULL);
185
186	/* Setup rf parameters */
187	if (IEEE80211_IS_CHAN_B(chan)) {
188		ob2GHz = ee->ee_obFor24;
189		db2GHz = ee->ee_dbFor24;
190	} else {
191		ob2GHz = ee->ee_obFor24g;
192		db2GHz = ee->ee_dbFor24g;
193	}
194
195	/* Bank 1 Write */
196	RF_BANK_SETUP(priv, 1, 1);
197
198	/* Bank 2 Write */
199	RF_BANK_SETUP(priv, 2, modesIndex);
200
201	/* Bank 3 Write */
202	RF_BANK_SETUP(priv, 3, modesIndex);
203
204	/* Bank 6 Write */
205	RF_BANK_SETUP(priv, 6, modesIndex);
206
207	ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz,   3, 178, 0);
208	ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz,   3, 175, 0);
209
210	/* Bank 7 Setup */
211	RF_BANK_SETUP(priv, 7, modesIndex);
212
213	/* Write Analog registers */
214	HAL_INI_WRITE_BANK(ah, ar5212Bank1_2316, priv->Bank1Data, regWrites);
215	HAL_INI_WRITE_BANK(ah, ar5212Bank2_2316, priv->Bank2Data, regWrites);
216	HAL_INI_WRITE_BANK(ah, ar5212Bank3_2316, priv->Bank3Data, regWrites);
217	HAL_INI_WRITE_BANK(ah, ar5212Bank6_2316, priv->Bank6Data, regWrites);
218	HAL_INI_WRITE_BANK(ah, ar5212Bank7_2316, priv->Bank7Data, regWrites);
219
220	/* Now that we have reprogrammed rfgain value, clear the flag. */
221	ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
222
223	return AH_TRUE;
224#undef	RF_BANK_SETUP
225}
226
227/*
228 * Return a reference to the requested RF Bank.
229 */
230static uint32_t *
231ar2316GetRfBank(struct ath_hal *ah, int bank)
232{
233	struct ar2316State *priv = AR2316(ah);
234
235	HALASSERT(priv != AH_NULL);
236	switch (bank) {
237	case 1: return priv->Bank1Data;
238	case 2: return priv->Bank2Data;
239	case 3: return priv->Bank3Data;
240	case 6: return priv->Bank6Data;
241	case 7: return priv->Bank7Data;
242	}
243	HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
244	    __func__, bank);
245	return AH_NULL;
246}
247
248/*
249 * Return indices surrounding the value in sorted integer lists.
250 *
251 * NB: the input list is assumed to be sorted in ascending order
252 */
253static void
254GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize,
255                          uint32_t *vlo, uint32_t *vhi)
256{
257	int16_t target = v;
258	const int16_t *ep = lp+listSize;
259	const int16_t *tp;
260
261	/*
262	 * Check first and last elements for out-of-bounds conditions.
263	 */
264	if (target < lp[0]) {
265		*vlo = *vhi = 0;
266		return;
267	}
268	if (target >= ep[-1]) {
269		*vlo = *vhi = listSize - 1;
270		return;
271	}
272
273	/* look for value being near or between 2 values in list */
274	for (tp = lp; tp < ep; tp++) {
275		/*
276		 * If value is close to the current value of the list
277		 * then target is not between values, it is one of the values
278		 */
279		if (*tp == target) {
280			*vlo = *vhi = tp - (const int16_t *) lp;
281			return;
282		}
283		/*
284		 * Look for value being between current value and next value
285		 * if so return these 2 values
286		 */
287		if (target < tp[1]) {
288			*vlo = tp - (const int16_t *) lp;
289			*vhi = *vlo + 1;
290			return;
291		}
292	}
293}
294
295/*
296 * Fill the Vpdlist for indices Pmax-Pmin
297 */
298static HAL_BOOL
299ar2316FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t  Pmax,
300		   const int16_t *pwrList, const int16_t *VpdList,
301		   uint16_t numIntercepts, uint16_t retVpdList[][64])
302{
303	uint16_t ii, jj, kk;
304	int16_t currPwr = (int16_t)(2*Pmin);
305	/* since Pmin is pwr*2 and pwrList is 4*pwr */
306	uint32_t  idxL, idxR;
307
308	ii = 0;
309	jj = 0;
310
311	if (numIntercepts < 2)
312		return AH_FALSE;
313
314	while (ii <= (uint16_t)(Pmax - Pmin)) {
315		GetLowerUpperIndex(currPwr, pwrList, numIntercepts,
316					 &(idxL), &(idxR));
317		if (idxR < 1)
318			idxR = 1;			/* extrapolate below */
319		if (idxL == (uint32_t)(numIntercepts - 1))
320			idxL = numIntercepts - 2;	/* extrapolate above */
321		if (pwrList[idxL] == pwrList[idxR])
322			kk = VpdList[idxL];
323		else
324			kk = (uint16_t)
325				(((currPwr - pwrList[idxL])*VpdList[idxR]+
326				  (pwrList[idxR] - currPwr)*VpdList[idxL])/
327				 (pwrList[idxR] - pwrList[idxL]));
328		retVpdList[pdGainIdx][ii] = kk;
329		ii++;
330		currPwr += 2;				/* half dB steps */
331	}
332
333	return AH_TRUE;
334}
335
336/*
337 * Returns interpolated or the scaled up interpolated value
338 */
339static int16_t
340interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
341	int16_t targetLeft, int16_t targetRight)
342{
343	int16_t rv;
344
345	if (srcRight != srcLeft) {
346		rv = ((target - srcLeft)*targetRight +
347		      (srcRight - target)*targetLeft) / (srcRight - srcLeft);
348	} else {
349		rv = targetLeft;
350	}
351	return rv;
352}
353
354/*
355 * Uses the data points read from EEPROM to reconstruct the pdadc power table
356 * Called by ar2316SetPowerTable()
357 */
358static int
359ar2316getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel,
360		const RAW_DATA_STRUCT_2316 *pRawDataset,
361		uint16_t pdGainOverlap_t2,
362		int16_t  *pMinCalPower, uint16_t pPdGainBoundaries[],
363		uint16_t pPdGainValues[], uint16_t pPDADCValues[])
364{
365	struct ar2316State *priv = AR2316(ah);
366#define	VpdTable_L	priv->vpdTable_L
367#define	VpdTable_R	priv->vpdTable_R
368#define	VpdTable_I	priv->vpdTable_I
369	uint32_t ii, jj, kk;
370	int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */
371	uint32_t idxL, idxR;
372	uint32_t numPdGainsUsed = 0;
373	/*
374	 * If desired to support -ve power levels in future, just
375	 * change pwr_I_0 to signed 5-bits.
376	 */
377	int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
378	/* to accommodate -ve power levels later on. */
379	int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
380	/* to accommodate -ve power levels later on */
381	uint16_t numVpd = 0;
382	uint16_t Vpd_step;
383	int16_t tmpVal ;
384	uint32_t sizeCurrVpdTable, maxIndex, tgtIndex;
385
386	/* Get upper lower index */
387	GetLowerUpperIndex(channel, pRawDataset->pChannels,
388				 pRawDataset->numChannels, &(idxL), &(idxR));
389
390	for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
391		jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
392		/* work backwards 'cause highest pdGain for lowest power */
393		numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd;
394		if (numVpd > 0) {
395			pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain;
396			Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0];
397			if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) {
398				Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0];
399			}
400			Pmin_t2[numPdGainsUsed] = (int16_t)
401				(Pmin_t2[numPdGainsUsed] / 2);
402			Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1];
403			if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1])
404				Pmax_t2[numPdGainsUsed] =
405					pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1];
406			Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2);
407			ar2316FillVpdTable(
408					   numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
409					   &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]),
410					   &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L
411					   );
412			ar2316FillVpdTable(
413					   numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
414					   &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]),
415					   &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R
416					   );
417			for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) {
418				VpdTable_I[numPdGainsUsed][kk] =
419					interpolate_signed(
420							   channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR],
421							   (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]);
422			}
423			/* fill VpdTable_I for this pdGain */
424			numPdGainsUsed++;
425		}
426		/* if this pdGain is used */
427	}
428
429	*pMinCalPower = Pmin_t2[0];
430	kk = 0; /* index for the final table */
431	for (ii = 0; ii < numPdGainsUsed; ii++) {
432		if (ii == (numPdGainsUsed - 1))
433			pPdGainBoundaries[ii] = Pmax_t2[ii] +
434				PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB;
435		else
436			pPdGainBoundaries[ii] = (uint16_t)
437				((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 );
438		if (pPdGainBoundaries[ii] > 63) {
439			HALDEBUG(ah, HAL_DEBUG_ANY,
440			    "%s: clamp pPdGainBoundaries[%d] %d\n",
441			    __func__, ii, pPdGainBoundaries[ii]);/*XXX*/
442			pPdGainBoundaries[ii] = 63;
443		}
444
445		/* Find starting index for this pdGain */
446		if (ii == 0)
447			ss = 0; /* for the first pdGain, start from index 0 */
448		else
449			ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) -
450				pdGainOverlap_t2;
451		Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]);
452		Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
453		/*
454		 *-ve ss indicates need to extrapolate data below for this pdGain
455		 */
456		while (ss < 0) {
457			tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step);
458			pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal);
459			ss++;
460		}
461
462		sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii];
463		tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii];
464		maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
465
466		while (ss < (int16_t)maxIndex)
467			pPDADCValues[kk++] = VpdTable_I[ii][ss++];
468
469		Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] -
470				       VpdTable_I[ii][sizeCurrVpdTable-2]);
471		Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
472		/*
473		 * for last gain, pdGainBoundary == Pmax_t2, so will
474		 * have to extrapolate
475		 */
476		if (tgtIndex > maxIndex) {	/* need to extrapolate above */
477			while(ss < (int16_t)tgtIndex) {
478				tmpVal = (uint16_t)
479					(VpdTable_I[ii][sizeCurrVpdTable-1] +
480					 (ss-maxIndex)*Vpd_step);
481				pPDADCValues[kk++] = (tmpVal > 127) ?
482					127 : tmpVal;
483				ss++;
484			}
485		}				/* extrapolated above */
486	}					/* for all pdGainUsed */
487
488	while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) {
489		pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1];
490		ii++;
491	}
492	while (kk < 128) {
493		pPDADCValues[kk] = pPDADCValues[kk-1];
494		kk++;
495	}
496
497	return numPdGainsUsed;
498#undef VpdTable_L
499#undef VpdTable_R
500#undef VpdTable_I
501}
502
503static HAL_BOOL
504ar2316SetPowerTable(struct ath_hal *ah,
505	int16_t *minPower, int16_t *maxPower,
506	const struct ieee80211_channel *chan,
507	uint16_t *rfXpdGain)
508{
509	struct ath_hal_5212 *ahp = AH5212(ah);
510	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
511	const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL;
512	uint16_t pdGainOverlap_t2;
513	int16_t minCalPower2316_t2;
514	uint16_t *pdadcValues = ahp->ah_pcdacTable;
515	uint16_t gainBoundaries[4];
516	uint32_t reg32, regoffset;
517	int i, numPdGainsUsed;
518#ifndef AH_USE_INIPDGAIN
519	uint32_t tpcrg1;
520#endif
521
522	HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
523	    __func__, chan->ic_freq, chan->ic_flags);
524
525	if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan))
526		pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
527	else if (IEEE80211_IS_CHAN_B(chan))
528		pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
529	else {
530		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: illegal mode\n", __func__);
531		return AH_FALSE;
532	}
533
534	pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5),
535					  AR_PHY_TPCRG5_PD_GAIN_OVERLAP);
536
537	numPdGainsUsed = ar2316getGainBoundariesAndPdadcsForPowers(ah,
538		chan->channel, pRawDataset, pdGainOverlap_t2,
539		&minCalPower2316_t2,gainBoundaries, rfXpdGain, pdadcValues);
540	HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
541
542#ifdef AH_USE_INIPDGAIN
543	/*
544	 * Use pd_gains curve from eeprom; Atheros always uses
545	 * the default curve from the ini file but some vendors
546	 * (e.g. Zcomax) want to override this curve and not
547	 * honoring their settings results in tx power 5dBm low.
548	 */
549	OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
550			 (pRawDataset->pDataPerChannel[0].numPdGains - 1));
551#else
552	tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
553	tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
554		  | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
555	switch (numPdGainsUsed) {
556	case 3:
557		tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3;
558		tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3);
559		/* fall thru... */
560	case 2:
561		tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2;
562		tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2);
563		/* fall thru... */
564	case 1:
565		tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1;
566		tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1);
567		break;
568	}
569#ifdef AH_DEBUG
570	if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1))
571		HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default "
572		    "pd_gains (default 0x%x, calculated 0x%x)\n",
573		    __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
574#endif
575	OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
576#endif
577
578	/*
579	 * Note the pdadc table may not start at 0 dBm power, could be
580	 * negative or greater than 0.  Need to offset the power
581	 * values by the amount of minPower for griffin
582	 */
583	if (minCalPower2316_t2 != 0)
584		ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2316_t2);
585	else
586		ahp->ah_txPowerIndexOffset = 0;
587
588	/* Finally, write the power values into the baseband power table */
589	regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */
590	for (i = 0; i < 32; i++) {
591		reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0)  |
592			((pdadcValues[4*i + 1] & 0xFF) << 8)  |
593			((pdadcValues[4*i + 2] & 0xFF) << 16) |
594			((pdadcValues[4*i + 3] & 0xFF) << 24) ;
595		OS_REG_WRITE(ah, regoffset, reg32);
596		regoffset += 4;
597	}
598
599	OS_REG_WRITE(ah, AR_PHY_TPCRG5,
600		     SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
601		     SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
602		     SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
603		     SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
604		     SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
605
606	return AH_TRUE;
607}
608
609static int16_t
610ar2316GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data)
611{
612	uint32_t ii,jj;
613	uint16_t Pmin=0,numVpd;
614
615	for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
616		jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
617		/* work backwards 'cause highest pdGain for lowest power */
618		numVpd = data->pDataPerPDGain[jj].numVpd;
619		if (numVpd > 0) {
620			Pmin = data->pDataPerPDGain[jj].pwr_t4[0];
621			return(Pmin);
622		}
623	}
624	return(Pmin);
625}
626
627static int16_t
628ar2316GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data)
629{
630	uint32_t ii;
631	uint16_t Pmax=0,numVpd;
632
633	for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
634		/* work forwards cuase lowest pdGain for highest power */
635		numVpd = data->pDataPerPDGain[ii].numVpd;
636		if (numVpd > 0) {
637			Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1];
638			return(Pmax);
639		}
640	}
641	return(Pmax);
642}
643
644static HAL_BOOL
645ar2316GetChannelMaxMinPower(struct ath_hal *ah,
646	const struct ieee80211_channel *chan,
647	int16_t *maxPow, int16_t *minPow)
648{
649	uint16_t freq = chan->ic_freq;		/* NB: never mapped */
650	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
651	const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL;
652	const RAW_DATA_PER_CHANNEL_2316 *data=AH_NULL;
653	uint16_t numChannels;
654	int totalD,totalF, totalMin,last, i;
655
656	*maxPow = 0;
657
658	if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan))
659		pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
660	else if (IEEE80211_IS_CHAN_B(chan))
661		pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
662	else
663		return(AH_FALSE);
664
665	numChannels = pRawDataset->numChannels;
666	data = pRawDataset->pDataPerChannel;
667
668	/* Make sure the channel is in the range of the TP values
669	 *  (freq piers)
670	 */
671	if (numChannels < 1)
672		return(AH_FALSE);
673
674	if ((freq < data[0].channelValue) ||
675	    (freq > data[numChannels-1].channelValue)) {
676		if (freq < data[0].channelValue) {
677			*maxPow = ar2316GetMaxPower(ah, &data[0]);
678			*minPow = ar2316GetMinPower(ah, &data[0]);
679			return(AH_TRUE);
680		} else {
681			*maxPow = ar2316GetMaxPower(ah, &data[numChannels - 1]);
682			*minPow = ar2316GetMinPower(ah, &data[numChannels - 1]);
683			return(AH_TRUE);
684		}
685	}
686
687	/* Linearly interpolate the power value now */
688	for (last=0,i=0; (i<numChannels) && (freq > data[i].channelValue);
689	     last = i++);
690	totalD = data[i].channelValue - data[last].channelValue;
691	if (totalD > 0) {
692		totalF = ar2316GetMaxPower(ah, &data[i]) - ar2316GetMaxPower(ah, &data[last]);
693		*maxPow = (int8_t) ((totalF*(freq-data[last].channelValue) +
694				     ar2316GetMaxPower(ah, &data[last])*totalD)/totalD);
695		totalMin = ar2316GetMinPower(ah, &data[i]) - ar2316GetMinPower(ah, &data[last]);
696		*minPow = (int8_t) ((totalMin*(freq-data[last].channelValue) +
697				     ar2316GetMinPower(ah, &data[last])*totalD)/totalD);
698		return(AH_TRUE);
699	} else {
700		if (freq == data[i].channelValue) {
701			*maxPow = ar2316GetMaxPower(ah, &data[i]);
702			*minPow = ar2316GetMinPower(ah, &data[i]);
703			return(AH_TRUE);
704		} else
705			return(AH_FALSE);
706	}
707}
708
709/*
710 * Free memory for analog bank scratch buffers
711 */
712static void
713ar2316RfDetach(struct ath_hal *ah)
714{
715	struct ath_hal_5212 *ahp = AH5212(ah);
716
717	HALASSERT(ahp->ah_rfHal != AH_NULL);
718	ath_hal_free(ahp->ah_rfHal);
719	ahp->ah_rfHal = AH_NULL;
720}
721
722/*
723 * Allocate memory for private state.
724 * Scratch Buffer will be reinitialized every reset so no need to zero now
725 */
726static HAL_BOOL
727ar2316RfAttach(struct ath_hal *ah, HAL_STATUS *status)
728{
729	struct ath_hal_5212 *ahp = AH5212(ah);
730	struct ar2316State *priv;
731
732	HALASSERT(ah->ah_magic == AR5212_MAGIC);
733
734	HALASSERT(ahp->ah_rfHal == AH_NULL);
735	priv = ath_hal_malloc(sizeof(struct ar2316State));
736	if (priv == AH_NULL) {
737		HALDEBUG(ah, HAL_DEBUG_ANY,
738		    "%s: cannot allocate private state\n", __func__);
739		*status = HAL_ENOMEM;		/* XXX */
740		return AH_FALSE;
741	}
742	priv->base.rfDetach		= ar2316RfDetach;
743	priv->base.writeRegs		= ar2316WriteRegs;
744	priv->base.getRfBank		= ar2316GetRfBank;
745	priv->base.setChannel		= ar2316SetChannel;
746	priv->base.setRfRegs		= ar2316SetRfRegs;
747	priv->base.setPowerTable	= ar2316SetPowerTable;
748	priv->base.getChannelMaxMinPower = ar2316GetChannelMaxMinPower;
749	priv->base.getNfAdjust		= ar5212GetNfAdjust;
750
751	ahp->ah_pcdacTable = priv->pcdacTable;
752	ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
753	ahp->ah_rfHal = &priv->base;
754
755	ahp->ah_cwCalRequire = AH_TRUE;		/* force initial cal */
756
757	return AH_TRUE;
758}
759
760static HAL_BOOL
761ar2316Probe(struct ath_hal *ah)
762{
763	return IS_2316(ah);
764}
765AH_RF(RF2316, ar2316Probe, ar2316RfAttach);
766