11e10b93dSalc /*
21e10b93dSalc  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
31e10b93dSalc  * Copyright (c) 2002-2008 Atheros Communications, Inc.
41e10b93dSalc  *
51e10b93dSalc  * Permission to use, copy, modify, and/or distribute this software for any
61e10b93dSalc  * purpose with or without fee is hereby granted, provided that the above
71e10b93dSalc  * copyright notice and this permission notice appear in all copies.
81e10b93dSalc  *
91e10b93dSalc  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101e10b93dSalc  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111e10b93dSalc  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121e10b93dSalc  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131e10b93dSalc  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141e10b93dSalc  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151e10b93dSalc  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161e10b93dSalc  *
17*705c466cSmartin  * $Id: ar2425.c,v 1.4 2013/09/12 12:05:52 martin Exp $
181e10b93dSalc  */
191e10b93dSalc #include "opt_ah.h"
201e10b93dSalc 
211e10b93dSalc #include "ah.h"
221e10b93dSalc #include "ah_internal.h"
231e10b93dSalc 
241e10b93dSalc #include "ar5212/ar5212.h"
251e10b93dSalc #include "ar5212/ar5212reg.h"
261e10b93dSalc #include "ar5212/ar5212phy.h"
271e10b93dSalc 
281e10b93dSalc #include "ah_eeprom_v3.h"
291e10b93dSalc 
301e10b93dSalc #define AH_5212_2425
311e10b93dSalc #define AH_5212_2417
321e10b93dSalc #include "ar5212/ar5212.ini"
331e10b93dSalc 
341e10b93dSalc #define	N(a)	(sizeof(a)/sizeof(a[0]))
351e10b93dSalc 
361e10b93dSalc struct ar2425State {
371e10b93dSalc 	RF_HAL_FUNCS	base;		/* public state, must be first */
381e10b93dSalc 	uint16_t	pcdacTable[PWR_TABLE_SIZE_2413];
391e10b93dSalc 
401e10b93dSalc 	uint32_t	Bank1Data[N(ar5212Bank1_2425)];
411e10b93dSalc 	uint32_t	Bank2Data[N(ar5212Bank2_2425)];
421e10b93dSalc 	uint32_t	Bank3Data[N(ar5212Bank3_2425)];
431e10b93dSalc 	uint32_t	Bank6Data[N(ar5212Bank6_2425)];	/* 2417 is same size */
441e10b93dSalc 	uint32_t	Bank7Data[N(ar5212Bank7_2425)];
451e10b93dSalc };
461e10b93dSalc #define	AR2425(ah)	((struct ar2425State *) AH5212(ah)->ah_rfHal)
471e10b93dSalc 
481e10b93dSalc extern	void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
491e10b93dSalc 		uint32_t numBits, uint32_t firstBit, uint32_t column);
501e10b93dSalc 
511e10b93dSalc static void
ar2425WriteRegs(struct ath_hal * ah,u_int modesIndex,u_int freqIndex,int writes)521e10b93dSalc ar2425WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
531e10b93dSalc 	int writes)
541e10b93dSalc {
551e10b93dSalc 	HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2425, modesIndex, writes);
561e10b93dSalc 	HAL_INI_WRITE_ARRAY(ah, ar5212Common_2425, 1, writes);
571e10b93dSalc 	HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2425, freqIndex, writes);
581e10b93dSalc #if 0
591e10b93dSalc 	/*
601e10b93dSalc 	 * for SWAN similar to Condor
611e10b93dSalc 	 * Bit 0 enables link to go to L1 when MAC goes to sleep.
621e10b93dSalc 	 * Bit 3 enables the loop back the link down to reset.
631e10b93dSalc 	 */
6461a10f9cSjmcneill 	if (AH_PRIVATE(ah)->ah_ispcie && && ath_hal_pcieL1SKPEnable) {
651e10b93dSalc 		OS_REG_WRITE(ah, AR_PCIE_PMC,
661e10b93dSalc 		    AR_PCIE_PMC_ENA_L1 | AR_PCIE_PMC_ENA_RESET);
671e10b93dSalc 	}
681e10b93dSalc 	/*
691e10b93dSalc 	 * for Standby issue in Swan/Condor.
701e10b93dSalc 	 * Bit 9 (MAC_WOW_PWR_STATE_MASK_D2)to be set to avoid skips
711e10b93dSalc 	 *	before last Training Sequence 2 (TS2)
721e10b93dSalc 	 * Bit 8 (MAC_WOW_PWR_STATE_MASK_D1)to be unset to assert
731e10b93dSalc 	 *	Power Reset along with PCI Reset
741e10b93dSalc 	 */
751e10b93dSalc 	OS_REG_SET_BIT(ah, AR_PCIE_PMC, MAC_WOW_PWR_STATE_MASK_D2);
761e10b93dSalc #endif
771e10b93dSalc }
781e10b93dSalc 
791e10b93dSalc /*
801e10b93dSalc  * Take the MHz channel value and set the Channel value
811e10b93dSalc  *
821e10b93dSalc  * ASSUMES: Writes enabled to analog bus
831e10b93dSalc  */
841e10b93dSalc static HAL_BOOL
ar2425SetChannel(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * chan)851e10b93dSalc ar2425SetChannel(struct ath_hal *ah,  HAL_CHANNEL_INTERNAL *chan)
861e10b93dSalc {
871e10b93dSalc 	uint32_t channelSel  = 0;
881e10b93dSalc 	uint32_t bModeSynth  = 0;
891e10b93dSalc 	uint32_t aModeRefSel = 0;
901e10b93dSalc 	uint32_t reg32       = 0;
911e10b93dSalc 	uint16_t freq;
921e10b93dSalc 
931e10b93dSalc 	OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel);
941e10b93dSalc 
951e10b93dSalc 	if (chan->channel < 4800) {
961e10b93dSalc 		uint32_t txctl;
971e10b93dSalc 
981e10b93dSalc         channelSel = chan->channel - 2272;
991e10b93dSalc         channelSel = ath_hal_reverseBits(channelSel, 8);
1001e10b93dSalc 
1011e10b93dSalc 		txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
1021e10b93dSalc         if (chan->channel == 2484) {
1031e10b93dSalc 			// Enable channel spreading for channel 14
1041e10b93dSalc 			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
1051e10b93dSalc 				txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
1061e10b93dSalc 		} else {
1071e10b93dSalc 			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
1081e10b93dSalc 				txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
1091e10b93dSalc 		}
1101e10b93dSalc 
1111e10b93dSalc 	} else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) {
1121e10b93dSalc 		freq = chan->channel - 2; /* Align to even 5MHz raster */
1131e10b93dSalc 		channelSel = ath_hal_reverseBits(
1141e10b93dSalc 			(uint32_t)(((freq - 4800)*10)/25 + 1), 8);
1151e10b93dSalc             	aModeRefSel = ath_hal_reverseBits(0, 2);
1161e10b93dSalc 	} else if ((chan->channel % 20) == 0 && chan->channel >= 5120) {
1171e10b93dSalc 		channelSel = ath_hal_reverseBits(
1181e10b93dSalc 			((chan->channel - 4800) / 20 << 2), 8);
1191e10b93dSalc 		aModeRefSel = ath_hal_reverseBits(1, 2);
1201e10b93dSalc 	} else if ((chan->channel % 10) == 0) {
1211e10b93dSalc 		channelSel = ath_hal_reverseBits(
1221e10b93dSalc 			((chan->channel - 4800) / 10 << 1), 8);
1231e10b93dSalc 		aModeRefSel = ath_hal_reverseBits(1, 2);
1241e10b93dSalc 	} else if ((chan->channel % 5) == 0) {
1251e10b93dSalc 		channelSel = ath_hal_reverseBits(
1261e10b93dSalc 			(chan->channel - 4800) / 5, 8);
1271e10b93dSalc 		aModeRefSel = ath_hal_reverseBits(1, 2);
1281e10b93dSalc 	} else {
1291e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
1301e10b93dSalc 		    __func__, chan->channel);
1311e10b93dSalc 		return AH_FALSE;
1321e10b93dSalc 	}
1331e10b93dSalc 
1341e10b93dSalc 	reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
1351e10b93dSalc 			(1 << 12) | 0x1;
1361e10b93dSalc 	OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
1371e10b93dSalc 
1381e10b93dSalc 	reg32 >>= 8;
1391e10b93dSalc 	OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
1401e10b93dSalc 
1411e10b93dSalc 	AH_PRIVATE(ah)->ah_curchan = chan;
1421e10b93dSalc 	return AH_TRUE;
1431e10b93dSalc }
1441e10b93dSalc 
1451e10b93dSalc /*
1461e10b93dSalc  * Reads EEPROM header info from device structure and programs
1471e10b93dSalc  * all rf registers
1481e10b93dSalc  *
1491e10b93dSalc  * REQUIRES: Access to the analog rf device
1501e10b93dSalc  */
1511e10b93dSalc static HAL_BOOL
ar2425SetRfRegs(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * chan,uint16_t modesIndex,uint16_t * rfXpdGain)1521e10b93dSalc ar2425SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain)
1531e10b93dSalc {
1541e10b93dSalc #define	RF_BANK_SETUP(_priv, _ix, _col) do {				    \
1551e10b93dSalc 	int i;								    \
1561e10b93dSalc 	for (i = 0; i < N(ar5212Bank##_ix##_2425); i++)			    \
1571e10b93dSalc 		(_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2425[i][_col];\
1581e10b93dSalc } while (0)
1591e10b93dSalc 	struct ath_hal_5212 *ahp = AH5212(ah);
1601e10b93dSalc 	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1611e10b93dSalc 	struct ar2425State *priv = AR2425(ah);
1621e10b93dSalc 	uint16_t ob2GHz = 0, db2GHz = 0;
1631e10b93dSalc 	int regWrites = 0;
1641e10b93dSalc 
1651e10b93dSalc 	HALDEBUG(ah, HAL_DEBUG_RFPARAM,
1661e10b93dSalc 	    "==>%s:chan 0x%x flag 0x%x modesIndex 0x%x\n",
1671e10b93dSalc 	    __func__, chan->channel, chan->channelFlags, modesIndex);
1681e10b93dSalc 
1691e10b93dSalc 	HALASSERT(priv);
1701e10b93dSalc 
1711e10b93dSalc 	/* Setup rf parameters */
1721e10b93dSalc 	switch (chan->channelFlags & CHANNEL_ALL) {
1731e10b93dSalc 	case CHANNEL_B:
1741e10b93dSalc 		ob2GHz = ee->ee_obFor24;
1751e10b93dSalc 		db2GHz = ee->ee_dbFor24;
1761e10b93dSalc 		break;
1771e10b93dSalc 	case CHANNEL_G:
1781e10b93dSalc 	case CHANNEL_108G:
1791e10b93dSalc 		ob2GHz = ee->ee_obFor24g;
1801e10b93dSalc 		db2GHz = ee->ee_dbFor24g;
1811e10b93dSalc 		break;
1821e10b93dSalc 	default:
1831e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
1841e10b93dSalc 			__func__, chan->channelFlags);
1851e10b93dSalc 		return AH_FALSE;
1861e10b93dSalc 	}
1871e10b93dSalc 
1881e10b93dSalc 	/* Bank 1 Write */
1891e10b93dSalc 	RF_BANK_SETUP(priv, 1, 1);
1901e10b93dSalc 
1911e10b93dSalc 	/* Bank 2 Write */
1921e10b93dSalc 	RF_BANK_SETUP(priv, 2, modesIndex);
1931e10b93dSalc 
1941e10b93dSalc 	/* Bank 3 Write */
1951e10b93dSalc 	RF_BANK_SETUP(priv, 3, modesIndex);
1961e10b93dSalc 
1971e10b93dSalc 	/* Bank 6 Write */
1981e10b93dSalc 	RF_BANK_SETUP(priv, 6, modesIndex);
1991e10b93dSalc 
2001e10b93dSalc         ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 193, 0);
2011e10b93dSalc         ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 190, 0);
2021e10b93dSalc 
2031e10b93dSalc 	/* Bank 7 Setup */
2041e10b93dSalc 	RF_BANK_SETUP(priv, 7, modesIndex);
2051e10b93dSalc 
2061e10b93dSalc 	/* Write Analog registers */
2071e10b93dSalc 	HAL_INI_WRITE_BANK(ah, ar5212Bank1_2425, priv->Bank1Data, regWrites);
2081e10b93dSalc 	HAL_INI_WRITE_BANK(ah, ar5212Bank2_2425, priv->Bank2Data, regWrites);
2091e10b93dSalc 	HAL_INI_WRITE_BANK(ah, ar5212Bank3_2425, priv->Bank3Data, regWrites);
2101e10b93dSalc 	if (IS_2417(ah)) {
2111e10b93dSalc 		HALASSERT(N(ar5212Bank6_2425) == N(ar5212Bank6_2417));
2121e10b93dSalc 		HAL_INI_WRITE_BANK(ah, ar5212Bank6_2417, priv->Bank6Data,
2131e10b93dSalc 		    regWrites);
2141e10b93dSalc 	} else
2151e10b93dSalc 		HAL_INI_WRITE_BANK(ah, ar5212Bank6_2425, priv->Bank6Data,
2161e10b93dSalc 		    regWrites);
2171e10b93dSalc 	HAL_INI_WRITE_BANK(ah, ar5212Bank7_2425, priv->Bank7Data, regWrites);
2181e10b93dSalc 
2191e10b93dSalc 	/* Now that we have reprogrammed rfgain value, clear the flag. */
2201e10b93dSalc 	ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
2211e10b93dSalc 
2221e10b93dSalc 	HALDEBUG(ah, HAL_DEBUG_RFPARAM, "<==%s\n", __func__);
2231e10b93dSalc 	return AH_TRUE;
2241e10b93dSalc #undef	RF_BANK_SETUP
2251e10b93dSalc }
2261e10b93dSalc 
2271e10b93dSalc /*
2281e10b93dSalc  * Return a reference to the requested RF Bank.
2291e10b93dSalc  */
2301e10b93dSalc static uint32_t *
ar2425GetRfBank(struct ath_hal * ah,int bank)2311e10b93dSalc ar2425GetRfBank(struct ath_hal *ah, int bank)
2321e10b93dSalc {
2331e10b93dSalc 	struct ar2425State *priv = AR2425(ah);
2341e10b93dSalc 
2351e10b93dSalc 	HALASSERT(priv != AH_NULL);
2361e10b93dSalc 	switch (bank) {
2371e10b93dSalc 	case 1: return priv->Bank1Data;
2381e10b93dSalc 	case 2: return priv->Bank2Data;
2391e10b93dSalc 	case 3: return priv->Bank3Data;
2401e10b93dSalc 	case 6: return priv->Bank6Data;
2411e10b93dSalc 	case 7: return priv->Bank7Data;
2421e10b93dSalc 	}
2431e10b93dSalc 	HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
2441e10b93dSalc 	    __func__, bank);
2451e10b93dSalc 	return AH_NULL;
2461e10b93dSalc }
2471e10b93dSalc 
2481e10b93dSalc /*
2491e10b93dSalc  * Return indices surrounding the value in sorted integer lists.
2501e10b93dSalc  *
2511e10b93dSalc  * NB: the input list is assumed to be sorted in ascending order
2521e10b93dSalc  */
2531e10b93dSalc static void
GetLowerUpperIndex(int16_t v,const uint16_t * lp,uint16_t listSize,uint32_t * vlo,uint32_t * vhi)2541e10b93dSalc GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize,
2551e10b93dSalc                           uint32_t *vlo, uint32_t *vhi)
2561e10b93dSalc {
2571e10b93dSalc 	int16_t target = v;
2581e10b93dSalc 	const uint16_t *ep = lp+listSize;
2591e10b93dSalc 	const uint16_t *tp;
2601e10b93dSalc 
2611e10b93dSalc 	/*
2621e10b93dSalc 	 * Check first and last elements for out-of-bounds conditions.
2631e10b93dSalc 	 */
2641e10b93dSalc 	if (target < lp[0]) {
2651e10b93dSalc 		*vlo = *vhi = 0;
2661e10b93dSalc 		return;
2671e10b93dSalc 	}
2681e10b93dSalc 	if (target >= ep[-1]) {
2691e10b93dSalc 		*vlo = *vhi = listSize - 1;
2701e10b93dSalc 		return;
2711e10b93dSalc 	}
2721e10b93dSalc 
2731e10b93dSalc 	/* look for value being near or between 2 values in list */
2741e10b93dSalc 	for (tp = lp; tp < ep; tp++) {
2751e10b93dSalc 		/*
2761e10b93dSalc 		 * If value is close to the current value of the list
2771e10b93dSalc 		 * then target is not between values, it is one of the values
2781e10b93dSalc 		 */
2791e10b93dSalc 		if (*tp == target) {
2801e10b93dSalc 			*vlo = *vhi = tp - (const uint16_t *) lp;
2811e10b93dSalc 			return;
2821e10b93dSalc 		}
2831e10b93dSalc 		/*
2841e10b93dSalc 		 * Look for value being between current value and next value
2851e10b93dSalc 		 * if so return these 2 values
2861e10b93dSalc 		 */
2871e10b93dSalc 		if (target < tp[1]) {
2881e10b93dSalc 			*vlo = tp - (const uint16_t *) lp;
2891e10b93dSalc 			*vhi = *vlo + 1;
2901e10b93dSalc 			return;
2911e10b93dSalc 		}
2921e10b93dSalc 	}
2931e10b93dSalc }
2941e10b93dSalc 
2951e10b93dSalc /*
2961e10b93dSalc  * Fill the Vpdlist for indices Pmax-Pmin
2971e10b93dSalc  */
2981e10b93dSalc static HAL_BOOL
ar2425FillVpdTable(uint32_t pdGainIdx,int16_t Pmin,int16_t Pmax,const int16_t * pwrList,const uint16_t * VpdList,uint16_t numIntercepts,uint16_t retVpdList[][64])2991e10b93dSalc ar2425FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t  Pmax,
3001e10b93dSalc 		   const int16_t *pwrList, const uint16_t *VpdList,
3011e10b93dSalc 		   uint16_t numIntercepts,
3021e10b93dSalc 		   uint16_t retVpdList[][64])
3031e10b93dSalc {
304*705c466cSmartin 	uint16_t ii, kk;
3051e10b93dSalc 	int16_t currPwr = (int16_t)(2*Pmin);
3061e10b93dSalc 	/* since Pmin is pwr*2 and pwrList is 4*pwr */
3077c9a97abSmrg 	uint32_t  idxL = 0, idxR = 0;
3081e10b93dSalc 
3091e10b93dSalc 	ii = 0;
3101e10b93dSalc 
3111e10b93dSalc 	if (numIntercepts < 2)
3121e10b93dSalc 		return AH_FALSE;
3131e10b93dSalc 
3141e10b93dSalc 	while (ii <= (uint16_t)(Pmax - Pmin)) {
3151e10b93dSalc 		GetLowerUpperIndex(currPwr, (const uint16_t *) pwrList,
3161e10b93dSalc 				   numIntercepts, &(idxL), &(idxR));
3171e10b93dSalc 		if (idxR < 1)
3181e10b93dSalc 			idxR = 1;			/* extrapolate below */
3191e10b93dSalc 		if (idxL == (uint32_t)(numIntercepts - 1))
3201e10b93dSalc 			idxL = numIntercepts - 2;	/* extrapolate above */
3211e10b93dSalc 		if (pwrList[idxL] == pwrList[idxR])
3221e10b93dSalc 			kk = VpdList[idxL];
3231e10b93dSalc 		else
3241e10b93dSalc 			kk = (uint16_t)
3251e10b93dSalc 				(((currPwr - pwrList[idxL])*VpdList[idxR]+
3261e10b93dSalc 				  (pwrList[idxR] - currPwr)*VpdList[idxL])/
3271e10b93dSalc 				 (pwrList[idxR] - pwrList[idxL]));
3281e10b93dSalc 		retVpdList[pdGainIdx][ii] = kk;
3291e10b93dSalc 		ii++;
3301e10b93dSalc 		currPwr += 2;				/* half dB steps */
3311e10b93dSalc 	}
3321e10b93dSalc 
3331e10b93dSalc 	return AH_TRUE;
3341e10b93dSalc }
3351e10b93dSalc 
3361e10b93dSalc /*
3371e10b93dSalc  * Returns interpolated or the scaled up interpolated value
3381e10b93dSalc  */
3391e10b93dSalc static int16_t
interpolate_signed(uint16_t target,uint16_t srcLeft,uint16_t srcRight,int16_t targetLeft,int16_t targetRight)3401e10b93dSalc interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
3411e10b93dSalc 	int16_t targetLeft, int16_t targetRight)
3421e10b93dSalc {
3431e10b93dSalc 	int16_t rv;
3441e10b93dSalc 
3451e10b93dSalc 	if (srcRight != srcLeft) {
3461e10b93dSalc 		rv = ((target - srcLeft)*targetRight +
3471e10b93dSalc 		      (srcRight - target)*targetLeft) / (srcRight - srcLeft);
3481e10b93dSalc 	} else {
3491e10b93dSalc 		rv = targetLeft;
3501e10b93dSalc 	}
3511e10b93dSalc 	return rv;
3521e10b93dSalc }
3531e10b93dSalc 
3541e10b93dSalc /*
3551e10b93dSalc  * Uses the data points read from EEPROM to reconstruct the pdadc power table
3561e10b93dSalc  * Called by ar2425SetPowerTable()
3571e10b93dSalc  */
3581e10b93dSalc static void
ar2425getGainBoundariesAndPdadcsForPowers(struct ath_hal * ah,uint16_t channel,const RAW_DATA_STRUCT_2413 * pRawDataset,uint16_t pdGainOverlap_t2,int16_t * pMinCalPower,uint16_t pPdGainBoundaries[],uint16_t pPdGainValues[],uint16_t pPDADCValues[])3591e10b93dSalc ar2425getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel,
3601e10b93dSalc 		const RAW_DATA_STRUCT_2413 *pRawDataset,
3611e10b93dSalc 		uint16_t pdGainOverlap_t2,
3621e10b93dSalc 		int16_t  *pMinCalPower, uint16_t pPdGainBoundaries[],
3631e10b93dSalc 		uint16_t pPdGainValues[], uint16_t pPDADCValues[])
3641e10b93dSalc {
3651e10b93dSalc     /* Note the items statically allocated below are to reduce stack usage */
3661e10b93dSalc 	uint32_t ii, jj, kk;
3671e10b93dSalc 	int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */
3687c9a97abSmrg 	uint32_t idxL = 0, idxR = 0;
3691e10b93dSalc 	uint32_t numPdGainsUsed = 0;
3701e10b93dSalc         static uint16_t VpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL][MAX_PWR_RANGE_IN_HALF_DB];
3711e10b93dSalc 	/* filled out Vpd table for all pdGains (chanL) */
3721e10b93dSalc         static uint16_t VpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL][MAX_PWR_RANGE_IN_HALF_DB];
3731e10b93dSalc 	/* filled out Vpd table for all pdGains (chanR) */
3741e10b93dSalc         static uint16_t VpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL][MAX_PWR_RANGE_IN_HALF_DB];
3751e10b93dSalc 	/* filled out Vpd table for all pdGains (interpolated) */
3761e10b93dSalc 	/*
3771e10b93dSalc 	 * If desired to support -ve power levels in future, just
3781e10b93dSalc 	 * change pwr_I_0 to signed 5-bits.
3791e10b93dSalc 	 */
3801e10b93dSalc         static int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
3811e10b93dSalc 	/* to accomodate -ve power levels later on. */
3821e10b93dSalc         static int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
3831e10b93dSalc 	/* to accomodate -ve power levels later on */
3841e10b93dSalc 	uint16_t numVpd = 0;
3851e10b93dSalc 	uint16_t Vpd_step;
3861e10b93dSalc 	int16_t tmpVal ;
3871e10b93dSalc 	uint32_t sizeCurrVpdTable, maxIndex, tgtIndex;
3881e10b93dSalc 
3891e10b93dSalc 	HALDEBUG(ah, HAL_DEBUG_RFPARAM, "==>%s:\n", __func__);
3901e10b93dSalc 
3911e10b93dSalc 	/* Get upper lower index */
3921e10b93dSalc 	GetLowerUpperIndex(channel, pRawDataset->pChannels,
3931e10b93dSalc 				 pRawDataset->numChannels, &(idxL), &(idxR));
3941e10b93dSalc 
3951e10b93dSalc 	for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
3961e10b93dSalc 		jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
3971e10b93dSalc 		/* work backwards 'cause highest pdGain for lowest power */
3981e10b93dSalc 		numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd;
3991e10b93dSalc 		if (numVpd > 0) {
4001e10b93dSalc 			pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain;
4011e10b93dSalc 			Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0];
4021e10b93dSalc 			if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) {
4031e10b93dSalc 				Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0];
4041e10b93dSalc 			}
4051e10b93dSalc 			Pmin_t2[numPdGainsUsed] = (int16_t)
4061e10b93dSalc 				(Pmin_t2[numPdGainsUsed] / 2);
4071e10b93dSalc 			Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1];
4081e10b93dSalc 			if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1])
4091e10b93dSalc 				Pmax_t2[numPdGainsUsed] =
4101e10b93dSalc 					pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1];
4111e10b93dSalc 			Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2);
4121e10b93dSalc 			ar2425FillVpdTable(
4131e10b93dSalc 					   numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
4141e10b93dSalc 					   &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]),
4151e10b93dSalc 					   &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L
4161e10b93dSalc 					   );
4171e10b93dSalc 			ar2425FillVpdTable(
4181e10b93dSalc 					   numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
4191e10b93dSalc 					   &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]),
4201e10b93dSalc 					   &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R
4211e10b93dSalc 					   );
4221e10b93dSalc 			for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) {
4231e10b93dSalc 				VpdTable_I[numPdGainsUsed][kk] =
4241e10b93dSalc 					interpolate_signed(
4251e10b93dSalc 							   channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR],
4261e10b93dSalc 							   (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]);
4271e10b93dSalc 			}
4281e10b93dSalc 			/* fill VpdTable_I for this pdGain */
4291e10b93dSalc 			numPdGainsUsed++;
4301e10b93dSalc 		}
4311e10b93dSalc 		/* if this pdGain is used */
4321e10b93dSalc 	}
4331e10b93dSalc 
4341e10b93dSalc 	*pMinCalPower = Pmin_t2[0];
4351e10b93dSalc 	kk = 0; /* index for the final table */
4361e10b93dSalc 	for (ii = 0; ii < numPdGainsUsed; ii++) {
4371e10b93dSalc 		if (ii == (numPdGainsUsed - 1))
4381e10b93dSalc 			pPdGainBoundaries[ii] = Pmax_t2[ii] +
4391e10b93dSalc 				PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB;
4401e10b93dSalc 		else
4411e10b93dSalc 			pPdGainBoundaries[ii] = (uint16_t)
4421e10b93dSalc 				((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 );
4431e10b93dSalc 
4441e10b93dSalc 		/* Find starting index for this pdGain */
4451e10b93dSalc 		if (ii == 0)
4461e10b93dSalc 			ss = 0; /* for the first pdGain, start from index 0 */
4471e10b93dSalc 		else
4481e10b93dSalc 			ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) -
4491e10b93dSalc 				pdGainOverlap_t2;
4501e10b93dSalc 		Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]);
4511e10b93dSalc 		Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
4521e10b93dSalc 		/*
4531e10b93dSalc 		 *-ve ss indicates need to extrapolate data below for this pdGain
4541e10b93dSalc 		 */
4551e10b93dSalc 		while (ss < 0) {
4561e10b93dSalc 			tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step);
4571e10b93dSalc 			pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal);
4581e10b93dSalc 			ss++;
4591e10b93dSalc 		}
4601e10b93dSalc 
4611e10b93dSalc 		sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii];
4621e10b93dSalc 		tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii];
4631e10b93dSalc 		maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
4641e10b93dSalc 
4651e10b93dSalc 		while (ss < (int16_t)maxIndex)
4661e10b93dSalc 			pPDADCValues[kk++] = VpdTable_I[ii][ss++];
4671e10b93dSalc 
4681e10b93dSalc 		Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] -
4691e10b93dSalc 				       VpdTable_I[ii][sizeCurrVpdTable-2]);
4701e10b93dSalc 		Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
4711e10b93dSalc 		/*
4721e10b93dSalc 		 * for last gain, pdGainBoundary == Pmax_t2, so will
4731e10b93dSalc 		 * have to extrapolate
4741e10b93dSalc 		 */
4751e10b93dSalc 		if (tgtIndex > maxIndex) {	/* need to extrapolate above */
4761e10b93dSalc 			while(ss < (int16_t)tgtIndex) {
4771e10b93dSalc 				tmpVal = (uint16_t)
4781e10b93dSalc 					(VpdTable_I[ii][sizeCurrVpdTable-1] +
4791e10b93dSalc 					 (ss-maxIndex)*Vpd_step);
4801e10b93dSalc 				pPDADCValues[kk++] = (tmpVal > 127) ?
4811e10b93dSalc 					127 : tmpVal;
4821e10b93dSalc 				ss++;
4831e10b93dSalc 			}
4841e10b93dSalc 		}				/* extrapolated above */
4851e10b93dSalc 	}					/* for all pdGainUsed */
4861e10b93dSalc 
4871e10b93dSalc 	while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) {
4881e10b93dSalc 		pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1];
4891e10b93dSalc 		ii++;
4901e10b93dSalc 	}
4911e10b93dSalc 	while (kk < 128) {
4921e10b93dSalc 		pPDADCValues[kk] = pPDADCValues[kk-1];
4931e10b93dSalc 		kk++;
4941e10b93dSalc 	}
4951e10b93dSalc 
4961e10b93dSalc 	HALDEBUG(ah, HAL_DEBUG_RFPARAM, "<==%s\n", __func__);
4971e10b93dSalc }
4981e10b93dSalc 
4991e10b93dSalc 
5001e10b93dSalc /* Same as 2413 set power table */
5011e10b93dSalc static HAL_BOOL
ar2425SetPowerTable(struct ath_hal * ah,int16_t * minPower,int16_t * maxPower,HAL_CHANNEL_INTERNAL * chan,uint16_t * rfXpdGain)5021e10b93dSalc ar2425SetPowerTable(struct ath_hal *ah,
5031e10b93dSalc 	int16_t *minPower, int16_t *maxPower, HAL_CHANNEL_INTERNAL *chan,
5041e10b93dSalc 	uint16_t *rfXpdGain)
5051e10b93dSalc {
5061e10b93dSalc 	struct ath_hal_5212 *ahp = AH5212(ah);
5071e10b93dSalc 	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
5081e10b93dSalc 	const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL;
5091e10b93dSalc 	uint16_t pdGainOverlap_t2;
5101e10b93dSalc 	int16_t minCalPower2413_t2;
5111e10b93dSalc 	uint16_t *pdadcValues = ahp->ah_pcdacTable;
5121e10b93dSalc 	uint16_t gainBoundaries[4];
5131e10b93dSalc 	uint32_t i, reg32, regoffset;
5141e10b93dSalc 
5151e10b93dSalc 	HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s:chan 0x%x flag 0x%x\n",
5161e10b93dSalc 	    __func__, chan->channel,chan->channelFlags);
5171e10b93dSalc 
5181e10b93dSalc 	if (IS_CHAN_G(chan) || IS_CHAN_108G(chan))
5191e10b93dSalc 		pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
5201e10b93dSalc 	else if (IS_CHAN_B(chan))
5211e10b93dSalc 		pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
5221e10b93dSalc 	else {
5231e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s:illegal mode\n", __func__);
5241e10b93dSalc 		return AH_FALSE;
5251e10b93dSalc 	}
5261e10b93dSalc 
5271e10b93dSalc 	pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5),
5281e10b93dSalc 					  AR_PHY_TPCRG5_PD_GAIN_OVERLAP);
5291e10b93dSalc 
5301e10b93dSalc 	ar2425getGainBoundariesAndPdadcsForPowers(ah, chan->channel,
5311e10b93dSalc 		pRawDataset, pdGainOverlap_t2,&minCalPower2413_t2,gainBoundaries,
5321e10b93dSalc 		rfXpdGain, pdadcValues);
5331e10b93dSalc 
5341e10b93dSalc 	OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
5351e10b93dSalc 			 (pRawDataset->pDataPerChannel[0].numPdGains - 1));
5361e10b93dSalc 
5371e10b93dSalc 	/*
5381e10b93dSalc 	 * Note the pdadc table may not start at 0 dBm power, could be
5391e10b93dSalc 	 * negative or greater than 0.  Need to offset the power
5401e10b93dSalc 	 * values by the amount of minPower for griffin
5411e10b93dSalc 	 */
5421e10b93dSalc 	if (minCalPower2413_t2 != 0)
5431e10b93dSalc 		ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2413_t2);
5441e10b93dSalc 	else
5451e10b93dSalc 		ahp->ah_txPowerIndexOffset = 0;
5461e10b93dSalc 
5471e10b93dSalc 	/* Finally, write the power values into the baseband power table */
5481e10b93dSalc 	regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */
5491e10b93dSalc 	for (i = 0; i < 32; i++) {
5501e10b93dSalc 		reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0)  |
5511e10b93dSalc 			((pdadcValues[4*i + 1] & 0xFF) << 8)  |
5521e10b93dSalc 			((pdadcValues[4*i + 2] & 0xFF) << 16) |
5531e10b93dSalc 			((pdadcValues[4*i + 3] & 0xFF) << 24) ;
5541e10b93dSalc 		OS_REG_WRITE(ah, regoffset, reg32);
5551e10b93dSalc 		regoffset += 4;
5561e10b93dSalc 	}
5571e10b93dSalc 
5581e10b93dSalc 	OS_REG_WRITE(ah, AR_PHY_TPCRG5,
5591e10b93dSalc 		     SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
5601e10b93dSalc 		     SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
5611e10b93dSalc 		     SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
5621e10b93dSalc 		     SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
5631e10b93dSalc 		     SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
5641e10b93dSalc 
5651e10b93dSalc 	return AH_TRUE;
5661e10b93dSalc }
5671e10b93dSalc 
5681e10b93dSalc static int16_t
ar2425GetMinPower(struct ath_hal * ah,const RAW_DATA_PER_CHANNEL_2413 * data)5691e10b93dSalc ar2425GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data)
5701e10b93dSalc {
5711e10b93dSalc 	uint32_t ii,jj;
5721e10b93dSalc 	uint16_t Pmin=0,numVpd;
5731e10b93dSalc 
5741e10b93dSalc 	for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
5751e10b93dSalc 		jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
5761e10b93dSalc 		/* work backwards 'cause highest pdGain for lowest power */
5771e10b93dSalc 		numVpd = data->pDataPerPDGain[jj].numVpd;
5781e10b93dSalc 		if (numVpd > 0) {
5791e10b93dSalc 			Pmin = data->pDataPerPDGain[jj].pwr_t4[0];
5801e10b93dSalc 			return(Pmin);
5811e10b93dSalc 		}
5821e10b93dSalc 	}
5831e10b93dSalc 	return(Pmin);
5841e10b93dSalc }
5851e10b93dSalc 
5861e10b93dSalc static int16_t
ar2425GetMaxPower(struct ath_hal * ah,const RAW_DATA_PER_CHANNEL_2413 * data)5871e10b93dSalc ar2425GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data)
5881e10b93dSalc {
5891e10b93dSalc 	uint32_t ii;
5901e10b93dSalc 	uint16_t Pmax=0,numVpd;
5911e10b93dSalc 
5921e10b93dSalc 	for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
5931e10b93dSalc 		/* work forwards cuase lowest pdGain for highest power */
5941e10b93dSalc 		numVpd = data->pDataPerPDGain[ii].numVpd;
5951e10b93dSalc 		if (numVpd > 0) {
5961e10b93dSalc 			Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1];
5971e10b93dSalc 			return(Pmax);
5981e10b93dSalc 		}
5991e10b93dSalc 	}
6001e10b93dSalc 	return(Pmax);
6011e10b93dSalc }
6021e10b93dSalc 
6031e10b93dSalc static
6041e10b93dSalc HAL_BOOL
ar2425GetChannelMaxMinPower(struct ath_hal * ah,HAL_CHANNEL * chan,int16_t * maxPow,int16_t * minPow)6051e10b93dSalc ar2425GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan,
6061e10b93dSalc 				     int16_t *maxPow, int16_t *minPow)
6071e10b93dSalc {
6081e10b93dSalc 	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
6091e10b93dSalc 	const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL;
6101e10b93dSalc 	const RAW_DATA_PER_CHANNEL_2413 *data = AH_NULL;
6111e10b93dSalc 	uint16_t numChannels;
6121e10b93dSalc 	int totalD,totalF, totalMin,last, i;
6131e10b93dSalc 
6141e10b93dSalc 	*maxPow = 0;
6151e10b93dSalc 
6161e10b93dSalc 	if (IS_CHAN_G(chan) || IS_CHAN_108G(chan))
6171e10b93dSalc 		pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
6181e10b93dSalc 	else if (IS_CHAN_B(chan))
6191e10b93dSalc 		pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
6201e10b93dSalc 	else
6211e10b93dSalc 		return(AH_FALSE);
6221e10b93dSalc 
6231e10b93dSalc 	numChannels = pRawDataset->numChannels;
6241e10b93dSalc 	data = pRawDataset->pDataPerChannel;
6251e10b93dSalc 
6261e10b93dSalc 	/* Make sure the channel is in the range of the TP values
6271e10b93dSalc 	 *  (freq piers)
6281e10b93dSalc 	 */
6291e10b93dSalc 	if (numChannels < 1)
6301e10b93dSalc 		return(AH_FALSE);
6311e10b93dSalc 
6321e10b93dSalc 	if ((chan->channel < data[0].channelValue) ||
6331e10b93dSalc 	    (chan->channel > data[numChannels-1].channelValue)) {
6341e10b93dSalc 		if (chan->channel < data[0].channelValue) {
6351e10b93dSalc 			*maxPow = ar2425GetMaxPower(ah, &data[0]);
6361e10b93dSalc 			*minPow = ar2425GetMinPower(ah, &data[0]);
6371e10b93dSalc 			return(AH_TRUE);
6381e10b93dSalc 		} else {
6391e10b93dSalc 			*maxPow = ar2425GetMaxPower(ah, &data[numChannels - 1]);
6401e10b93dSalc 			*minPow = ar2425GetMinPower(ah, &data[numChannels - 1]);
6411e10b93dSalc 			return(AH_TRUE);
6421e10b93dSalc 		}
6431e10b93dSalc 	}
6441e10b93dSalc 
6451e10b93dSalc 	/* Linearly interpolate the power value now */
6461e10b93dSalc 	for (last=0,i=0; (i<numChannels) && (chan->channel > data[i].channelValue);
6471e10b93dSalc 	     last = i++);
6481e10b93dSalc 	totalD = data[i].channelValue - data[last].channelValue;
6491e10b93dSalc 	if (totalD > 0) {
6501e10b93dSalc 		totalF = ar2425GetMaxPower(ah, &data[i]) - ar2425GetMaxPower(ah, &data[last]);
6511e10b93dSalc 		*maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) +
6521e10b93dSalc 				     ar2425GetMaxPower(ah, &data[last])*totalD)/totalD);
6531e10b93dSalc 		totalMin = ar2425GetMinPower(ah, &data[i]) - ar2425GetMinPower(ah, &data[last]);
6541e10b93dSalc 		*minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) +
6551e10b93dSalc 				     ar2425GetMinPower(ah, &data[last])*totalD)/totalD);
6561e10b93dSalc 		return(AH_TRUE);
6571e10b93dSalc 	} else {
6581e10b93dSalc 		if (chan->channel == data[i].channelValue) {
6591e10b93dSalc 			*maxPow = ar2425GetMaxPower(ah, &data[i]);
6601e10b93dSalc 			*minPow = ar2425GetMinPower(ah, &data[i]);
6611e10b93dSalc 			return(AH_TRUE);
6621e10b93dSalc 		} else
6631e10b93dSalc 			return(AH_FALSE);
6641e10b93dSalc 	}
6651e10b93dSalc }
6661e10b93dSalc 
6671e10b93dSalc /*
6681e10b93dSalc  * Free memory for analog bank scratch buffers
6691e10b93dSalc  */
6701e10b93dSalc static void
ar2425RfDetach(struct ath_hal * ah)6711e10b93dSalc ar2425RfDetach(struct ath_hal *ah)
6721e10b93dSalc {
6731e10b93dSalc 	struct ath_hal_5212 *ahp = AH5212(ah);
6741e10b93dSalc 
6751e10b93dSalc 	HALASSERT(ahp->ah_rfHal != AH_NULL);
6761e10b93dSalc 	ath_hal_free(ahp->ah_rfHal);
6771e10b93dSalc 	ahp->ah_rfHal = AH_NULL;
6781e10b93dSalc }
6791e10b93dSalc 
6801e10b93dSalc /*
6811e10b93dSalc  * Allocate memory for analog bank scratch buffers
6821e10b93dSalc  * Scratch Buffer will be reinitialized every reset so no need to zero now
6831e10b93dSalc  */
6841e10b93dSalc static HAL_BOOL
ar2425RfAttach(struct ath_hal * ah,HAL_STATUS * status)6851e10b93dSalc ar2425RfAttach(struct ath_hal *ah, HAL_STATUS *status)
6861e10b93dSalc {
6871e10b93dSalc 	struct ath_hal_5212 *ahp = AH5212(ah);
6881e10b93dSalc 	struct ar2425State *priv;
6891e10b93dSalc 
6901e10b93dSalc 	HALASSERT(ah->ah_magic == AR5212_MAGIC);
6911e10b93dSalc 
6921e10b93dSalc 	HALASSERT(ahp->ah_rfHal == AH_NULL);
6931e10b93dSalc 	priv = ath_hal_malloc(sizeof(struct ar2425State));
6941e10b93dSalc 	if (priv == AH_NULL) {
6951e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY,
6961e10b93dSalc 		    "%s: cannot allocate private state\n", __func__);
6971e10b93dSalc 		*status = HAL_ENOMEM;		/* XXX */
6981e10b93dSalc 		return AH_FALSE;
6991e10b93dSalc 	}
7001e10b93dSalc 	priv->base.rfDetach		= ar2425RfDetach;
7011e10b93dSalc 	priv->base.writeRegs		= ar2425WriteRegs;
7021e10b93dSalc 	priv->base.getRfBank		= ar2425GetRfBank;
7031e10b93dSalc 	priv->base.setChannel		= ar2425SetChannel;
7041e10b93dSalc 	priv->base.setRfRegs		= ar2425SetRfRegs;
7051e10b93dSalc 	priv->base.setPowerTable	= ar2425SetPowerTable;
7061e10b93dSalc 	priv->base.getChannelMaxMinPower = ar2425GetChannelMaxMinPower;
7071e10b93dSalc 	priv->base.getNfAdjust		= ar5212GetNfAdjust;
7081e10b93dSalc 
7091e10b93dSalc 	ahp->ah_pcdacTable = priv->pcdacTable;
7101e10b93dSalc 	ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
7111e10b93dSalc 	ahp->ah_rfHal = &priv->base;
7121e10b93dSalc 
7131e10b93dSalc 	return AH_TRUE;
7141e10b93dSalc }
7151e10b93dSalc 
7161e10b93dSalc static HAL_BOOL
ar2425Probe(struct ath_hal * ah)7171e10b93dSalc ar2425Probe(struct ath_hal *ah)
7181e10b93dSalc {
7191e10b93dSalc 	return IS_2425(ah) || IS_2417(ah);
7201e10b93dSalc }
7211e10b93dSalc AH_RF(RF2425, ar2425Probe, ar2425RfAttach);
722