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*98c00ab4Smrg  * $Id: ah_eeprom_v3.c,v 1.5 2021/04/13 03:27:13 mrg Exp $
181e10b93dSalc  */
191e10b93dSalc #include "opt_ah.h"
201e10b93dSalc 
211e10b93dSalc #include "ah.h"
221e10b93dSalc #include "ah_internal.h"
231e10b93dSalc #include "ah_eeprom_v3.h"
241e10b93dSalc 
251e10b93dSalc static void
getPcdacInterceptsFromPcdacMinMax(HAL_EEPROM * ee,uint16_t pcdacMin,uint16_t pcdacMax,uint16_t * vp)261e10b93dSalc getPcdacInterceptsFromPcdacMinMax(HAL_EEPROM *ee,
271e10b93dSalc 	uint16_t pcdacMin, uint16_t pcdacMax, uint16_t *vp)
281e10b93dSalc {
29a9d4fb0bSalc 	static const uint16_t intercepts3[] =
301e10b93dSalc 		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
31a9d4fb0bSalc 	static const uint16_t intercepts3_2[] =
321e10b93dSalc 		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
331e10b93dSalc 	const uint16_t *ip = ee->ee_version < AR_EEPROM_VER3_2 ?
341e10b93dSalc 		intercepts3 : intercepts3_2;
351e10b93dSalc 	int i;
361e10b93dSalc 
371e10b93dSalc 	/* loop for the percentages in steps or 5 */
381e10b93dSalc 	for (i = 0; i < NUM_INTERCEPTS; i++ )
391e10b93dSalc 		*vp++ = (ip[i] * pcdacMax + (100 - ip[i]) * pcdacMin) / 100;
401e10b93dSalc }
411e10b93dSalc 
421e10b93dSalc /*
431e10b93dSalc  * Get channel value from binary representation held in eeprom
441e10b93dSalc  */
451e10b93dSalc static uint16_t
fbin2freq(HAL_EEPROM * ee,uint16_t fbin)461e10b93dSalc fbin2freq(HAL_EEPROM *ee, uint16_t fbin)
471e10b93dSalc {
481e10b93dSalc 	if (fbin == CHANNEL_UNUSED)	/* reserved value, don't convert */
491e10b93dSalc 		return fbin;
501e10b93dSalc 	return ee->ee_version <= AR_EEPROM_VER3_2 ?
511e10b93dSalc 		(fbin > 62 ? 5100 + 10*62 + 5*(fbin-62) : 5100 + 10*fbin) :
521e10b93dSalc 		4800 + 5*fbin;
531e10b93dSalc }
541e10b93dSalc 
551e10b93dSalc static uint16_t
fbin2freq_2p4(HAL_EEPROM * ee,uint16_t fbin)561e10b93dSalc fbin2freq_2p4(HAL_EEPROM *ee, uint16_t fbin)
571e10b93dSalc {
581e10b93dSalc 	if (fbin == CHANNEL_UNUSED)	/* reserved value, don't convert */
591e10b93dSalc 		return fbin;
601e10b93dSalc 	return ee->ee_version <= AR_EEPROM_VER3_2 ?
611e10b93dSalc 		2400 + fbin :
621e10b93dSalc 		2300 + fbin;
631e10b93dSalc }
641e10b93dSalc 
651e10b93dSalc /*
661e10b93dSalc  * Now copy EEPROM frequency pier contents into the allocated space
671e10b93dSalc  */
681e10b93dSalc static HAL_BOOL
readEepromFreqPierInfo(struct ath_hal * ah,HAL_EEPROM * ee)691e10b93dSalc readEepromFreqPierInfo(struct ath_hal *ah, HAL_EEPROM *ee)
701e10b93dSalc {
711e10b93dSalc #define	EEREAD(_off) do {				\
721e10b93dSalc 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
731e10b93dSalc 		return AH_FALSE;			\
741e10b93dSalc } while (0)
751e10b93dSalc 	uint16_t eeval, off;
761e10b93dSalc 	int i;
771e10b93dSalc 
781e10b93dSalc 	if (ee->ee_version >= AR_EEPROM_VER4_0 &&
791e10b93dSalc 	    ee->ee_eepMap && !ee->ee_Amode) {
801e10b93dSalc 		/*
811e10b93dSalc 		 * V4.0 EEPROMs with map type 1 have frequency pier
821e10b93dSalc 		 * data only when 11a mode is supported.
831e10b93dSalc 		 */
841e10b93dSalc 		return AH_TRUE;
851e10b93dSalc 	}
861e10b93dSalc 	if (ee->ee_version >= AR_EEPROM_VER3_3) {
871e10b93dSalc 		off = GROUPS_OFFSET3_3 + GROUP1_OFFSET;
881e10b93dSalc 		for (i = 0; i < ee->ee_numChannels11a; i += 2) {
891e10b93dSalc 			EEREAD(off++);
901e10b93dSalc 			ee->ee_channels11a[i]   = (eeval >> 8) & FREQ_MASK_3_3;
911e10b93dSalc 			ee->ee_channels11a[i+1] = eeval & FREQ_MASK_3_3;
921e10b93dSalc 		}
931e10b93dSalc 	} else {
941e10b93dSalc 		off = GROUPS_OFFSET3_2 + GROUP1_OFFSET;
951e10b93dSalc 
961e10b93dSalc 		EEREAD(off++);
971e10b93dSalc 		ee->ee_channels11a[0] = (eeval >> 9) & FREQ_MASK;
981e10b93dSalc 		ee->ee_channels11a[1] = (eeval >> 2) & FREQ_MASK;
991e10b93dSalc 		ee->ee_channels11a[2] = (eeval << 5) & FREQ_MASK;
1001e10b93dSalc 
1011e10b93dSalc 		EEREAD(off++);
1021e10b93dSalc 		ee->ee_channels11a[2] |= (eeval >> 11) & 0x1f;
1031e10b93dSalc 		ee->ee_channels11a[3]  = (eeval >>  4) & FREQ_MASK;
1041e10b93dSalc 		ee->ee_channels11a[4]  = (eeval <<  3) & FREQ_MASK;
1051e10b93dSalc 
1061e10b93dSalc 		EEREAD(off++);
1071e10b93dSalc 		ee->ee_channels11a[4] |= (eeval >> 13) & 0x7;
1081e10b93dSalc 		ee->ee_channels11a[5]  = (eeval >>  6) & FREQ_MASK;
1091e10b93dSalc 		ee->ee_channels11a[6]  = (eeval <<  1) & FREQ_MASK;
1101e10b93dSalc 
1111e10b93dSalc 		EEREAD(off++);
1121e10b93dSalc 		ee->ee_channels11a[6] |= (eeval >> 15) & 0x1;
1131e10b93dSalc 		ee->ee_channels11a[7]  = (eeval >>  8) & FREQ_MASK;
1141e10b93dSalc 		ee->ee_channels11a[8]  = (eeval >>  1) & FREQ_MASK;
1151e10b93dSalc 		ee->ee_channels11a[9]  = (eeval <<  6) & FREQ_MASK;
1161e10b93dSalc 
1171e10b93dSalc 		EEREAD(off++);
1181e10b93dSalc 		ee->ee_channels11a[9] |= (eeval >> 10) & 0x3f;
1191e10b93dSalc 	}
1201e10b93dSalc 
1211e10b93dSalc 	for (i = 0; i < ee->ee_numChannels11a; i++)
1221e10b93dSalc 		ee->ee_channels11a[i] = fbin2freq(ee, ee->ee_channels11a[i]);
1231e10b93dSalc 
1241e10b93dSalc 	return AH_TRUE;
1251e10b93dSalc #undef EEREAD
1261e10b93dSalc }
1271e10b93dSalc 
1281e10b93dSalc /*
1291e10b93dSalc  * Rev 4 Eeprom 5112 Power Extract Functions
1301e10b93dSalc  */
1311e10b93dSalc 
1321e10b93dSalc /*
1331e10b93dSalc  * Allocate the power information based on the number of channels
1341e10b93dSalc  * recorded by the calibration.  These values are then initialized.
1351e10b93dSalc  */
1361e10b93dSalc static HAL_BOOL
eepromAllocExpnPower5112(struct ath_hal * ah,const EEPROM_POWER_5112 * pCalDataset,EEPROM_POWER_EXPN_5112 * pPowerExpn)1371e10b93dSalc eepromAllocExpnPower5112(struct ath_hal *ah,
1381e10b93dSalc 	const EEPROM_POWER_5112 *pCalDataset,
1391e10b93dSalc 	EEPROM_POWER_EXPN_5112 *pPowerExpn)
1401e10b93dSalc {
1411e10b93dSalc 	uint16_t numChannels = pCalDataset->numChannels;
1421e10b93dSalc 	const uint16_t *pChanList = pCalDataset->pChannels;
1431e10b93dSalc 	void *data;
1441e10b93dSalc 	int i, j;
1451e10b93dSalc 
1461e10b93dSalc 	/* Allocate the channel and Power Data arrays together */
1471e10b93dSalc 	data = ath_hal_malloc(
1481e10b93dSalc 		roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)) +
1491e10b93dSalc 		sizeof(EXPN_DATA_PER_CHANNEL_5112) * numChannels);
1501e10b93dSalc 	if (data == AH_NULL) {
1511e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY,
1521e10b93dSalc 		    "%s unable to allocate raw data struct (gen3)\n", __func__);
1531e10b93dSalc 		return AH_FALSE;
1541e10b93dSalc 	}
1551e10b93dSalc 	pPowerExpn->pChannels = data;
1561e10b93dSalc 	pPowerExpn->pDataPerChannel = (void *)(((char *)data) +
1571e10b93dSalc 		roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)));
1581e10b93dSalc 
1591e10b93dSalc 	pPowerExpn->numChannels = numChannels;
1601e10b93dSalc 	for (i = 0; i < numChannels; i++) {
1611e10b93dSalc 		pPowerExpn->pChannels[i] =
1621e10b93dSalc 			pPowerExpn->pDataPerChannel[i].channelValue =
1631e10b93dSalc 				pChanList[i];
1641e10b93dSalc 		for (j = 0; j < NUM_XPD_PER_CHANNEL; j++) {
1651e10b93dSalc 			pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].xpd_gain = j;
1661e10b93dSalc 			pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].numPcdacs = 0;
1671e10b93dSalc 		}
1681e10b93dSalc 		pPowerExpn->pDataPerChannel[i].pDataPerXPD[0].numPcdacs = 4;
1691e10b93dSalc 		pPowerExpn->pDataPerChannel[i].pDataPerXPD[3].numPcdacs = 3;
1701e10b93dSalc 	}
1711e10b93dSalc 	return AH_TRUE;
1721e10b93dSalc }
1731e10b93dSalc 
1741e10b93dSalc /*
1751e10b93dSalc  * Expand the dataSet from the calibration information into the
1761e10b93dSalc  * final power structure for 5112
1771e10b93dSalc  */
1781e10b93dSalc static HAL_BOOL
eepromExpandPower5112(struct ath_hal * ah,const EEPROM_POWER_5112 * pCalDataset,EEPROM_POWER_EXPN_5112 * pPowerExpn)1791e10b93dSalc eepromExpandPower5112(struct ath_hal *ah,
1801e10b93dSalc 	const EEPROM_POWER_5112 *pCalDataset,
1811e10b93dSalc 	EEPROM_POWER_EXPN_5112 *pPowerExpn)
1821e10b93dSalc {
1831e10b93dSalc 	int ii, jj, kk;
1841e10b93dSalc 	EXPN_DATA_PER_XPD_5112 *pExpnXPD;
1851e10b93dSalc 	/* ptr to array of info held per channel */
1861e10b93dSalc 	const EEPROM_DATA_PER_CHANNEL_5112 *pCalCh;
1871e10b93dSalc 	uint16_t xgainList[2], xpdMask;
1881e10b93dSalc 
1891e10b93dSalc 	pPowerExpn->xpdMask = pCalDataset->xpdMask;
1901e10b93dSalc 
1911e10b93dSalc 	xgainList[0] = 0xDEAD;
1921e10b93dSalc 	xgainList[1] = 0xDEAD;
1931e10b93dSalc 
1941e10b93dSalc 	kk = 0;
1951e10b93dSalc 	xpdMask = pPowerExpn->xpdMask;
1961e10b93dSalc 	for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) {
1971e10b93dSalc 		if (((xpdMask >> jj) & 1) > 0) {
1981e10b93dSalc 			if (kk > 1) {
1991e10b93dSalc 				HALDEBUG(ah, HAL_DEBUG_ANY,
2001e10b93dSalc 				    "%s: too many xpdGains in dataset: %u\n",
2011e10b93dSalc 				    __func__, kk);
2021e10b93dSalc 				return AH_FALSE;
2031e10b93dSalc 			}
2041e10b93dSalc 			xgainList[kk++] = jj;
2051e10b93dSalc 		}
2061e10b93dSalc 	}
2071e10b93dSalc 
2081e10b93dSalc 	pPowerExpn->numChannels = pCalDataset->numChannels;
2091e10b93dSalc 	if (pPowerExpn->numChannels == 0) {
2101e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no channels\n", __func__);
2111e10b93dSalc 		return AH_FALSE;
2121e10b93dSalc 	}
2131e10b93dSalc 
2141e10b93dSalc 	for (ii = 0; ii < pPowerExpn->numChannels; ii++) {
2151e10b93dSalc 		pCalCh = &pCalDataset->pDataPerChannel[ii];
2161e10b93dSalc 		pPowerExpn->pDataPerChannel[ii].channelValue =
2171e10b93dSalc 			pCalCh->channelValue;
2181e10b93dSalc 		pPowerExpn->pDataPerChannel[ii].maxPower_t4 =
2191e10b93dSalc 			pCalCh->maxPower_t4;
2201e10b93dSalc 
2211e10b93dSalc 		for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++)
2221e10b93dSalc 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj].numPcdacs = 0;
2231e10b93dSalc 		if (xgainList[1] == 0xDEAD) {
2241e10b93dSalc 			jj = xgainList[0];
2251e10b93dSalc 			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
2261e10b93dSalc 			pExpnXPD->numPcdacs = 4;
2271e10b93dSalc 			pExpnXPD->pcdac[0] = pCalCh->pcd1_xg0;
2281e10b93dSalc 			pExpnXPD->pcdac[1] = (uint16_t)
2291e10b93dSalc 				(pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0);
2301e10b93dSalc 			pExpnXPD->pcdac[2] = (uint16_t)
2311e10b93dSalc 				(pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0);
2321e10b93dSalc 			pExpnXPD->pcdac[3] = (uint16_t)
2331e10b93dSalc 				(pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0);
2341e10b93dSalc 
2351e10b93dSalc 			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0;
2361e10b93dSalc 			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0;
2371e10b93dSalc 			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0;
2381e10b93dSalc 			pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0;
2391e10b93dSalc 
2401e10b93dSalc 		} else {
2411e10b93dSalc 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[0]].pcdac[0] = pCalCh->pcd1_xg0;
2421e10b93dSalc 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[0] = 20;
2431e10b93dSalc 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[1] = 35;
2441e10b93dSalc 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[2] = 63;
2451e10b93dSalc 
2461e10b93dSalc 			jj = xgainList[0];
2471e10b93dSalc 			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
2481e10b93dSalc 			pExpnXPD->numPcdacs = 4;
2491e10b93dSalc 			pExpnXPD->pcdac[1] = (uint16_t)
2501e10b93dSalc 				(pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0);
2511e10b93dSalc 			pExpnXPD->pcdac[2] = (uint16_t)
2521e10b93dSalc 				(pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0);
2531e10b93dSalc 			pExpnXPD->pcdac[3] = (uint16_t)
2541e10b93dSalc 				(pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0);
2551e10b93dSalc 			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0;
2561e10b93dSalc 			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0;
2571e10b93dSalc 			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0;
2581e10b93dSalc 			pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0;
2591e10b93dSalc 
2601e10b93dSalc 			jj = xgainList[1];
2611e10b93dSalc 			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
2621e10b93dSalc 			pExpnXPD->numPcdacs = 3;
2631e10b93dSalc 
2641e10b93dSalc 			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg3;
2651e10b93dSalc 			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg3;
2661e10b93dSalc 			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg3;
2671e10b93dSalc 		}
2681e10b93dSalc 	}
2691e10b93dSalc 	return AH_TRUE;
2701e10b93dSalc }
2711e10b93dSalc 
2721e10b93dSalc static HAL_BOOL
readEepromRawPowerCalInfo5112(struct ath_hal * ah,HAL_EEPROM * ee)2731e10b93dSalc readEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee)
2741e10b93dSalc {
2751e10b93dSalc #define	EEREAD(_off) do {				\
2761e10b93dSalc 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
2771e10b93dSalc 		return AH_FALSE;			\
2781e10b93dSalc } while (0)
2791e10b93dSalc 	const uint16_t dbmmask		 = 0xff;
2801e10b93dSalc 	const uint16_t pcdac_delta_mask = 0x1f;
2811e10b93dSalc 	const uint16_t pcdac_mask	 = 0x3f;
2821e10b93dSalc 	const uint16_t freqmask	 = 0xff;
2831e10b93dSalc 
2841e10b93dSalc 	int i, mode, numPiers;
2851e10b93dSalc 	uint32_t off;
2861e10b93dSalc 	uint16_t eeval;
2871e10b93dSalc 	uint16_t freq[NUM_11A_EEPROM_CHANNELS];
2881e10b93dSalc         EEPROM_POWER_5112 eePower;
2891e10b93dSalc 
2901e10b93dSalc 	HALASSERT(ee->ee_version >= AR_EEPROM_VER4_0);
2911e10b93dSalc 	off = GROUPS_OFFSET3_3;
2921e10b93dSalc 	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
2931e10b93dSalc 		numPiers = 0;
2941e10b93dSalc 		switch (mode) {
2951e10b93dSalc 		case headerInfo11A:
2961e10b93dSalc 			if (!ee->ee_Amode)	/* no 11a calibration data */
2971e10b93dSalc 				continue;
2981e10b93dSalc 			while (numPiers < NUM_11A_EEPROM_CHANNELS) {
2991e10b93dSalc 				EEREAD(off++);
3001e10b93dSalc 				if ((eeval & freqmask) == 0)
3011e10b93dSalc 					break;
3021e10b93dSalc 				freq[numPiers++] = fbin2freq(ee,
3031e10b93dSalc 					eeval & freqmask);
3041e10b93dSalc 
3051e10b93dSalc 				if (((eeval >> 8) & freqmask) == 0)
3061e10b93dSalc 					break;
3071e10b93dSalc 				freq[numPiers++] = fbin2freq(ee,
3081e10b93dSalc 					(eeval>>8) & freqmask);
3091e10b93dSalc 			}
3101e10b93dSalc 			break;
3111e10b93dSalc 		case headerInfo11B:
3121e10b93dSalc 			if (!ee->ee_Bmode)	/* no 11b calibration data */
3131e10b93dSalc 				continue;
3141e10b93dSalc 			for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++)
3151e10b93dSalc 				if (ee->ee_calPier11b[i] != CHANNEL_UNUSED)
3161e10b93dSalc 					freq[numPiers++] = ee->ee_calPier11b[i];
3171e10b93dSalc 			break;
3181e10b93dSalc 		case headerInfo11G:
3191e10b93dSalc 			if (!ee->ee_Gmode)	/* no 11g calibration data */
3201e10b93dSalc 				continue;
3211e10b93dSalc 			for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++)
3221e10b93dSalc 				if (ee->ee_calPier11g[i] != CHANNEL_UNUSED)
3231e10b93dSalc 					freq[numPiers++] = ee->ee_calPier11g[i];
3241e10b93dSalc 			break;
3251e10b93dSalc 		default:
3261e10b93dSalc 			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
3271e10b93dSalc 			    __func__, mode);
3281e10b93dSalc 			return AH_FALSE;
3291e10b93dSalc 		}
3301e10b93dSalc 
3311e10b93dSalc 		OS_MEMZERO(&eePower, sizeof(eePower));
3321e10b93dSalc 		eePower.numChannels = numPiers;
3331e10b93dSalc 
3341e10b93dSalc 		for (i = 0; i < numPiers; i++) {
3351e10b93dSalc 			eePower.pChannels[i] = freq[i];
3361e10b93dSalc 			eePower.pDataPerChannel[i].channelValue = freq[i];
3371e10b93dSalc 
3381e10b93dSalc 			EEREAD(off++);
3391e10b93dSalc 			eePower.pDataPerChannel[i].pwr1_xg0 = (int16_t)
3401e10b93dSalc 				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
3411e10b93dSalc 			eePower.pDataPerChannel[i].pwr2_xg0 = (int16_t)
3421e10b93dSalc 				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
3431e10b93dSalc 
3441e10b93dSalc 			EEREAD(off++);
3451e10b93dSalc 			eePower.pDataPerChannel[i].pwr3_xg0 = (int16_t)
3461e10b93dSalc 				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
3471e10b93dSalc 			eePower.pDataPerChannel[i].pwr4_xg0 = (int16_t)
3481e10b93dSalc 				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
3491e10b93dSalc 
3501e10b93dSalc 			EEREAD(off++);
3511e10b93dSalc 			eePower.pDataPerChannel[i].pcd2_delta_xg0 = (uint16_t)
3521e10b93dSalc 				(eeval & pcdac_delta_mask);
3531e10b93dSalc 			eePower.pDataPerChannel[i].pcd3_delta_xg0 = (uint16_t)
3541e10b93dSalc 				((eeval >> 5) & pcdac_delta_mask);
3551e10b93dSalc 			eePower.pDataPerChannel[i].pcd4_delta_xg0 = (uint16_t)
3561e10b93dSalc 				((eeval >> 10) & pcdac_delta_mask);
3571e10b93dSalc 
3581e10b93dSalc 			EEREAD(off++);
3591e10b93dSalc 			eePower.pDataPerChannel[i].pwr1_xg3 = (int16_t)
3601e10b93dSalc 				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
3611e10b93dSalc 			eePower.pDataPerChannel[i].pwr2_xg3 = (int16_t)
3621e10b93dSalc 				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
3631e10b93dSalc 
3641e10b93dSalc 			EEREAD(off++);
3651e10b93dSalc 			eePower.pDataPerChannel[i].pwr3_xg3 = (int16_t)
3661e10b93dSalc 				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
3671e10b93dSalc 			if (ee->ee_version >= AR_EEPROM_VER4_3) {
3681e10b93dSalc 				eePower.pDataPerChannel[i].maxPower_t4 =
3691e10b93dSalc 					eePower.pDataPerChannel[i].pwr4_xg0;
3701e10b93dSalc 				eePower.pDataPerChannel[i].pcd1_xg0 = (uint16_t)
3711e10b93dSalc 					((eeval >> 8) & pcdac_mask);
3721e10b93dSalc 			} else {
3731e10b93dSalc 				eePower.pDataPerChannel[i].maxPower_t4 = (int16_t)
3741e10b93dSalc 					(((eeval >> 8) & dbmmask) -
3751e10b93dSalc 					 ((eeval >> 15) & 0x1)*256);
3761e10b93dSalc 				eePower.pDataPerChannel[i].pcd1_xg0 = 1;
3771e10b93dSalc 			}
3781e10b93dSalc 		}
3791e10b93dSalc 		eePower.xpdMask = ee->ee_xgain[mode];
3801e10b93dSalc 
3811e10b93dSalc 		if (!eepromAllocExpnPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) {
3821e10b93dSalc 			HALDEBUG(ah, HAL_DEBUG_ANY,
3831e10b93dSalc 			    "%s: did not allocate power struct\n", __func__);
3841e10b93dSalc 			return AH_FALSE;
3851e10b93dSalc                 }
3861e10b93dSalc                 if (!eepromExpandPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) {
3871e10b93dSalc 			HALDEBUG(ah, HAL_DEBUG_ANY,
3881e10b93dSalc 			    "%s: did not expand power struct\n", __func__);
3891e10b93dSalc 			return AH_FALSE;
3901e10b93dSalc 		}
3911e10b93dSalc 	}
3921e10b93dSalc 	return AH_TRUE;
3931e10b93dSalc #undef EEREAD
3941e10b93dSalc }
3951e10b93dSalc 
3961e10b93dSalc static void
freeEepromRawPowerCalInfo5112(struct ath_hal * ah,HAL_EEPROM * ee)3971e10b93dSalc freeEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee)
3981e10b93dSalc {
3991e10b93dSalc 	int mode;
4001e10b93dSalc 	void *data;
4011e10b93dSalc 
4021e10b93dSalc 	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
4031e10b93dSalc 		EEPROM_POWER_EXPN_5112 *pPowerExpn =
4041e10b93dSalc 			&ee->ee_modePowerArray5112[mode];
4051e10b93dSalc 		data = pPowerExpn->pChannels;
4061e10b93dSalc 		if (data != AH_NULL) {
4071e10b93dSalc 			pPowerExpn->pChannels = AH_NULL;
4081e10b93dSalc 			ath_hal_free(data);
4091e10b93dSalc 		}
4101e10b93dSalc 	}
4111e10b93dSalc }
4121e10b93dSalc 
4131e10b93dSalc static void
ar2413SetupEEPROMDataset(EEPROM_DATA_STRUCT_2413 * pEEPROMDataset2413,uint16_t myNumRawChannels,uint16_t * pMyRawChanList)4141e10b93dSalc ar2413SetupEEPROMDataset(EEPROM_DATA_STRUCT_2413 *pEEPROMDataset2413,
4151e10b93dSalc 	uint16_t myNumRawChannels, uint16_t *pMyRawChanList)
4161e10b93dSalc {
4171e10b93dSalc 	uint16_t i, channelValue;
4181e10b93dSalc 	uint32_t xpd_mask;
4191e10b93dSalc 	uint16_t numPdGainsUsed;
4201e10b93dSalc 
4211e10b93dSalc 	pEEPROMDataset2413->numChannels = myNumRawChannels;
4221e10b93dSalc 
4231e10b93dSalc 	xpd_mask = pEEPROMDataset2413->xpd_mask;
4241e10b93dSalc 	numPdGainsUsed = 0;
4251e10b93dSalc 	if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++;
4261e10b93dSalc 	if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++;
4271e10b93dSalc 	if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++;
4281e10b93dSalc 	if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++;
4291e10b93dSalc 
4301e10b93dSalc 	for (i = 0; i < myNumRawChannels; i++) {
4311e10b93dSalc 		channelValue = pMyRawChanList[i];
4321e10b93dSalc 		pEEPROMDataset2413->pChannels[i] = channelValue;
4331e10b93dSalc 		pEEPROMDataset2413->pDataPerChannel[i].channelValue = channelValue;
4341e10b93dSalc 		pEEPROMDataset2413->pDataPerChannel[i].numPdGains = numPdGainsUsed;
4351e10b93dSalc 	}
4361e10b93dSalc }
4371e10b93dSalc 
4381e10b93dSalc static HAL_BOOL
ar2413ReadCalDataset(struct ath_hal * ah,HAL_EEPROM * ee,EEPROM_DATA_STRUCT_2413 * pCalDataset,uint32_t start_offset,uint32_t maxPiers,uint8_t mode)4391e10b93dSalc ar2413ReadCalDataset(struct ath_hal *ah, HAL_EEPROM *ee,
4401e10b93dSalc 	EEPROM_DATA_STRUCT_2413 *pCalDataset,
4411e10b93dSalc 	uint32_t start_offset, uint32_t maxPiers, uint8_t mode)
4421e10b93dSalc {
4431e10b93dSalc #define	EEREAD(_off) do {				\
4441e10b93dSalc 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
4451e10b93dSalc 		return AH_FALSE;			\
4461e10b93dSalc } while (0)
4471e10b93dSalc 	const uint16_t dbm_I_mask = 0x1F;	/* 5-bits. 1dB step. */
4481e10b93dSalc 	const uint16_t dbm_delta_mask = 0xF;	/* 4-bits. 0.5dB step. */
4491e10b93dSalc 	const uint16_t Vpd_I_mask = 0x7F;	/* 7-bits. 0-128 */
4501e10b93dSalc 	const uint16_t Vpd_delta_mask = 0x3F;	/* 6-bits. 0-63 */
4511e10b93dSalc 	const uint16_t freqmask = 0xff;
4521e10b93dSalc 
4531e10b93dSalc 	uint16_t ii, eeval;
4541e10b93dSalc 	uint16_t idx, numPiers;
4551e10b93dSalc 	uint16_t freq[NUM_11A_EEPROM_CHANNELS];
4561e10b93dSalc 
4571e10b93dSalc 	idx = start_offset;
4581e10b93dSalc     for (numPiers = 0; numPiers < maxPiers;) {
4591e10b93dSalc         EEREAD(idx++);
4601e10b93dSalc         if ((eeval & freqmask) == 0)
4611e10b93dSalc             break;
4621e10b93dSalc         if (mode == headerInfo11A)
4631e10b93dSalc             freq[numPiers++] = fbin2freq(ee, (eeval & freqmask));
4641e10b93dSalc         else
4651e10b93dSalc             freq[numPiers++] = fbin2freq_2p4(ee, (eeval & freqmask));
4661e10b93dSalc 
4671e10b93dSalc         if (((eeval >> 8) & freqmask) == 0)
4681e10b93dSalc             break;
4691e10b93dSalc         if (mode == headerInfo11A)
4701e10b93dSalc             freq[numPiers++] = fbin2freq(ee, (eeval >> 8) & freqmask);
4711e10b93dSalc         else
4721e10b93dSalc             freq[numPiers++] = fbin2freq_2p4(ee, (eeval >> 8) & freqmask);
4731e10b93dSalc     }
4741e10b93dSalc 	ar2413SetupEEPROMDataset(pCalDataset, numPiers, &freq[0]);
4751e10b93dSalc 
4761e10b93dSalc 	idx = start_offset + (maxPiers / 2);
4771e10b93dSalc 	for (ii = 0; ii < pCalDataset->numChannels; ii++) {
4781e10b93dSalc 		EEPROM_DATA_PER_CHANNEL_2413 *currCh =
4791e10b93dSalc 			&(pCalDataset->pDataPerChannel[ii]);
4801e10b93dSalc 
4811e10b93dSalc 		if (currCh->numPdGains > 0) {
4821e10b93dSalc 			/*
4831e10b93dSalc 			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
4841e10b93dSalc 			 * and Vpd values for pdgain_0
4851e10b93dSalc 			 */
4861e10b93dSalc 			EEREAD(idx++);
4871e10b93dSalc 			currCh->pwr_I[0] = eeval & dbm_I_mask;
4881e10b93dSalc 			currCh->Vpd_I[0] = (eeval >> 5) & Vpd_I_mask;
4891e10b93dSalc 			currCh->pwr_delta_t2[0][0] =
4901e10b93dSalc 				(eeval >> 12) & dbm_delta_mask;
4911e10b93dSalc 
4921e10b93dSalc 			EEREAD(idx++);
4931e10b93dSalc 			currCh->Vpd_delta[0][0] = eeval & Vpd_delta_mask;
4941e10b93dSalc 			currCh->pwr_delta_t2[1][0] =
4951e10b93dSalc 				(eeval >> 6) & dbm_delta_mask;
4961e10b93dSalc 			currCh->Vpd_delta[1][0] =
4971e10b93dSalc 				(eeval >> 10) & Vpd_delta_mask;
4981e10b93dSalc 
4991e10b93dSalc 			EEREAD(idx++);
5001e10b93dSalc 			currCh->pwr_delta_t2[2][0] = eeval & dbm_delta_mask;
5011e10b93dSalc 			currCh->Vpd_delta[2][0] = (eeval >> 4) & Vpd_delta_mask;
5021e10b93dSalc 		}
5031e10b93dSalc 
5041e10b93dSalc 		if (currCh->numPdGains > 1) {
5051e10b93dSalc 			/*
5061e10b93dSalc 			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
5071e10b93dSalc 			 * and Vpd values for pdgain_1
5081e10b93dSalc 			 */
5091e10b93dSalc 			currCh->pwr_I[1] = (eeval >> 10) & dbm_I_mask;
5101e10b93dSalc 			currCh->Vpd_I[1] = (eeval >> 15) & 0x1;
5111e10b93dSalc 
5121e10b93dSalc 			EEREAD(idx++);
5131e10b93dSalc 			/* upper 6 bits */
5141e10b93dSalc 			currCh->Vpd_I[1] |= (eeval & 0x3F) << 1;
5151e10b93dSalc 			currCh->pwr_delta_t2[0][1] =
5161e10b93dSalc 				(eeval >> 6) & dbm_delta_mask;
5171e10b93dSalc 			currCh->Vpd_delta[0][1] =
5181e10b93dSalc 				(eeval >> 10) & Vpd_delta_mask;
5191e10b93dSalc 
5201e10b93dSalc 			EEREAD(idx++);
5211e10b93dSalc 			currCh->pwr_delta_t2[1][1] = eeval & dbm_delta_mask;
5221e10b93dSalc 			currCh->Vpd_delta[1][1] = (eeval >> 4) & Vpd_delta_mask;
5231e10b93dSalc 			currCh->pwr_delta_t2[2][1] =
5241e10b93dSalc 				(eeval >> 10) & dbm_delta_mask;
5251e10b93dSalc 			currCh->Vpd_delta[2][1] = (eeval >> 14) & 0x3;
5261e10b93dSalc 
5271e10b93dSalc 			EEREAD(idx++);
5281e10b93dSalc 			/* upper 4 bits */
5291e10b93dSalc 			currCh->Vpd_delta[2][1] |= (eeval & 0xF) << 2;
5301e10b93dSalc 		} else if (currCh->numPdGains == 1) {
5311e10b93dSalc 			/*
5321e10b93dSalc 			 * Read the last pwr and Vpd values for pdgain_0
5331e10b93dSalc 			 */
5341e10b93dSalc 			currCh->pwr_delta_t2[3][0] =
5351e10b93dSalc 				(eeval >> 10) & dbm_delta_mask;
5361e10b93dSalc 			currCh->Vpd_delta[3][0] = (eeval >> 14) & 0x3;
5371e10b93dSalc 
5381e10b93dSalc 			EEREAD(idx++);
5391e10b93dSalc 			/* upper 4 bits */
5401e10b93dSalc 			currCh->Vpd_delta[3][0] |= (eeval & 0xF) << 2;
5411e10b93dSalc 
5421e10b93dSalc 			/* 4 words if numPdGains == 1 */
5431e10b93dSalc 		}
5441e10b93dSalc 
5451e10b93dSalc 		if (currCh->numPdGains > 2) {
5461e10b93dSalc 			/*
5471e10b93dSalc 			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
5481e10b93dSalc 			 * and Vpd values for pdgain_2
5491e10b93dSalc 			 */
5501e10b93dSalc 			currCh->pwr_I[2] = (eeval >> 4) & dbm_I_mask;
5511e10b93dSalc 			currCh->Vpd_I[2] = (eeval >> 9) & Vpd_I_mask;
5521e10b93dSalc 
5531e10b93dSalc 			EEREAD(idx++);
5541e10b93dSalc 			currCh->pwr_delta_t2[0][2] =
5551e10b93dSalc 				(eeval >> 0) & dbm_delta_mask;
5561e10b93dSalc 			currCh->Vpd_delta[0][2] = (eeval >> 4) & Vpd_delta_mask;
5571e10b93dSalc 			currCh->pwr_delta_t2[1][2] =
5581e10b93dSalc 				(eeval >> 10) & dbm_delta_mask;
5591e10b93dSalc 			currCh->Vpd_delta[1][2] = (eeval >> 14) & 0x3;
5601e10b93dSalc 
5611e10b93dSalc 			EEREAD(idx++);
5621e10b93dSalc 			/* upper 4 bits */
5631e10b93dSalc 			currCh->Vpd_delta[1][2] |= (eeval & 0xF) << 2;
5641e10b93dSalc 			currCh->pwr_delta_t2[2][2] =
5651e10b93dSalc 				(eeval >> 4) & dbm_delta_mask;
5661e10b93dSalc 			currCh->Vpd_delta[2][2] = (eeval >> 8) & Vpd_delta_mask;
5671e10b93dSalc 		} else if (currCh->numPdGains == 2) {
5681e10b93dSalc 			/*
5691e10b93dSalc 			 * Read the last pwr and Vpd values for pdgain_1
5701e10b93dSalc 			 */
5711e10b93dSalc 			currCh->pwr_delta_t2[3][1] =
5721e10b93dSalc 				(eeval >> 4) & dbm_delta_mask;
5731e10b93dSalc 			currCh->Vpd_delta[3][1] = (eeval >> 8) & Vpd_delta_mask;
5741e10b93dSalc 
5751e10b93dSalc 			/* 6 words if numPdGains == 2 */
5761e10b93dSalc 		}
5771e10b93dSalc 
5781e10b93dSalc 		if (currCh->numPdGains > 3) {
5791e10b93dSalc 			/*
5801e10b93dSalc 			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
5811e10b93dSalc 			 * and Vpd values for pdgain_3
5821e10b93dSalc 			 */
5831e10b93dSalc 			currCh->pwr_I[3] = (eeval >> 14) & 0x3;
5841e10b93dSalc 
5851e10b93dSalc 			EEREAD(idx++);
5861e10b93dSalc 			/* upper 3 bits */
5871e10b93dSalc 			currCh->pwr_I[3] |= ((eeval >> 0) & 0x7) << 2;
5881e10b93dSalc 			currCh->Vpd_I[3] = (eeval >> 3) & Vpd_I_mask;
5891e10b93dSalc 			currCh->pwr_delta_t2[0][3] =
5901e10b93dSalc 				(eeval >> 10) & dbm_delta_mask;
5911e10b93dSalc 			currCh->Vpd_delta[0][3] = (eeval >> 14) & 0x3;
5921e10b93dSalc 
5931e10b93dSalc 			EEREAD(idx++);
5941e10b93dSalc 			/* upper 4 bits */
5951e10b93dSalc 			currCh->Vpd_delta[0][3] |= (eeval & 0xF) << 2;
5961e10b93dSalc 			currCh->pwr_delta_t2[1][3] =
5971e10b93dSalc 				(eeval >> 4) & dbm_delta_mask;
5981e10b93dSalc 			currCh->Vpd_delta[1][3] = (eeval >> 8) & Vpd_delta_mask;
5991e10b93dSalc 			currCh->pwr_delta_t2[2][3] = (eeval >> 14) & 0x3;
6001e10b93dSalc 
6011e10b93dSalc 			EEREAD(idx++);
6021e10b93dSalc 			/* upper 2 bits */
6031e10b93dSalc 			currCh->pwr_delta_t2[2][3] |= ((eeval >> 0) & 0x3) << 2;
6041e10b93dSalc 			currCh->Vpd_delta[2][3] = (eeval >> 2) & Vpd_delta_mask;
6051e10b93dSalc 			currCh->pwr_delta_t2[3][3] =
6061e10b93dSalc 				(eeval >> 8) & dbm_delta_mask;
6071e10b93dSalc 			currCh->Vpd_delta[3][3] = (eeval >> 12) & 0xF;
6081e10b93dSalc 
6091e10b93dSalc 			EEREAD(idx++);
6101e10b93dSalc 			/* upper 2 bits */
6111e10b93dSalc 			currCh->Vpd_delta[3][3] |= ((eeval >> 0) & 0x3) << 4;
6121e10b93dSalc 
6131e10b93dSalc 			/* 12 words if numPdGains == 4 */
6141e10b93dSalc 		} else if (currCh->numPdGains == 3) {
6151e10b93dSalc 			/* read the last pwr and Vpd values for pdgain_2 */
6161e10b93dSalc 			currCh->pwr_delta_t2[3][2] = (eeval >> 14) & 0x3;
6171e10b93dSalc 
6181e10b93dSalc 			EEREAD(idx++);
6191e10b93dSalc 			/* upper 2 bits */
6201e10b93dSalc 			currCh->pwr_delta_t2[3][2] |= ((eeval >> 0) & 0x3) << 2;
6211e10b93dSalc 			currCh->Vpd_delta[3][2] = (eeval >> 2) & Vpd_delta_mask;
6221e10b93dSalc 
6231e10b93dSalc 			/* 9 words if numPdGains == 3 */
6241e10b93dSalc 		}
6251e10b93dSalc 	}
6261e10b93dSalc 	return AH_TRUE;
6271e10b93dSalc #undef EEREAD
6281e10b93dSalc }
6291e10b93dSalc 
6301e10b93dSalc static void
ar2413SetupRawDataset(RAW_DATA_STRUCT_2413 * pRaw,EEPROM_DATA_STRUCT_2413 * pCal)6311e10b93dSalc ar2413SetupRawDataset(RAW_DATA_STRUCT_2413 *pRaw, EEPROM_DATA_STRUCT_2413 *pCal)
6321e10b93dSalc {
6331e10b93dSalc 	uint16_t i, j, kk, channelValue;
6341e10b93dSalc 	uint16_t xpd_mask;
6351e10b93dSalc 	uint16_t numPdGainsUsed;
6361e10b93dSalc 
6371e10b93dSalc 	pRaw->numChannels = pCal->numChannels;
6381e10b93dSalc 
6391e10b93dSalc 	xpd_mask = pRaw->xpd_mask;
6401e10b93dSalc 	numPdGainsUsed = 0;
6411e10b93dSalc 	if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++;
6421e10b93dSalc 	if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++;
6431e10b93dSalc 	if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++;
6441e10b93dSalc 	if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++;
6451e10b93dSalc 
6461e10b93dSalc 	for (i = 0; i < pCal->numChannels; i++) {
6471e10b93dSalc 		channelValue = pCal->pChannels[i];
6481e10b93dSalc 
6491e10b93dSalc 		pRaw->pChannels[i] = channelValue;
6501e10b93dSalc 
6511e10b93dSalc 		pRaw->pDataPerChannel[i].channelValue = channelValue;
6521e10b93dSalc 		pRaw->pDataPerChannel[i].numPdGains = numPdGainsUsed;
6531e10b93dSalc 
6541e10b93dSalc 		kk = 0;
6551e10b93dSalc 		for (j = 0; j < MAX_NUM_PDGAINS_PER_CHANNEL; j++) {
6561e10b93dSalc 			pRaw->pDataPerChannel[i].pDataPerPDGain[j].pd_gain = j;
6571e10b93dSalc 			if ((xpd_mask >> j) & 0x1) {
6581e10b93dSalc 				pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_OTHER_PDGAINS;
6591e10b93dSalc 				kk++;
6601e10b93dSalc 				if (kk == 1) {
6611e10b93dSalc 					/*
6621e10b93dSalc 					 * lowest pd_gain corresponds
6631e10b93dSalc 					 *  to highest power and thus,
6641e10b93dSalc 					 *  has one more point
6651e10b93dSalc 					 */
6661e10b93dSalc 					pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_LAST_PDGAIN;
6671e10b93dSalc 				}
6681e10b93dSalc 			} else {
6691e10b93dSalc 				pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = 0;
6701e10b93dSalc 			}
6711e10b93dSalc 		}
6721e10b93dSalc 	}
6731e10b93dSalc }
6741e10b93dSalc 
6751e10b93dSalc static HAL_BOOL
ar2413EepromToRawDataset(struct ath_hal * ah,EEPROM_DATA_STRUCT_2413 * pCal,RAW_DATA_STRUCT_2413 * pRaw)6761e10b93dSalc ar2413EepromToRawDataset(struct ath_hal *ah,
6771e10b93dSalc 	EEPROM_DATA_STRUCT_2413 *pCal, RAW_DATA_STRUCT_2413 *pRaw)
6781e10b93dSalc {
6791e10b93dSalc 	uint16_t ii, jj, kk, ss;
6801e10b93dSalc 	RAW_DATA_PER_PDGAIN_2413 *pRawXPD;
6811e10b93dSalc 	/* ptr to array of info held per channel */
6821e10b93dSalc 	EEPROM_DATA_PER_CHANNEL_2413 *pCalCh;
6831e10b93dSalc 	uint16_t xgain_list[MAX_NUM_PDGAINS_PER_CHANNEL];
6841e10b93dSalc 	uint16_t xpd_mask;
6851e10b93dSalc 	uint32_t numPdGainsUsed;
6861e10b93dSalc 
6871e10b93dSalc 	HALASSERT(pRaw->xpd_mask == pCal->xpd_mask);
6881e10b93dSalc 
6891e10b93dSalc 	xgain_list[0] = 0xDEAD;
6901e10b93dSalc 	xgain_list[1] = 0xDEAD;
6911e10b93dSalc 	xgain_list[2] = 0xDEAD;
6921e10b93dSalc 	xgain_list[3] = 0xDEAD;
6931e10b93dSalc 
6941e10b93dSalc 	numPdGainsUsed = 0;
6951e10b93dSalc 	xpd_mask = pRaw->xpd_mask;
6961e10b93dSalc 	for (jj = 0; jj < MAX_NUM_PDGAINS_PER_CHANNEL; jj++) {
6971e10b93dSalc 		if ((xpd_mask >> (MAX_NUM_PDGAINS_PER_CHANNEL-jj-1)) & 1)
6981e10b93dSalc 			xgain_list[numPdGainsUsed++] = MAX_NUM_PDGAINS_PER_CHANNEL-jj-1;
6991e10b93dSalc 	}
7001e10b93dSalc 
7011e10b93dSalc 	pRaw->numChannels = pCal->numChannels;
7021e10b93dSalc 	for (ii = 0; ii < pRaw->numChannels; ii++) {
7031e10b93dSalc 		pCalCh = &(pCal->pDataPerChannel[ii]);
7041e10b93dSalc 		pRaw->pDataPerChannel[ii].channelValue = pCalCh->channelValue;
7051e10b93dSalc 
7061e10b93dSalc 		/* numVpd has already been setup appropriately for the relevant pdGains */
7071e10b93dSalc 		for (jj = 0; jj < numPdGainsUsed; jj++) {
7081e10b93dSalc 			/* use jj for calDataset and ss for rawDataset */
7091e10b93dSalc 			ss = xgain_list[jj];
7101e10b93dSalc 			pRawXPD = &(pRaw->pDataPerChannel[ii].pDataPerPDGain[ss]);
7111e10b93dSalc 			HALASSERT(pRawXPD->numVpd >= 1);
7121e10b93dSalc 
7131e10b93dSalc 			pRawXPD->pwr_t4[0] = (uint16_t)(4*pCalCh->pwr_I[jj]);
7141e10b93dSalc 			pRawXPD->Vpd[0]    = pCalCh->Vpd_I[jj];
7151e10b93dSalc 
7161e10b93dSalc 			for (kk = 1; kk < pRawXPD->numVpd; kk++) {
7171e10b93dSalc 				pRawXPD->pwr_t4[kk] = (int16_t)(pRawXPD->pwr_t4[kk-1] + 2*pCalCh->pwr_delta_t2[kk-1][jj]);
7181e10b93dSalc 				pRawXPD->Vpd[kk] = (uint16_t)(pRawXPD->Vpd[kk-1] + pCalCh->Vpd_delta[kk-1][jj]);
7191e10b93dSalc 			}
7201e10b93dSalc 			/* loop over Vpds */
7211e10b93dSalc 		}
7221e10b93dSalc 		/* loop over pd_gains */
7231e10b93dSalc 	}
7241e10b93dSalc 	/* loop over channels */
7251e10b93dSalc 	return AH_TRUE;
7261e10b93dSalc }
7271e10b93dSalc 
7281e10b93dSalc static HAL_BOOL
readEepromRawPowerCalInfo2413(struct ath_hal * ah,HAL_EEPROM * ee)7291e10b93dSalc readEepromRawPowerCalInfo2413(struct ath_hal *ah, HAL_EEPROM *ee)
7301e10b93dSalc {
7311e10b93dSalc 	/* NB: index is 1 less than numPdgains */
7321e10b93dSalc 	static const uint16_t wordsForPdgains[] = { 4, 6, 9, 12 };
7331e10b93dSalc 	EEPROM_DATA_STRUCT_2413 *pCal = AH_NULL;
7341e10b93dSalc 	RAW_DATA_STRUCT_2413 *pRaw;
7351e10b93dSalc 	int numEEPROMWordsPerChannel;
7361e10b93dSalc 	uint32_t off;
7371e10b93dSalc 	HAL_BOOL ret = AH_FALSE;
7381e10b93dSalc 
7391e10b93dSalc 	HALASSERT(ee->ee_version >= AR_EEPROM_VER5_0);
7401e10b93dSalc 	HALASSERT(ee->ee_eepMap == 2);
7411e10b93dSalc 
7421e10b93dSalc 	pCal = ath_hal_malloc(sizeof(EEPROM_DATA_STRUCT_2413));
7431e10b93dSalc 	if (pCal == AH_NULL)
7441e10b93dSalc 		goto exit;
7451e10b93dSalc 
7461e10b93dSalc 	off = ee->ee_eepMap2PowerCalStart;
7471e10b93dSalc 	if (ee->ee_Amode) {
7481e10b93dSalc 		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
7491e10b93dSalc 		pCal->xpd_mask = ee->ee_xgain[headerInfo11A];
7501e10b93dSalc 		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
7511e10b93dSalc 			NUM_11A_EEPROM_CHANNELS_2413, headerInfo11A)) {
7521e10b93dSalc 			goto exit;
7531e10b93dSalc 		}
7541e10b93dSalc 		pRaw = &ee->ee_rawDataset2413[headerInfo11A];
7551e10b93dSalc 		pRaw->xpd_mask = ee->ee_xgain[headerInfo11A];
7561e10b93dSalc 		ar2413SetupRawDataset(pRaw, pCal);
7571e10b93dSalc 		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
7581e10b93dSalc 			goto exit;
7591e10b93dSalc 		}
7601e10b93dSalc 		/* setup offsets for mode_11a next */
7611e10b93dSalc 		numEEPROMWordsPerChannel = wordsForPdgains[
7621e10b93dSalc 			pCal->pDataPerChannel[0].numPdGains - 1];
7631e10b93dSalc 		off += pCal->numChannels * numEEPROMWordsPerChannel + 5;
7641e10b93dSalc 	}
7651e10b93dSalc 	if (ee->ee_Bmode) {
7661e10b93dSalc 		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
7671e10b93dSalc 		pCal->xpd_mask = ee->ee_xgain[headerInfo11B];
7681e10b93dSalc 		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
7691e10b93dSalc 			NUM_2_4_EEPROM_CHANNELS_2413 , headerInfo11B)) {
7701e10b93dSalc 			goto exit;
7711e10b93dSalc 		}
7721e10b93dSalc 		pRaw = &ee->ee_rawDataset2413[headerInfo11B];
7731e10b93dSalc 		pRaw->xpd_mask = ee->ee_xgain[headerInfo11B];
7741e10b93dSalc 		ar2413SetupRawDataset(pRaw, pCal);
7751e10b93dSalc 		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
7761e10b93dSalc 			goto exit;
7771e10b93dSalc 		}
7781e10b93dSalc 		/* setup offsets for mode_11g next */
7791e10b93dSalc 		numEEPROMWordsPerChannel = wordsForPdgains[
7801e10b93dSalc 			pCal->pDataPerChannel[0].numPdGains - 1];
7811e10b93dSalc 		off += pCal->numChannels * numEEPROMWordsPerChannel + 2;
7821e10b93dSalc 	}
7831e10b93dSalc 	if (ee->ee_Gmode) {
7841e10b93dSalc 		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
7851e10b93dSalc 		pCal->xpd_mask = ee->ee_xgain[headerInfo11G];
7861e10b93dSalc 		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
7871e10b93dSalc 			NUM_2_4_EEPROM_CHANNELS_2413, headerInfo11G)) {
7881e10b93dSalc 			goto exit;
7891e10b93dSalc 		}
7901e10b93dSalc 		pRaw = &ee->ee_rawDataset2413[headerInfo11G];
7911e10b93dSalc 		pRaw->xpd_mask = ee->ee_xgain[headerInfo11G];
7921e10b93dSalc 		ar2413SetupRawDataset(pRaw, pCal);
7931e10b93dSalc 		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
7941e10b93dSalc 			goto exit;
7951e10b93dSalc 		}
7961e10b93dSalc 	}
7971e10b93dSalc 	ret = AH_TRUE;
7981e10b93dSalc  exit:
7991e10b93dSalc 	if (pCal != AH_NULL)
8001e10b93dSalc 		ath_hal_free(pCal);
8011e10b93dSalc 	return ret;
8021e10b93dSalc }
8031e10b93dSalc 
8041e10b93dSalc /*
8051e10b93dSalc  * Now copy EEPROM Raw Power Calibration per frequency contents
8061e10b93dSalc  * into the allocated space
8071e10b93dSalc  */
8081e10b93dSalc static HAL_BOOL
readEepromRawPowerCalInfo(struct ath_hal * ah,HAL_EEPROM * ee)8091e10b93dSalc readEepromRawPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee)
8101e10b93dSalc {
8111e10b93dSalc #define	EEREAD(_off) do {				\
8121e10b93dSalc 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
8131e10b93dSalc 		return AH_FALSE;			\
8141e10b93dSalc } while (0)
8151e10b93dSalc 	uint16_t eeval, nchan;
8161e10b93dSalc 	uint32_t off;
8171e10b93dSalc 	int i, j, mode;
8181e10b93dSalc 
8191e10b93dSalc         if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1)
8201e10b93dSalc 		return readEepromRawPowerCalInfo5112(ah, ee);
8211e10b93dSalc 	if (ee->ee_version >= AR_EEPROM_VER5_0 && ee->ee_eepMap == 2)
8221e10b93dSalc 		return readEepromRawPowerCalInfo2413(ah, ee);
8231e10b93dSalc 
8241e10b93dSalc 	/*
8251e10b93dSalc 	 * Group 2:  read raw power data for all frequency piers
8261e10b93dSalc 	 *
8271e10b93dSalc 	 * NOTE: Group 2 contains the raw power calibration
8281e10b93dSalc 	 *	 information for each of the channels that
8291e10b93dSalc 	 *	 we recorded above.
8301e10b93dSalc 	 */
8311e10b93dSalc 	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
8321e10b93dSalc 		uint16_t *pChannels = AH_NULL;
8331e10b93dSalc 		DATA_PER_CHANNEL *pChannelData = AH_NULL;
8341e10b93dSalc 
8351e10b93dSalc 		off = ee->ee_version >= AR_EEPROM_VER3_3 ?
8361e10b93dSalc 			GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2;
8371e10b93dSalc 		switch (mode) {
8381e10b93dSalc 		case headerInfo11A:
8391e10b93dSalc 			off      	+= GROUP2_OFFSET;
8401e10b93dSalc 			nchan		= ee->ee_numChannels11a;
8411e10b93dSalc 			pChannelData	= ee->ee_dataPerChannel11a;
8421e10b93dSalc 			pChannels	= ee->ee_channels11a;
8431e10b93dSalc 			break;
8441e10b93dSalc 		case headerInfo11B:
8451e10b93dSalc 			if (!ee->ee_Bmode)
8461e10b93dSalc 				continue;
8471e10b93dSalc 			off		+= GROUP3_OFFSET;
8481e10b93dSalc 			nchan		= ee->ee_numChannels2_4;
8491e10b93dSalc 			pChannelData	= ee->ee_dataPerChannel11b;
8501e10b93dSalc 			pChannels	= ee->ee_channels11b;
8511e10b93dSalc 			break;
8521e10b93dSalc 		case headerInfo11G:
8531e10b93dSalc 			if (!ee->ee_Gmode)
8541e10b93dSalc 				continue;
8551e10b93dSalc 			off		+= GROUP4_OFFSET;
8561e10b93dSalc 			nchan		= ee->ee_numChannels2_4;
8571e10b93dSalc 			pChannelData	= ee->ee_dataPerChannel11g;
8581e10b93dSalc 			pChannels	= ee->ee_channels11g;
8591e10b93dSalc 			break;
8601e10b93dSalc 		default:
8611e10b93dSalc 			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
8621e10b93dSalc 			    __func__, mode);
8631e10b93dSalc 			return AH_FALSE;
8641e10b93dSalc 		}
8651e10b93dSalc 		for (i = 0; i < nchan; i++) {
8661e10b93dSalc 			pChannelData->channelValue = pChannels[i];
8671e10b93dSalc 
8681e10b93dSalc 			EEREAD(off++);
8691e10b93dSalc 			pChannelData->pcdacMax     = (uint16_t)((eeval >> 10) & PCDAC_MASK);
8701e10b93dSalc 			pChannelData->pcdacMin     = (uint16_t)((eeval >> 4) & PCDAC_MASK);
8711e10b93dSalc 			pChannelData->PwrValues[0] = (uint16_t)((eeval << 2) & POWER_MASK);
8721e10b93dSalc 
8731e10b93dSalc 			EEREAD(off++);
8741e10b93dSalc 			pChannelData->PwrValues[0] |= (uint16_t)((eeval >> 14) & 0x3);
8751e10b93dSalc 			pChannelData->PwrValues[1] = (uint16_t)((eeval >> 8) & POWER_MASK);
8761e10b93dSalc 			pChannelData->PwrValues[2] = (uint16_t)((eeval >> 2) & POWER_MASK);
8771e10b93dSalc 			pChannelData->PwrValues[3] = (uint16_t)((eeval << 4) & POWER_MASK);
8781e10b93dSalc 
8791e10b93dSalc 			EEREAD(off++);
8801e10b93dSalc 			pChannelData->PwrValues[3] |= (uint16_t)((eeval >> 12) & 0xf);
8811e10b93dSalc 			pChannelData->PwrValues[4] = (uint16_t)((eeval >> 6) & POWER_MASK);
8821e10b93dSalc 			pChannelData->PwrValues[5] = (uint16_t)(eeval  & POWER_MASK);
8831e10b93dSalc 
8841e10b93dSalc 			EEREAD(off++);
8851e10b93dSalc 			pChannelData->PwrValues[6] = (uint16_t)((eeval >> 10) & POWER_MASK);
8861e10b93dSalc 			pChannelData->PwrValues[7] = (uint16_t)((eeval >> 4) & POWER_MASK);
8871e10b93dSalc 			pChannelData->PwrValues[8] = (uint16_t)((eeval << 2) & POWER_MASK);
8881e10b93dSalc 
8891e10b93dSalc 			EEREAD(off++);
8901e10b93dSalc 			pChannelData->PwrValues[8] |= (uint16_t)((eeval >> 14) & 0x3);
8911e10b93dSalc 			pChannelData->PwrValues[9] = (uint16_t)((eeval >> 8) & POWER_MASK);
8921e10b93dSalc 			pChannelData->PwrValues[10] = (uint16_t)((eeval >> 2) & POWER_MASK);
8931e10b93dSalc 
8941e10b93dSalc 			getPcdacInterceptsFromPcdacMinMax(ee,
8951e10b93dSalc 				pChannelData->pcdacMin, pChannelData->pcdacMax,
8961e10b93dSalc 				pChannelData->PcdacValues) ;
8971e10b93dSalc 
8981e10b93dSalc 			for (j = 0; j < pChannelData->numPcdacValues; j++) {
8991e10b93dSalc 				pChannelData->PwrValues[j] = (uint16_t)(
9001e10b93dSalc 					PWR_STEP * pChannelData->PwrValues[j]);
9011e10b93dSalc 				/* Note these values are scaled up. */
9021e10b93dSalc 			}
9031e10b93dSalc 			pChannelData++;
9041e10b93dSalc 		}
9051e10b93dSalc 	}
9061e10b93dSalc 	return AH_TRUE;
9071e10b93dSalc #undef EEREAD
9081e10b93dSalc }
9091e10b93dSalc 
9101e10b93dSalc /*
9111e10b93dSalc  * Copy EEPROM Target Power Calbration per rate contents
9121e10b93dSalc  * into the allocated space
9131e10b93dSalc  */
9141e10b93dSalc static HAL_BOOL
readEepromTargetPowerCalInfo(struct ath_hal * ah,HAL_EEPROM * ee)9151e10b93dSalc readEepromTargetPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee)
9161e10b93dSalc {
9171e10b93dSalc #define	EEREAD(_off) do {				\
9181e10b93dSalc 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
9191e10b93dSalc 		return AH_FALSE;			\
9201e10b93dSalc } while (0)
9211e10b93dSalc 	uint16_t eeval, enable24;
9221e10b93dSalc 	uint32_t off;
9231e10b93dSalc 	int i, mode, nchan;
9241e10b93dSalc 
9251e10b93dSalc 	enable24 = ee->ee_Bmode || ee->ee_Gmode;
9261e10b93dSalc 	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
9271e10b93dSalc 		TRGT_POWER_INFO *pPowerInfo;
9281e10b93dSalc 		uint16_t *pNumTrgtChannels;
9291e10b93dSalc 
9301e10b93dSalc 		off = ee->ee_version >= AR_EEPROM_VER4_0 ?
9311e10b93dSalc 				ee->ee_targetPowersStart - GROUP5_OFFSET :
9321e10b93dSalc 		      ee->ee_version >= AR_EEPROM_VER3_3 ?
9331e10b93dSalc 				GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2;
9341e10b93dSalc 		switch (mode) {
9351e10b93dSalc 		case headerInfo11A:
9361e10b93dSalc 			off += GROUP5_OFFSET;
9371e10b93dSalc 			nchan = NUM_TEST_FREQUENCIES;
9381e10b93dSalc 			pPowerInfo = ee->ee_trgtPwr_11a;
9391e10b93dSalc 			pNumTrgtChannels = &ee->ee_numTargetPwr_11a;
9401e10b93dSalc 			break;
9411e10b93dSalc 		case headerInfo11B:
9421e10b93dSalc 			if (!enable24)
9431e10b93dSalc 				continue;
9441e10b93dSalc 			off += GROUP6_OFFSET;
9451e10b93dSalc 			nchan = 2;
9461e10b93dSalc 			pPowerInfo = ee->ee_trgtPwr_11b;
9471e10b93dSalc 			pNumTrgtChannels = &ee->ee_numTargetPwr_11b;
9481e10b93dSalc 			break;
9491e10b93dSalc 		case headerInfo11G:
9501e10b93dSalc 			if (!enable24)
9511e10b93dSalc 				continue;
9521e10b93dSalc 			off += GROUP7_OFFSET;
9531e10b93dSalc 			nchan = 3;
9541e10b93dSalc 			pPowerInfo = ee->ee_trgtPwr_11g;
9551e10b93dSalc 			pNumTrgtChannels = &ee->ee_numTargetPwr_11g;
9561e10b93dSalc 			break;
9571e10b93dSalc 		default:
9581e10b93dSalc 			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
9591e10b93dSalc 			    __func__, mode);
9601e10b93dSalc 			return AH_FALSE;
9611e10b93dSalc 		}
9621e10b93dSalc 		*pNumTrgtChannels = 0;
9631e10b93dSalc 		for (i = 0; i < nchan; i++) {
9641e10b93dSalc 			EEREAD(off++);
9651e10b93dSalc 			if (ee->ee_version >= AR_EEPROM_VER3_3) {
9661e10b93dSalc 				pPowerInfo->testChannel = (eeval >> 8) & 0xff;
9671e10b93dSalc 			} else {
9681e10b93dSalc 				pPowerInfo->testChannel = (eeval >> 9) & 0x7f;
9691e10b93dSalc 			}
9701e10b93dSalc 
9711e10b93dSalc 			if (pPowerInfo->testChannel != 0) {
9721e10b93dSalc 				/* get the channel value and read rest of info */
9731e10b93dSalc 				if (mode == headerInfo11A) {
9741e10b93dSalc 					pPowerInfo->testChannel = fbin2freq(ee, pPowerInfo->testChannel);
9751e10b93dSalc 				} else {
9761e10b93dSalc 					pPowerInfo->testChannel = fbin2freq_2p4(ee, pPowerInfo->testChannel);
9771e10b93dSalc 				}
9781e10b93dSalc 
9791e10b93dSalc 				if (ee->ee_version >= AR_EEPROM_VER3_3) {
9801e10b93dSalc 					pPowerInfo->twicePwr6_24 = (eeval >> 2) & POWER_MASK;
9811e10b93dSalc 					pPowerInfo->twicePwr36   = (eeval << 4) & POWER_MASK;
9821e10b93dSalc 				} else {
9831e10b93dSalc 					pPowerInfo->twicePwr6_24 = (eeval >> 3) & POWER_MASK;
9841e10b93dSalc 					pPowerInfo->twicePwr36   = (eeval << 3) & POWER_MASK;
9851e10b93dSalc 				}
9861e10b93dSalc 
9871e10b93dSalc 				EEREAD(off++);
9881e10b93dSalc 				if (ee->ee_version >= AR_EEPROM_VER3_3) {
9891e10b93dSalc 					pPowerInfo->twicePwr36 |= (eeval >> 12) & 0xf;
9901e10b93dSalc 					pPowerInfo->twicePwr48 = (eeval >> 6) & POWER_MASK;
9911e10b93dSalc 					pPowerInfo->twicePwr54 =  eeval & POWER_MASK;
9921e10b93dSalc 				} else {
9931e10b93dSalc 					pPowerInfo->twicePwr36 |= (eeval >> 13) & 0x7;
9941e10b93dSalc 					pPowerInfo->twicePwr48 = (eeval >> 7) & POWER_MASK;
9951e10b93dSalc 					pPowerInfo->twicePwr54 = (eeval >> 1) & POWER_MASK;
9961e10b93dSalc 				}
9971e10b93dSalc 				(*pNumTrgtChannels)++;
9981e10b93dSalc 			}
9991e10b93dSalc 			pPowerInfo++;
10001e10b93dSalc 		}
10011e10b93dSalc 	}
10021e10b93dSalc 	return AH_TRUE;
10031e10b93dSalc #undef EEREAD
10041e10b93dSalc }
10051e10b93dSalc 
10061e10b93dSalc /*
10071e10b93dSalc  * Now copy EEPROM Coformance Testing Limits contents
10081e10b93dSalc  * into the allocated space
10091e10b93dSalc  */
10101e10b93dSalc static HAL_BOOL
readEepromCTLInfo(struct ath_hal * ah,HAL_EEPROM * ee)10111e10b93dSalc readEepromCTLInfo(struct ath_hal *ah, HAL_EEPROM *ee)
10121e10b93dSalc {
10131e10b93dSalc #define	EEREAD(_off) do {				\
10141e10b93dSalc 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
10151e10b93dSalc 		return AH_FALSE;			\
10161e10b93dSalc } while (0)
10171e10b93dSalc 	RD_EDGES_POWER *rep;
10181e10b93dSalc 	uint16_t eeval;
10191e10b93dSalc 	uint32_t off;
10201e10b93dSalc 	int i, j;
10211e10b93dSalc 
10221e10b93dSalc 	rep = ee->ee_rdEdgesPower;
10231e10b93dSalc 
10241e10b93dSalc 	off = GROUP8_OFFSET +
10251e10b93dSalc 		(ee->ee_version >= AR_EEPROM_VER4_0 ?
10261e10b93dSalc 			ee->ee_targetPowersStart - GROUP5_OFFSET :
10271e10b93dSalc 	         ee->ee_version >= AR_EEPROM_VER3_3 ?
10281e10b93dSalc 			GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2);
10291e10b93dSalc 	for (i = 0; i < ee->ee_numCtls; i++) {
10301e10b93dSalc 		if (ee->ee_ctl[i] == 0) {
10311e10b93dSalc 			/* Move offset and edges */
10321e10b93dSalc 			off += (ee->ee_version >= AR_EEPROM_VER3_3 ? 8 : 7);
10331e10b93dSalc 			rep += NUM_EDGES;
10341e10b93dSalc 			continue;
10351e10b93dSalc 		}
10361e10b93dSalc 		if (ee->ee_version >= AR_EEPROM_VER3_3) {
10371e10b93dSalc 			for (j = 0; j < NUM_EDGES; j += 2) {
10381e10b93dSalc 				EEREAD(off++);
10391e10b93dSalc 				rep[j].rdEdge = (eeval >> 8) & FREQ_MASK_3_3;
10401e10b93dSalc 				rep[j+1].rdEdge = eeval & FREQ_MASK_3_3;
10411e10b93dSalc 			}
10421e10b93dSalc 			for (j = 0; j < NUM_EDGES; j += 2) {
10431e10b93dSalc 				EEREAD(off++);
10441e10b93dSalc 				rep[j].twice_rdEdgePower =
10451e10b93dSalc 					(eeval >> 8) & POWER_MASK;
10461e10b93dSalc 				rep[j].flag = (eeval >> 14) & 1;
10471e10b93dSalc 				rep[j+1].twice_rdEdgePower = eeval & POWER_MASK;
10481e10b93dSalc 				rep[j+1].flag = (eeval >> 6) & 1;
10491e10b93dSalc 			}
10501e10b93dSalc 		} else {
10511e10b93dSalc 			EEREAD(off++);
10521e10b93dSalc 			rep[0].rdEdge = (eeval >> 9) & FREQ_MASK;
10531e10b93dSalc 			rep[1].rdEdge = (eeval >> 2) & FREQ_MASK;
10541e10b93dSalc 			rep[2].rdEdge = (eeval << 5) & FREQ_MASK;
10551e10b93dSalc 
10561e10b93dSalc 			EEREAD(off++);
10571e10b93dSalc 			rep[2].rdEdge |= (eeval >> 11) & 0x1f;
10581e10b93dSalc 			rep[3].rdEdge = (eeval >> 4) & FREQ_MASK;
10591e10b93dSalc 			rep[4].rdEdge = (eeval << 3) & FREQ_MASK;
10601e10b93dSalc 
10611e10b93dSalc 			EEREAD(off++);
10621e10b93dSalc 			rep[4].rdEdge |= (eeval >> 13) & 0x7;
10631e10b93dSalc 			rep[5].rdEdge = (eeval >> 6) & FREQ_MASK;
10641e10b93dSalc 			rep[6].rdEdge = (eeval << 1) & FREQ_MASK;
10651e10b93dSalc 
10661e10b93dSalc 			EEREAD(off++);
10671e10b93dSalc 			rep[6].rdEdge |= (eeval >> 15) & 0x1;
10681e10b93dSalc 			rep[7].rdEdge = (eeval >> 8) & FREQ_MASK;
10691e10b93dSalc 
10701e10b93dSalc 			rep[0].twice_rdEdgePower = (eeval >> 2) & POWER_MASK;
10711e10b93dSalc 			rep[1].twice_rdEdgePower = (eeval << 4) & POWER_MASK;
10721e10b93dSalc 
10731e10b93dSalc 			EEREAD(off++);
10741e10b93dSalc 			rep[1].twice_rdEdgePower |= (eeval >> 12) & 0xf;
10751e10b93dSalc 			rep[2].twice_rdEdgePower = (eeval >> 6) & POWER_MASK;
10761e10b93dSalc 			rep[3].twice_rdEdgePower = eeval & POWER_MASK;
10771e10b93dSalc 
10781e10b93dSalc 			EEREAD(off++);
10791e10b93dSalc 			rep[4].twice_rdEdgePower = (eeval >> 10) & POWER_MASK;
10801e10b93dSalc 			rep[5].twice_rdEdgePower = (eeval >> 4) & POWER_MASK;
10811e10b93dSalc 			rep[6].twice_rdEdgePower = (eeval << 2) & POWER_MASK;
10821e10b93dSalc 
10831e10b93dSalc 			EEREAD(off++);
10841e10b93dSalc 			rep[6].twice_rdEdgePower |= (eeval >> 14) & 0x3;
10851e10b93dSalc 			rep[7].twice_rdEdgePower = (eeval >> 8) & POWER_MASK;
10861e10b93dSalc 		}
10871e10b93dSalc 
10881e10b93dSalc 		for (j = 0; j < NUM_EDGES; j++ ) {
10891e10b93dSalc 			if (rep[j].rdEdge != 0 || rep[j].twice_rdEdgePower != 0) {
10901e10b93dSalc 				if ((ee->ee_ctl[i] & CTL_MODE_M) == CTL_11A ||
10911e10b93dSalc 				    (ee->ee_ctl[i] & CTL_MODE_M) == CTL_TURBO) {
10921e10b93dSalc 					rep[j].rdEdge = fbin2freq(ee, rep[j].rdEdge);
10931e10b93dSalc 				} else {
10941e10b93dSalc 					rep[j].rdEdge = fbin2freq_2p4(ee, rep[j].rdEdge);
10951e10b93dSalc 				}
10961e10b93dSalc 			}
10971e10b93dSalc 		}
10981e10b93dSalc 		rep += NUM_EDGES;
10991e10b93dSalc 	}
11001e10b93dSalc 	return AH_TRUE;
11011e10b93dSalc #undef EEREAD
11021e10b93dSalc }
11031e10b93dSalc 
11041e10b93dSalc /*
11051e10b93dSalc  * Read the individual header fields for a Rev 3 EEPROM
11061e10b93dSalc  */
11071e10b93dSalc static HAL_BOOL
readHeaderInfo(struct ath_hal * ah,HAL_EEPROM * ee)11081e10b93dSalc readHeaderInfo(struct ath_hal *ah, HAL_EEPROM *ee)
11091e10b93dSalc {
11101e10b93dSalc #define	EEREAD(_off) do {				\
11111e10b93dSalc 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
11121e10b93dSalc 		return AH_FALSE;			\
11131e10b93dSalc } while (0)
11141e10b93dSalc 	static const uint32_t headerOffset3_0[] = {
11151e10b93dSalc 		0x00C2, /* 0 - Mode bits, device type, max turbo power */
11161e10b93dSalc 		0x00C4, /* 1 - 2.4 and 5 antenna gain */
11171e10b93dSalc 		0x00C5, /* 2 - Begin 11A modal section */
11181e10b93dSalc 		0x00D0, /* 3 - Begin 11B modal section */
11191e10b93dSalc 		0x00DA, /* 4 - Begin 11G modal section */
11201e10b93dSalc 		0x00E4  /* 5 - Begin CTL section */
11211e10b93dSalc 	};
11221e10b93dSalc 	static const uint32_t headerOffset3_3[] = {
11231e10b93dSalc 		0x00C2, /* 0 - Mode bits, device type, max turbo power */
11241e10b93dSalc 		0x00C3, /* 1 - 2.4 and 5 antenna gain */
11251e10b93dSalc 		0x00D4, /* 2 - Begin 11A modal section */
11261e10b93dSalc 		0x00F2, /* 3 - Begin 11B modal section */
11271e10b93dSalc 		0x010D, /* 4 - Begin 11G modal section */
11281e10b93dSalc 		0x0128  /* 5 - Begin CTL section */
11291e10b93dSalc 	};
11301e10b93dSalc 
11311e10b93dSalc 	static const uint32_t regCapOffsetPre4_0 = 0x00CF;
11321e10b93dSalc 	static const uint32_t regCapOffsetPost4_0 = 0x00CA;
11331e10b93dSalc 
11341e10b93dSalc 	const uint32_t *header;
11351e10b93dSalc 	uint32_t off;
11361e10b93dSalc 	uint16_t eeval;
11371e10b93dSalc 	int i;
11381e10b93dSalc 
11391e10b93dSalc 	/* initialize cckOfdmGainDelta for < 4.2 eeprom */
11401e10b93dSalc 	ee->ee_cckOfdmGainDelta = CCK_OFDM_GAIN_DELTA;
11411e10b93dSalc 	ee->ee_scaledCh14FilterCckDelta = TENX_CH14_FILTER_CCK_DELTA_INIT;
11421e10b93dSalc 
11431e10b93dSalc 	if (ee->ee_version >= AR_EEPROM_VER3_3) {
11441e10b93dSalc 		header = headerOffset3_3;
11451e10b93dSalc 		ee->ee_numCtls = NUM_CTLS_3_3;
11461e10b93dSalc 	} else {
11471e10b93dSalc 		header = headerOffset3_0;
11481e10b93dSalc 		ee->ee_numCtls = NUM_CTLS;
11491e10b93dSalc 	}
11501e10b93dSalc 	HALASSERT(ee->ee_numCtls <= NUM_CTLS_MAX);
11511e10b93dSalc 
11521e10b93dSalc 	EEREAD(header[0]);
11531e10b93dSalc 	ee->ee_turbo5Disable	= (eeval >> 15) & 0x01;
11541e10b93dSalc 	ee->ee_rfKill		= (eeval >> 14) & 0x01;
11551e10b93dSalc 	ee->ee_deviceType	= (eeval >> 11) & 0x07;
11561e10b93dSalc 	ee->ee_turbo2WMaxPower5	= (eeval >> 4) & 0x7F;
11571e10b93dSalc 	if (ee->ee_version >= AR_EEPROM_VER4_0)
11581e10b93dSalc 		ee->ee_turbo2Disable	= (eeval >> 3) & 0x01;
11591e10b93dSalc 	else
11601e10b93dSalc 		ee->ee_turbo2Disable	= 1;
11611e10b93dSalc 	ee->ee_Gmode		= (eeval >> 2) & 0x01;
11621e10b93dSalc 	ee->ee_Bmode		= (eeval >> 1) & 0x01;
11631e10b93dSalc 	ee->ee_Amode		= (eeval & 0x01);
11641e10b93dSalc 
11651e10b93dSalc 	off = header[1];
11661e10b93dSalc 	EEREAD(off++);
11671e10b93dSalc 	ee->ee_antennaGainMax[0] = (int8_t)((eeval >> 8) & 0xFF);
11681e10b93dSalc 	ee->ee_antennaGainMax[1] = (int8_t)(eeval & 0xFF);
11691e10b93dSalc 	if (ee->ee_version >= AR_EEPROM_VER4_0) {
11701e10b93dSalc 		EEREAD(off++);
11711e10b93dSalc 		ee->ee_eepMap		 = (eeval>>14) & 0x3;
11721e10b93dSalc 		ee->ee_disableXr5	 = (eeval>>13) & 0x1;
11731e10b93dSalc 		ee->ee_disableXr2	 = (eeval>>12) & 0x1;
11741e10b93dSalc 		ee->ee_earStart		 = eeval & 0xfff;
11751e10b93dSalc 
11761e10b93dSalc 		EEREAD(off++);
11771e10b93dSalc 		ee->ee_targetPowersStart = eeval & 0xfff;
11781e10b93dSalc 		ee->ee_exist32kHzCrystal = (eeval>>14) & 0x1;
11791e10b93dSalc 
11801e10b93dSalc 		if (ee->ee_version >= AR_EEPROM_VER5_0) {
11811e10b93dSalc 			off += 2;
11821e10b93dSalc 			EEREAD(off);
11831e10b93dSalc 			ee->ee_eepMap2PowerCalStart = (eeval >> 4) & 0xfff;
11841e10b93dSalc 			/* Properly cal'ed 5.0 devices should be non-zero */
11851e10b93dSalc 		}
11861e10b93dSalc 	}
11871e10b93dSalc 
11881e10b93dSalc 	/* Read the moded sections of the EEPROM header in the order A, B, G */
11891e10b93dSalc 	for (i = headerInfo11A; i <= headerInfo11G; i++) {
11901e10b93dSalc 		/* Set the offset via the index */
11911e10b93dSalc 		off = header[2 + i];
11921e10b93dSalc 
11931e10b93dSalc 		EEREAD(off++);
11941e10b93dSalc 		ee->ee_switchSettling[i] = (eeval >> 8) & 0x7f;
11951e10b93dSalc 		ee->ee_txrxAtten[i] = (eeval >> 2) & 0x3f;
11961e10b93dSalc 		ee->ee_antennaControl[0][i] = (eeval << 4) & 0x3f;
11971e10b93dSalc 
11981e10b93dSalc 		EEREAD(off++);
11991e10b93dSalc 		ee->ee_antennaControl[0][i] |= (eeval >> 12) & 0x0f;
12001e10b93dSalc 		ee->ee_antennaControl[1][i] = (eeval >> 6) & 0x3f;
12011e10b93dSalc 		ee->ee_antennaControl[2][i] = eeval & 0x3f;
12021e10b93dSalc 
12031e10b93dSalc 		EEREAD(off++);
12041e10b93dSalc 		ee->ee_antennaControl[3][i] = (eeval >> 10)  & 0x3f;
12051e10b93dSalc 		ee->ee_antennaControl[4][i] = (eeval >> 4)  & 0x3f;
12061e10b93dSalc 		ee->ee_antennaControl[5][i] = (eeval << 2)  & 0x3f;
12071e10b93dSalc 
12081e10b93dSalc 		EEREAD(off++);
12091e10b93dSalc 		ee->ee_antennaControl[5][i] |= (eeval >> 14)  & 0x03;
12101e10b93dSalc 		ee->ee_antennaControl[6][i] = (eeval >> 8)  & 0x3f;
12111e10b93dSalc 		ee->ee_antennaControl[7][i] = (eeval >> 2)  & 0x3f;
12121e10b93dSalc 		ee->ee_antennaControl[8][i] = (eeval << 4)  & 0x3f;
12131e10b93dSalc 
12141e10b93dSalc 		EEREAD(off++);
12151e10b93dSalc 		ee->ee_antennaControl[8][i] |= (eeval >> 12)  & 0x0f;
12161e10b93dSalc 		ee->ee_antennaControl[9][i] = (eeval >> 6)  & 0x3f;
12171e10b93dSalc 		ee->ee_antennaControl[10][i] = eeval & 0x3f;
12181e10b93dSalc 
12191e10b93dSalc 		EEREAD(off++);
12201e10b93dSalc 		ee->ee_adcDesiredSize[i] = (int8_t)((eeval >> 8)  & 0xff);
12211e10b93dSalc 		switch (i) {
12221e10b93dSalc 		case headerInfo11A:
12231e10b93dSalc 			ee->ee_ob4 = (eeval >> 5)  & 0x07;
12241e10b93dSalc 			ee->ee_db4 = (eeval >> 2)  & 0x07;
12251e10b93dSalc 			ee->ee_ob3 = (eeval << 1)  & 0x07;
12261e10b93dSalc 			break;
12271e10b93dSalc 		case headerInfo11B:
12281e10b93dSalc 			ee->ee_obFor24 = (eeval >> 4)  & 0x07;
12291e10b93dSalc 			ee->ee_dbFor24 = eeval & 0x07;
12301e10b93dSalc 			break;
12311e10b93dSalc 		case headerInfo11G:
12321e10b93dSalc 			ee->ee_obFor24g = (eeval >> 4)  & 0x07;
12331e10b93dSalc 			ee->ee_dbFor24g = eeval & 0x07;
12341e10b93dSalc 			break;
12351e10b93dSalc 		}
12361e10b93dSalc 
12371e10b93dSalc 		if (i == headerInfo11A) {
12381e10b93dSalc 			EEREAD(off++);
12391e10b93dSalc 			ee->ee_ob3 |= (eeval >> 15)  & 0x01;
12401e10b93dSalc 			ee->ee_db3 = (eeval >> 12)  & 0x07;
12411e10b93dSalc 			ee->ee_ob2 = (eeval >> 9)  & 0x07;
12421e10b93dSalc 			ee->ee_db2 = (eeval >> 6)  & 0x07;
12431e10b93dSalc 			ee->ee_ob1 = (eeval >> 3)  & 0x07;
12441e10b93dSalc 			ee->ee_db1 = eeval & 0x07;
12451e10b93dSalc 		}
12461e10b93dSalc 
12471e10b93dSalc 		EEREAD(off++);
12481e10b93dSalc 		ee->ee_txEndToXLNAOn[i] = (eeval >> 8)  & 0xff;
12491e10b93dSalc 		ee->ee_thresh62[i] = eeval & 0xff;
12501e10b93dSalc 
12511e10b93dSalc 		EEREAD(off++);
12521e10b93dSalc 		ee->ee_txEndToXPAOff[i] = (eeval >> 8)  & 0xff;
12531e10b93dSalc 		ee->ee_txFrameToXPAOn[i] = eeval  & 0xff;
12541e10b93dSalc 
12551e10b93dSalc 		EEREAD(off++);
12561e10b93dSalc 		ee->ee_pgaDesiredSize[i] = (int8_t)((eeval >> 8)  & 0xff);
12571e10b93dSalc 		ee->ee_noiseFloorThresh[i] = eeval  & 0xff;
12581e10b93dSalc 		if (ee->ee_noiseFloorThresh[i] & 0x80) {
12591e10b93dSalc 			ee->ee_noiseFloorThresh[i] = 0 -
12601e10b93dSalc 				((ee->ee_noiseFloorThresh[i] ^ 0xff) + 1);
12611e10b93dSalc 		}
12621e10b93dSalc 
12631e10b93dSalc 		EEREAD(off++);
12641e10b93dSalc 		ee->ee_xlnaGain[i] = (eeval >> 5)  & 0xff;
12651e10b93dSalc 		ee->ee_xgain[i] = (eeval >> 1)  & 0x0f;
12661e10b93dSalc 		ee->ee_xpd[i] = eeval  & 0x01;
12671e10b93dSalc 		if (ee->ee_version >= AR_EEPROM_VER4_0) {
12681e10b93dSalc 			switch (i) {
12691e10b93dSalc 			case headerInfo11A:
12701e10b93dSalc 				ee->ee_fixedBias5 = (eeval >> 13) & 0x1;
12711e10b93dSalc 				break;
12721e10b93dSalc 			case headerInfo11G:
12731e10b93dSalc 				ee->ee_fixedBias2 = (eeval >> 13) & 0x1;
12741e10b93dSalc 				break;
12751e10b93dSalc 			}
12761e10b93dSalc 		}
12771e10b93dSalc 
12781e10b93dSalc 		if (ee->ee_version >= AR_EEPROM_VER3_3) {
12791e10b93dSalc 			EEREAD(off++);
12801e10b93dSalc 			ee->ee_falseDetectBackoff[i] = (eeval >> 6) & 0x7F;
12811e10b93dSalc 			switch (i) {
12821e10b93dSalc 			case headerInfo11B:
12831e10b93dSalc 				ee->ee_ob2GHz[0] = eeval & 0x7;
12841e10b93dSalc 				ee->ee_db2GHz[0] = (eeval >> 3) & 0x7;
12851e10b93dSalc 				break;
12861e10b93dSalc 			case headerInfo11G:
12871e10b93dSalc 				ee->ee_ob2GHz[1] = eeval & 0x7;
12881e10b93dSalc 				ee->ee_db2GHz[1] = (eeval >> 3) & 0x7;
12891e10b93dSalc 				break;
12901e10b93dSalc 			case headerInfo11A:
12911e10b93dSalc 				ee->ee_xrTargetPower5 = eeval & 0x3f;
12921e10b93dSalc 				break;
12931e10b93dSalc 			}
12941e10b93dSalc 		}
12951e10b93dSalc 		if (ee->ee_version >= AR_EEPROM_VER3_4) {
12961e10b93dSalc 			ee->ee_gainI[i] = (eeval >> 13) & 0x07;
12971e10b93dSalc 
12981e10b93dSalc 			EEREAD(off++);
12991e10b93dSalc 			ee->ee_gainI[i] |= (eeval << 3) & 0x38;
13001e10b93dSalc 			if (i == headerInfo11G) {
13011e10b93dSalc 				ee->ee_cckOfdmPwrDelta = (eeval >> 3) & 0xFF;
13021e10b93dSalc 				if (ee->ee_version >= AR_EEPROM_VER4_6)
13031e10b93dSalc 					ee->ee_scaledCh14FilterCckDelta =
13041e10b93dSalc 						(eeval >> 11) & 0x1f;
13051e10b93dSalc 			}
13061e10b93dSalc 			if (i == headerInfo11A &&
13071e10b93dSalc 			    ee->ee_version >= AR_EEPROM_VER4_0) {
13081e10b93dSalc 				ee->ee_iqCalI[0] = (eeval >> 8 ) & 0x3f;
13091e10b93dSalc 				ee->ee_iqCalQ[0] = (eeval >> 3 ) & 0x1f;
13101e10b93dSalc 			}
13111e10b93dSalc 		} else {
13121e10b93dSalc 			ee->ee_gainI[i] = 10;
13131e10b93dSalc 			ee->ee_cckOfdmPwrDelta = TENX_OFDM_CCK_DELTA_INIT;
13141e10b93dSalc 		}
13151e10b93dSalc 		if (ee->ee_version >= AR_EEPROM_VER4_0) {
13161e10b93dSalc 			switch (i) {
13171e10b93dSalc 			case headerInfo11B:
13181e10b93dSalc 				EEREAD(off++);
13191e10b93dSalc 				ee->ee_calPier11b[0] =
13201e10b93dSalc 					fbin2freq_2p4(ee, eeval&0xff);
13211e10b93dSalc 				ee->ee_calPier11b[1] =
13221e10b93dSalc 					fbin2freq_2p4(ee, (eeval >> 8)&0xff);
13231e10b93dSalc 				EEREAD(off++);
13241e10b93dSalc 				ee->ee_calPier11b[2] =
13251e10b93dSalc 					fbin2freq_2p4(ee, eeval&0xff);
13261e10b93dSalc 				if (ee->ee_version >= AR_EEPROM_VER4_1)
13271e10b93dSalc 					ee->ee_rxtxMargin[headerInfo11B] =
13281e10b93dSalc 						(eeval >> 8) & 0x3f;
13291e10b93dSalc 				break;
13301e10b93dSalc 			case headerInfo11G:
13311e10b93dSalc 				EEREAD(off++);
13321e10b93dSalc 				ee->ee_calPier11g[0] =
13331e10b93dSalc 					fbin2freq_2p4(ee, eeval & 0xff);
13341e10b93dSalc 				ee->ee_calPier11g[1] =
13351e10b93dSalc 					fbin2freq_2p4(ee, (eeval >> 8) & 0xff);
13361e10b93dSalc 
13371e10b93dSalc 				EEREAD(off++);
13381e10b93dSalc 				ee->ee_turbo2WMaxPower2 = eeval & 0x7F;
13391e10b93dSalc 				ee->ee_xrTargetPower2 = (eeval >> 7) & 0x3f;
13401e10b93dSalc 
13411e10b93dSalc 				EEREAD(off++);
13421e10b93dSalc 				ee->ee_calPier11g[2] =
13431e10b93dSalc 					fbin2freq_2p4(ee, eeval & 0xff);
13441e10b93dSalc 				if (ee->ee_version >= AR_EEPROM_VER4_1)
13451e10b93dSalc 					 ee->ee_rxtxMargin[headerInfo11G] =
13461e10b93dSalc 						(eeval >> 8) & 0x3f;
13471e10b93dSalc 
13481e10b93dSalc 				EEREAD(off++);
13491e10b93dSalc 				ee->ee_iqCalI[1] = (eeval >> 5) & 0x3F;
13501e10b93dSalc 				ee->ee_iqCalQ[1] = eeval & 0x1F;
13511e10b93dSalc 
13521e10b93dSalc 				if (ee->ee_version >= AR_EEPROM_VER4_2) {
13531e10b93dSalc 					EEREAD(off++);
13541e10b93dSalc 					ee->ee_cckOfdmGainDelta =
13551e10b93dSalc 						(uint8_t)(eeval & 0xFF);
13561e10b93dSalc 					if (ee->ee_version >= AR_EEPROM_VER5_0) {
13571e10b93dSalc 						ee->ee_switchSettlingTurbo[1] =
13581e10b93dSalc 							(eeval >> 8) & 0x7f;
13591e10b93dSalc 						ee->ee_txrxAttenTurbo[1] =
13601e10b93dSalc 							(eeval >> 15) & 0x1;
13611e10b93dSalc 						EEREAD(off++);
13621e10b93dSalc 						ee->ee_txrxAttenTurbo[1] |=
13631e10b93dSalc 							(eeval & 0x1F) << 1;
13641e10b93dSalc 						ee->ee_rxtxMarginTurbo[1] =
13651e10b93dSalc 							(eeval >> 5) & 0x3F;
13661e10b93dSalc 						ee->ee_adcDesiredSizeTurbo[1] =
13671e10b93dSalc 							(eeval >> 11) & 0x1F;
13681e10b93dSalc 						EEREAD(off++);
13691e10b93dSalc 						ee->ee_adcDesiredSizeTurbo[1] |=
13701e10b93dSalc 							(eeval & 0x7) << 5;
13711e10b93dSalc 						ee->ee_pgaDesiredSizeTurbo[1] =
13721e10b93dSalc 							(eeval >> 3) & 0xFF;
13731e10b93dSalc 					}
13741e10b93dSalc 				}
13751e10b93dSalc 				break;
13761e10b93dSalc 			case headerInfo11A:
13771e10b93dSalc 				if (ee->ee_version >= AR_EEPROM_VER4_1) {
13781e10b93dSalc 					EEREAD(off++);
13791e10b93dSalc 					ee->ee_rxtxMargin[headerInfo11A] =
13801e10b93dSalc 						eeval & 0x3f;
13811e10b93dSalc 					if (ee->ee_version >= AR_EEPROM_VER5_0) {
13821e10b93dSalc 						ee->ee_switchSettlingTurbo[0] =
13831e10b93dSalc 							(eeval >> 6) & 0x7f;
13841e10b93dSalc 						ee->ee_txrxAttenTurbo[0] =
13851e10b93dSalc 							(eeval >> 13) & 0x7;
13861e10b93dSalc 						EEREAD(off++);
13871e10b93dSalc 						ee->ee_txrxAttenTurbo[0] |=
13881e10b93dSalc 							(eeval & 0x7) << 3;
13891e10b93dSalc 						ee->ee_rxtxMarginTurbo[0] =
13901e10b93dSalc 							(eeval >> 3) & 0x3F;
13911e10b93dSalc 						ee->ee_adcDesiredSizeTurbo[0] =
13921e10b93dSalc 							(eeval >> 9) & 0x7F;
13931e10b93dSalc 						EEREAD(off++);
13941e10b93dSalc 						ee->ee_adcDesiredSizeTurbo[0] |=
13951e10b93dSalc 							(eeval & 0x1) << 7;
13961e10b93dSalc 						ee->ee_pgaDesiredSizeTurbo[0] =
13971e10b93dSalc 							(eeval >> 1) & 0xFF;
13981e10b93dSalc 					}
13991e10b93dSalc 				}
14001e10b93dSalc 				break;
14011e10b93dSalc 			}
14021e10b93dSalc 		}
14031e10b93dSalc 	}
14041e10b93dSalc 	if (ee->ee_version < AR_EEPROM_VER3_3) {
14051e10b93dSalc 		/* Version 3.1+ specific parameters */
14061e10b93dSalc 		EEREAD(0xec);
14071e10b93dSalc 		ee->ee_ob2GHz[0] = eeval & 0x7;
14081e10b93dSalc 		ee->ee_db2GHz[0] = (eeval >> 3) & 0x7;
14091e10b93dSalc 
14101e10b93dSalc 		EEREAD(0xed);
14111e10b93dSalc 		ee->ee_ob2GHz[1] = eeval & 0x7;
14121e10b93dSalc 		ee->ee_db2GHz[1] = (eeval >> 3) & 0x7;
14131e10b93dSalc 	}
14141e10b93dSalc 
14151e10b93dSalc 	/* Initialize corner cal (thermal tx gain adjust parameters) */
14161e10b93dSalc 	ee->ee_cornerCal.clip = 4;
14171e10b93dSalc 	ee->ee_cornerCal.pd90 = 1;
14181e10b93dSalc 	ee->ee_cornerCal.pd84 = 1;
14191e10b93dSalc 	ee->ee_cornerCal.gSel = 0;
14201e10b93dSalc 
14211e10b93dSalc 	/*
14221e10b93dSalc 	* Read the conformance test limit identifiers
14231e10b93dSalc 	* These are used to match regulatory domain testing needs with
14241e10b93dSalc 	* the RD-specific tests that have been calibrated in the EEPROM.
14251e10b93dSalc 	*/
14261e10b93dSalc 	off = header[5];
14271e10b93dSalc 	for (i = 0; i < ee->ee_numCtls; i += 2) {
14281e10b93dSalc 		EEREAD(off++);
14291e10b93dSalc 		ee->ee_ctl[i] = (eeval >> 8) & 0xff;
14301e10b93dSalc 		ee->ee_ctl[i+1] = eeval & 0xff;
14311e10b93dSalc 	}
14321e10b93dSalc 
14331e10b93dSalc 	if (ee->ee_version < AR_EEPROM_VER5_3) {
14341e10b93dSalc 		/* XXX only for 5413? */
14351e10b93dSalc 		ee->ee_spurChans[0][1] = AR_SPUR_5413_1;
14361e10b93dSalc 		ee->ee_spurChans[1][1] = AR_SPUR_5413_2;
14371e10b93dSalc 		ee->ee_spurChans[2][1] = AR_NO_SPUR;
14381e10b93dSalc 		ee->ee_spurChans[0][0] = AR_NO_SPUR;
14391e10b93dSalc 	} else {
14401e10b93dSalc 		/* Read spur mitigation data */
14411e10b93dSalc 		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
14421e10b93dSalc 			EEREAD(off);
14431e10b93dSalc 			ee->ee_spurChans[i][0] = eeval;
14441e10b93dSalc 			EEREAD(off+AR_EEPROM_MODAL_SPURS);
14451e10b93dSalc 			ee->ee_spurChans[i][1] = eeval;
14461e10b93dSalc 			off++;
14471e10b93dSalc 		}
14481e10b93dSalc 	}
14491e10b93dSalc 
14501e10b93dSalc 	/* for recent changes to NF scale */
14511e10b93dSalc 	if (ee->ee_version <= AR_EEPROM_VER3_2) {
14521e10b93dSalc 		ee->ee_noiseFloorThresh[headerInfo11A] = -54;
14531e10b93dSalc 		ee->ee_noiseFloorThresh[headerInfo11B] = -1;
14541e10b93dSalc 		ee->ee_noiseFloorThresh[headerInfo11G] = -1;
14551e10b93dSalc 	}
14561e10b93dSalc 	/* to override thresh62 for better 2.4 and 5 operation */
14571e10b93dSalc 	if (ee->ee_version <= AR_EEPROM_VER3_2) {
14581e10b93dSalc 		ee->ee_thresh62[headerInfo11A] = 15;	/* 11A */
14591e10b93dSalc 		ee->ee_thresh62[headerInfo11B] = 28;	/* 11B */
14601e10b93dSalc 		ee->ee_thresh62[headerInfo11G] = 28;	/* 11G */
14611e10b93dSalc 	}
14621e10b93dSalc 
14631e10b93dSalc 	/* Check for regulatory capabilities */
14641e10b93dSalc 	if (ee->ee_version >= AR_EEPROM_VER4_0) {
14651e10b93dSalc 		EEREAD(regCapOffsetPost4_0);
14661e10b93dSalc 	} else {
14671e10b93dSalc 		EEREAD(regCapOffsetPre4_0);
14681e10b93dSalc 	}
14691e10b93dSalc 
14701e10b93dSalc 	ee->ee_regCap = eeval;
14711e10b93dSalc 
14721e10b93dSalc 	if (ee->ee_Amode == 0) {
14731e10b93dSalc 		/* Check for valid Amode in upgraded h/w */
14741e10b93dSalc 		if (ee->ee_version >= AR_EEPROM_VER4_0) {
14751e10b93dSalc 			ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A)?1:0;
14761e10b93dSalc 		} else {
14771e10b93dSalc 			ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0)?1:0;
14781e10b93dSalc 		}
14791e10b93dSalc 	}
14801e10b93dSalc 
14811e10b93dSalc 	if (ee->ee_version >= AR_EEPROM_VER5_1)
14821e10b93dSalc 		EEREAD(AR_EEPROM_CAPABILITIES_OFFSET);
14831e10b93dSalc 	else
14841e10b93dSalc 		eeval = 0;
14851e10b93dSalc 	ee->ee_opCap = eeval;
14861e10b93dSalc 
14871e10b93dSalc 	EEREAD(AR_EEPROM_REG_DOMAIN);
14881e10b93dSalc 	ee->ee_regdomain = eeval;
14891e10b93dSalc 
14901e10b93dSalc 	return AH_TRUE;
14911e10b93dSalc #undef EEREAD
14921e10b93dSalc }
14931e10b93dSalc 
14941e10b93dSalc /*
14951e10b93dSalc  * Now verify and copy EEPROM contents into the allocated space
14961e10b93dSalc  */
14971e10b93dSalc static HAL_BOOL
legacyEepromReadContents(struct ath_hal * ah,HAL_EEPROM * ee)14981e10b93dSalc legacyEepromReadContents(struct ath_hal *ah, HAL_EEPROM *ee)
14991e10b93dSalc {
15001e10b93dSalc 	/* Read the header information here */
15011e10b93dSalc 	if (!readHeaderInfo(ah, ee))
15021e10b93dSalc 		return AH_FALSE;
15031e10b93dSalc #if 0
15041e10b93dSalc 	/* Require 5112 devices to have EEPROM 4.0 EEP_MAP set */
15051e10b93dSalc 	if (IS_5112(ah) && !ee->ee_eepMap) {
15061e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY,
15071e10b93dSalc 		    "%s: 5112 devices must have EEPROM 4.0 with the "
15081e10b93dSalc 		    "EEP_MAP set\n", __func__);
15091e10b93dSalc 		return AH_FALSE;
15101e10b93dSalc 	}
15111e10b93dSalc #endif
15121e10b93dSalc 	/*
15131e10b93dSalc 	 * Group 1: frequency pier locations readback
15141e10b93dSalc 	 * check that the structure has been populated
15151e10b93dSalc 	 * with enough space to hold the channels
15161e10b93dSalc 	 *
15171e10b93dSalc 	 * NOTE: Group 1 contains the 5 GHz channel numbers
15181e10b93dSalc 	 *	 that have dBm->pcdac calibrated information.
15191e10b93dSalc 	 */
15201e10b93dSalc 	if (!readEepromFreqPierInfo(ah, ee))
15211e10b93dSalc 		return AH_FALSE;
15221e10b93dSalc 
15231e10b93dSalc 	/*
15241e10b93dSalc 	 * Group 2:  readback data for all frequency piers
15251e10b93dSalc 	 *
15261e10b93dSalc 	 * NOTE: Group 2 contains the raw power calibration
15271e10b93dSalc 	 *	 information for each of the channels that we
15281e10b93dSalc 	 *	 recorded above.
15291e10b93dSalc 	 */
15301e10b93dSalc 	if (!readEepromRawPowerCalInfo(ah, ee))
15311e10b93dSalc 		return AH_FALSE;
15321e10b93dSalc 
15331e10b93dSalc 	/*
15341e10b93dSalc 	 * Group 5: target power values per rate
15351e10b93dSalc 	 *
15361e10b93dSalc 	 * NOTE: Group 5 contains the recorded maximum power
15371e10b93dSalc 	 *	 in dB that can be attained for the given rate.
15381e10b93dSalc 	 */
15391e10b93dSalc 	/* Read the power per rate info for test channels */
15401e10b93dSalc 	if (!readEepromTargetPowerCalInfo(ah, ee))
15411e10b93dSalc 		return AH_FALSE;
15421e10b93dSalc 
15431e10b93dSalc 	/*
15441e10b93dSalc 	 * Group 8: Conformance Test Limits information
15451e10b93dSalc 	 *
15461e10b93dSalc 	 * NOTE: Group 8 contains the values to limit the
15471e10b93dSalc 	 *	 maximum transmit power value based on any
15481e10b93dSalc 	 *	 band edge violations.
15491e10b93dSalc 	 */
15501e10b93dSalc 	/* Read the RD edge power limits */
15511e10b93dSalc 	return readEepromCTLInfo(ah, ee);
15521e10b93dSalc }
15531e10b93dSalc 
15541e10b93dSalc static HAL_STATUS
legacyEepromGet(struct ath_hal * ah,int param,void * val)15551e10b93dSalc legacyEepromGet(struct ath_hal *ah, int param, void *val)
15561e10b93dSalc {
15571e10b93dSalc 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
15581e10b93dSalc 	uint8_t *macaddr;
15591e10b93dSalc 	uint16_t eeval;
15601e10b93dSalc 	uint32_t sum;
15611e10b93dSalc 	int i;
15621e10b93dSalc 
15631e10b93dSalc 	switch (param) {
15641e10b93dSalc 	case AR_EEP_OPCAP:
15651e10b93dSalc 		*(uint16_t *) val = ee->ee_opCap;
15661e10b93dSalc 		return HAL_OK;
15671e10b93dSalc 	case AR_EEP_REGDMN_0:
15681e10b93dSalc 		*(uint16_t *) val = ee->ee_regdomain;
15691e10b93dSalc 		return HAL_OK;
15701e10b93dSalc 	case AR_EEP_RFSILENT:
15711e10b93dSalc 		if (!ath_hal_eepromRead(ah, AR_EEPROM_RFSILENT, &eeval))
15721e10b93dSalc 			return HAL_EEREAD;
15731e10b93dSalc 		*(uint16_t *) val = eeval;
15741e10b93dSalc 		return HAL_OK;
15751e10b93dSalc 	case AR_EEP_MACADDR:
15761e10b93dSalc 		sum = 0;
15771e10b93dSalc 		macaddr = val;
15781e10b93dSalc 		for (i = 0; i < 3; i++) {
15791e10b93dSalc 			if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(2-i), &eeval)) {
15801e10b93dSalc 				HALDEBUG(ah, HAL_DEBUG_ANY,
15811e10b93dSalc 				    "%s: cannot read EEPROM location %u\n",
15821e10b93dSalc 				    __func__, i);
15831e10b93dSalc 				return HAL_EEREAD;
15841e10b93dSalc 			}
15851e10b93dSalc 			sum += eeval;
15861e10b93dSalc 			macaddr[2*i] = eeval >> 8;
15871e10b93dSalc 			macaddr[2*i + 1] = eeval & 0xff;
15881e10b93dSalc 		}
15891e10b93dSalc 		if (sum == 0 || sum == 0xffff*3) {
15901e10b93dSalc 			HALDEBUG(ah, HAL_DEBUG_ANY,
15911e10b93dSalc 			    "%s: mac address read failed: %s\n", __func__,
15921e10b93dSalc 			    ath_hal_ether_sprintf(macaddr));
15931e10b93dSalc 			return HAL_EEBADMAC;
15941e10b93dSalc 		}
15951e10b93dSalc 		return HAL_OK;
15961e10b93dSalc 	case AR_EEP_RFKILL:
15971e10b93dSalc 		HALASSERT(val == AH_NULL);
15981e10b93dSalc 		return ee->ee_rfKill ? HAL_OK : HAL_EIO;
15991e10b93dSalc 	case AR_EEP_AMODE:
16001e10b93dSalc 		HALASSERT(val == AH_NULL);
16011e10b93dSalc 		return ee->ee_Amode ? HAL_OK : HAL_EIO;
16021e10b93dSalc 	case AR_EEP_BMODE:
16031e10b93dSalc 		HALASSERT(val == AH_NULL);
16041e10b93dSalc 		return ee->ee_Bmode ? HAL_OK : HAL_EIO;
16051e10b93dSalc 	case AR_EEP_GMODE:
16061e10b93dSalc 		HALASSERT(val == AH_NULL);
16071e10b93dSalc 		return ee->ee_Gmode ? HAL_OK : HAL_EIO;
16081e10b93dSalc 	case AR_EEP_TURBO5DISABLE:
16091e10b93dSalc 		HALASSERT(val == AH_NULL);
16101e10b93dSalc 		return ee->ee_turbo5Disable ? HAL_OK : HAL_EIO;
16111e10b93dSalc 	case AR_EEP_TURBO2DISABLE:
16121e10b93dSalc 		HALASSERT(val == AH_NULL);
16131e10b93dSalc 		return ee->ee_turbo2Disable ? HAL_OK : HAL_EIO;
16141e10b93dSalc 	case AR_EEP_ISTALON:		/* Talon detect */
16151e10b93dSalc 		HALASSERT(val == AH_NULL);
16161e10b93dSalc 		return (ee->ee_version >= AR_EEPROM_VER5_4 &&
16171e10b93dSalc 		    ath_hal_eepromRead(ah, 0x0b, &eeval) && eeval == 1) ?
16181e10b93dSalc 			HAL_OK : HAL_EIO;
16191e10b93dSalc 	case AR_EEP_32KHZCRYSTAL:
16201e10b93dSalc 		HALASSERT(val == AH_NULL);
16211e10b93dSalc 		return ee->ee_exist32kHzCrystal ? HAL_OK : HAL_EIO;
16221e10b93dSalc 	case AR_EEP_COMPRESS:
16231e10b93dSalc 		HALASSERT(val == AH_NULL);
16241e10b93dSalc 		return (ee->ee_opCap & AR_EEPROM_EEPCAP_COMPRESS_DIS) == 0 ?
16251e10b93dSalc 		    HAL_OK : HAL_EIO;
16261e10b93dSalc 	case AR_EEP_FASTFRAME:
16271e10b93dSalc 		HALASSERT(val == AH_NULL);
16281e10b93dSalc 		return (ee->ee_opCap & AR_EEPROM_EEPCAP_FASTFRAME_DIS) == 0 ?
16291e10b93dSalc 		    HAL_OK : HAL_EIO;
16301e10b93dSalc 	case AR_EEP_AES:
16311e10b93dSalc 		HALASSERT(val == AH_NULL);
16321e10b93dSalc 		return (ee->ee_opCap & AR_EEPROM_EEPCAP_AES_DIS) == 0 ?
16331e10b93dSalc 		    HAL_OK : HAL_EIO;
16341e10b93dSalc 	case AR_EEP_BURST:
16351e10b93dSalc 		HALASSERT(val == AH_NULL);
16361e10b93dSalc 		return (ee->ee_opCap & AR_EEPROM_EEPCAP_BURST_DIS) == 0 ?
16371e10b93dSalc 		    HAL_OK : HAL_EIO;
16381e10b93dSalc 	case AR_EEP_MAXQCU:
16391e10b93dSalc 		if (ee->ee_opCap & AR_EEPROM_EEPCAP_MAXQCU) {
16401e10b93dSalc 			*(uint16_t *) val =
16411e10b93dSalc 			    MS(ee->ee_opCap, AR_EEPROM_EEPCAP_MAXQCU);
16421e10b93dSalc 			return HAL_OK;
16431e10b93dSalc 		} else
16441e10b93dSalc 			return HAL_EIO;
16451e10b93dSalc 	case AR_EEP_KCENTRIES:
16461e10b93dSalc 		if (ee->ee_opCap & AR_EEPROM_EEPCAP_KC_ENTRIES) {
16471e10b93dSalc 			*(uint16_t *) val =
16481e10b93dSalc 			    1 << MS(ee->ee_opCap, AR_EEPROM_EEPCAP_KC_ENTRIES);
16491e10b93dSalc 			return HAL_OK;
16501e10b93dSalc 		} else
16511e10b93dSalc 			return HAL_EIO;
16521e10b93dSalc 	case AR_EEP_ANTGAINMAX_5:
16531e10b93dSalc 		*(int8_t *) val = ee->ee_antennaGainMax[0];
16541e10b93dSalc 		return HAL_OK;
16551e10b93dSalc 	case AR_EEP_ANTGAINMAX_2:
16561e10b93dSalc 		*(int8_t *) val = ee->ee_antennaGainMax[1];
16571e10b93dSalc 		return HAL_OK;
16581e10b93dSalc 	case AR_EEP_WRITEPROTECT:
16591e10b93dSalc 		HALASSERT(val == AH_NULL);
16601e10b93dSalc 		return (ee->ee_protect & AR_EEPROM_PROTECT_WP_128_191) ?
16611e10b93dSalc 		    HAL_OK : HAL_EIO;
16621e10b93dSalc 	}
16631e10b93dSalc 	return HAL_EINVAL;
16641e10b93dSalc }
16651e10b93dSalc 
16661e10b93dSalc static HAL_BOOL
legacyEepromSet(struct ath_hal * ah,int param,int v)16671e10b93dSalc legacyEepromSet(struct ath_hal *ah, int param, int v)
16681e10b93dSalc {
16691e10b93dSalc 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
16701e10b93dSalc 
16711e10b93dSalc 	switch (param) {
16721e10b93dSalc 	case AR_EEP_AMODE:
16731e10b93dSalc 		ee->ee_Amode = v;
1674*98c00ab4Smrg 		return AH_TRUE;
16751e10b93dSalc 	case AR_EEP_BMODE:
16761e10b93dSalc 		ee->ee_Bmode = v;
1677*98c00ab4Smrg 		return AH_TRUE;
16781e10b93dSalc 	case AR_EEP_GMODE:
16791e10b93dSalc 		ee->ee_Gmode = v;
1680*98c00ab4Smrg 		return AH_TRUE;
16811e10b93dSalc 	case AR_EEP_TURBO5DISABLE:
16821e10b93dSalc 		ee->ee_turbo5Disable = v;
1683*98c00ab4Smrg 		return AH_TRUE;
16841e10b93dSalc 	case AR_EEP_TURBO2DISABLE:
16851e10b93dSalc 		ee->ee_turbo2Disable = v;
1686*98c00ab4Smrg 		return AH_TRUE;
16871e10b93dSalc 	case AR_EEP_COMPRESS:
16881e10b93dSalc 		if (v)
16891e10b93dSalc 			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_COMPRESS_DIS;
16901e10b93dSalc 		else
16911e10b93dSalc 			ee->ee_opCap |= AR_EEPROM_EEPCAP_COMPRESS_DIS;
1692*98c00ab4Smrg 		return AH_TRUE;
16931e10b93dSalc 	case AR_EEP_FASTFRAME:
16941e10b93dSalc 		if (v)
16951e10b93dSalc 			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_FASTFRAME_DIS;
16961e10b93dSalc 		else
16971e10b93dSalc 			ee->ee_opCap |= AR_EEPROM_EEPCAP_FASTFRAME_DIS;
1698*98c00ab4Smrg 		return AH_TRUE;
16991e10b93dSalc 	case AR_EEP_AES:
17001e10b93dSalc 		if (v)
17011e10b93dSalc 			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_AES_DIS;
17021e10b93dSalc 		else
17031e10b93dSalc 			ee->ee_opCap |= AR_EEPROM_EEPCAP_AES_DIS;
1704*98c00ab4Smrg 		return AH_TRUE;
17051e10b93dSalc 	case AR_EEP_BURST:
17061e10b93dSalc 		if (v)
17071e10b93dSalc 			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_BURST_DIS;
17081e10b93dSalc 		else
17091e10b93dSalc 			ee->ee_opCap |= AR_EEPROM_EEPCAP_BURST_DIS;
1710*98c00ab4Smrg 		return AH_TRUE;
17111e10b93dSalc 	}
1712*98c00ab4Smrg 	return AH_FALSE;
17131e10b93dSalc }
17141e10b93dSalc 
17151e10b93dSalc static HAL_BOOL
legacyEepromDiag(struct ath_hal * ah,int request,const void * args,uint32_t argsize,void ** result,uint32_t * resultsize)17161e10b93dSalc legacyEepromDiag(struct ath_hal *ah, int request,
17171e10b93dSalc      const void *args, uint32_t argsize, void **result, uint32_t *resultsize)
17181e10b93dSalc {
17191e10b93dSalc 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
17201e10b93dSalc 	const EEPROM_POWER_EXPN_5112 *pe;
17211e10b93dSalc 
17221e10b93dSalc 	switch (request) {
17231e10b93dSalc 	case HAL_DIAG_EEPROM:
17241e10b93dSalc 		*result = ee;
17251e10b93dSalc 		*resultsize = sizeof(*ee);
17261e10b93dSalc 		return AH_TRUE;
17271e10b93dSalc 	case HAL_DIAG_EEPROM_EXP_11A:
17281e10b93dSalc 	case HAL_DIAG_EEPROM_EXP_11B:
17291e10b93dSalc 	case HAL_DIAG_EEPROM_EXP_11G:
17301e10b93dSalc 		pe = &ee->ee_modePowerArray5112[
17311e10b93dSalc 		    request - HAL_DIAG_EEPROM_EXP_11A];
17321e10b93dSalc 		*result = pe->pChannels;
17331e10b93dSalc 		*resultsize = (*result == AH_NULL) ? 0 :
17341e10b93dSalc 			roundup(sizeof(uint16_t) * pe->numChannels,
17351e10b93dSalc 				sizeof(uint32_t)) +
17361e10b93dSalc 			sizeof(EXPN_DATA_PER_CHANNEL_5112) * pe->numChannels;
17371e10b93dSalc 		return AH_TRUE;
17381e10b93dSalc 	}
17391e10b93dSalc 	return AH_FALSE;
17401e10b93dSalc }
17411e10b93dSalc 
17421e10b93dSalc static uint16_t
legacyEepromGetSpurChan(struct ath_hal * ah,int ix,HAL_BOOL is2GHz)17431e10b93dSalc legacyEepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz)
17441e10b93dSalc {
17451e10b93dSalc 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
17461e10b93dSalc 
17471e10b93dSalc 	HALASSERT(0 <= ix && ix < AR_EEPROM_MODAL_SPURS);
17481e10b93dSalc 	return ee->ee_spurChans[ix][is2GHz];
17491e10b93dSalc }
17501e10b93dSalc 
17511e10b93dSalc /*
17521e10b93dSalc  * Reclaim any EEPROM-related storage.
17531e10b93dSalc  */
17541e10b93dSalc static void
legacyEepromDetach(struct ath_hal * ah)17551e10b93dSalc legacyEepromDetach(struct ath_hal *ah)
17561e10b93dSalc {
17571e10b93dSalc 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
17581e10b93dSalc 
17591e10b93dSalc         if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1)
1760f24695abScegger 		freeEepromRawPowerCalInfo5112(ah, ee);
17611e10b93dSalc 	ath_hal_free(ee);
17621e10b93dSalc 	AH_PRIVATE(ah)->ah_eeprom = AH_NULL;
17631e10b93dSalc }
17641e10b93dSalc 
17651e10b93dSalc /*
17661e10b93dSalc  * These are not valid 2.4 channels, either we change 'em
17671e10b93dSalc  * or we need to change the coding to accept them.
17681e10b93dSalc  */
17691e10b93dSalc static const uint16_t channels11b[] = { 2412, 2447, 2484 };
17701e10b93dSalc static const uint16_t channels11g[] = { 2312, 2412, 2484 };
17711e10b93dSalc 
17721e10b93dSalc HAL_STATUS
ath_hal_legacyEepromAttach(struct ath_hal * ah)17731e10b93dSalc ath_hal_legacyEepromAttach(struct ath_hal *ah)
17741e10b93dSalc {
17751e10b93dSalc 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
17761e10b93dSalc 	uint32_t sum, eepMax;
17771e10b93dSalc 	uint16_t eeversion, eeprotect, eeval;
17781e10b93dSalc 	u_int i;
17791e10b93dSalc 
17801e10b93dSalc 	HALASSERT(ee == AH_NULL);
17811e10b93dSalc 
17821e10b93dSalc 	if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &eeversion)) {
17831e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY,
17841e10b93dSalc 		    "%s: unable to read EEPROM version\n", __func__);
17851e10b93dSalc 		return HAL_EEREAD;
17861e10b93dSalc 	}
17871e10b93dSalc 	if (eeversion < AR_EEPROM_VER3) {
17881e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM version "
17891e10b93dSalc 		    "%u (0x%x) found\n", __func__, eeversion, eeversion);
17901e10b93dSalc 		return HAL_EEVERSION;
17911e10b93dSalc 	}
17921e10b93dSalc 
17931e10b93dSalc 	if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &eeprotect)) {
17941e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read EEPROM protection "
17951e10b93dSalc 		    "bits; read locked?\n", __func__);
17961e10b93dSalc 		return HAL_EEREAD;
17971e10b93dSalc 	}
17981e10b93dSalc 	HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", eeprotect);
17991e10b93dSalc 	/* XXX check proper access before continuing */
18001e10b93dSalc 
18011e10b93dSalc 	/*
18021e10b93dSalc 	 * Read the Atheros EEPROM entries and calculate the checksum.
18031e10b93dSalc 	 */
18041e10b93dSalc 	if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_UPPER, &eeval)) {
18051e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY,
18061e10b93dSalc 		    "%s: cannot read EEPROM upper size\n" , __func__);
18071e10b93dSalc 		return HAL_EEREAD;
18081e10b93dSalc 	}
18091e10b93dSalc 	if (eeval != 0)	{
18101e10b93dSalc 		eepMax = (eeval & AR_EEPROM_SIZE_UPPER_MASK) <<
18111e10b93dSalc 			AR_EEPROM_SIZE_ENDLOC_SHIFT;
18121e10b93dSalc 		if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_LOWER, &eeval)) {
18131e10b93dSalc 			HALDEBUG(ah, HAL_DEBUG_ANY,
18141e10b93dSalc 			    "%s: cannot read EEPROM lower size\n" , __func__);
18151e10b93dSalc 			return HAL_EEREAD;
18161e10b93dSalc 		}
18171e10b93dSalc 		eepMax = (eepMax | eeval) - AR_EEPROM_ATHEROS_BASE;
18181e10b93dSalc 	} else
18191e10b93dSalc 		eepMax = AR_EEPROM_ATHEROS_MAX;
18201e10b93dSalc 	sum = 0;
18211e10b93dSalc 	for (i = 0; i < eepMax; i++) {
18221e10b93dSalc 		if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &eeval)) {
18231e10b93dSalc 			return HAL_EEREAD;
18241e10b93dSalc 		}
18251e10b93dSalc 		sum ^= eeval;
18261e10b93dSalc 	}
18271e10b93dSalc 	if (sum != 0xffff) {
18281e10b93dSalc 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n",
18291e10b93dSalc 		    __func__, sum);
18301e10b93dSalc 		return HAL_EEBADSUM;
18311e10b93dSalc 	}
18321e10b93dSalc 
18331e10b93dSalc 	ee = ath_hal_malloc(sizeof(HAL_EEPROM));
18341e10b93dSalc 	if (ee == AH_NULL) {
18351e10b93dSalc 		/* XXX message */
18361e10b93dSalc 		return HAL_ENOMEM;
18371e10b93dSalc 	}
18381e10b93dSalc 
18391e10b93dSalc 	ee->ee_protect = eeprotect;
18401e10b93dSalc 	ee->ee_version = eeversion;
18411e10b93dSalc 
18421e10b93dSalc 	ee->ee_numChannels11a = NUM_11A_EEPROM_CHANNELS;
18431e10b93dSalc 	ee->ee_numChannels2_4 = NUM_2_4_EEPROM_CHANNELS;
18441e10b93dSalc 
18451e10b93dSalc 	for (i = 0; i < NUM_11A_EEPROM_CHANNELS; i ++)
18461e10b93dSalc 		ee->ee_dataPerChannel11a[i].numPcdacValues = NUM_PCDAC_VALUES;
18471e10b93dSalc 
18481e10b93dSalc 	/* the channel list for 2.4 is fixed, fill this in here */
18491e10b93dSalc 	for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++) {
18501e10b93dSalc 		ee->ee_channels11b[i] = channels11b[i];
18511e10b93dSalc 		/* XXX 5211 requires a hack though we don't support 11g */
18521e10b93dSalc 		if (ah->ah_magic == 0x19570405)
18531e10b93dSalc 			ee->ee_channels11g[i] = channels11b[i];
18541e10b93dSalc 		else
18551e10b93dSalc 			ee->ee_channels11g[i] = channels11g[i];
18561e10b93dSalc 		ee->ee_dataPerChannel11b[i].numPcdacValues = NUM_PCDAC_VALUES;
18571e10b93dSalc 		ee->ee_dataPerChannel11g[i].numPcdacValues = NUM_PCDAC_VALUES;
18581e10b93dSalc 	}
18591e10b93dSalc 
18601e10b93dSalc 	if (!legacyEepromReadContents(ah, ee)) {
18611e10b93dSalc 		/* XXX message */
18621e10b93dSalc 		ath_hal_free(ee);
18631e10b93dSalc 		return HAL_EEREAD;	/* XXX */
18641e10b93dSalc 	}
18651e10b93dSalc 
18661e10b93dSalc 	AH_PRIVATE(ah)->ah_eeprom = ee;
18671e10b93dSalc 	AH_PRIVATE(ah)->ah_eeversion = eeversion;
18681e10b93dSalc 	AH_PRIVATE(ah)->ah_eepromDetach = legacyEepromDetach;
18691e10b93dSalc 	AH_PRIVATE(ah)->ah_eepromGet = legacyEepromGet;
18701e10b93dSalc 	AH_PRIVATE(ah)->ah_eepromSet = legacyEepromSet;
18711e10b93dSalc 	AH_PRIVATE(ah)->ah_getSpurChan = legacyEepromGetSpurChan;
18721e10b93dSalc 	AH_PRIVATE(ah)->ah_eepromDiag = legacyEepromDiag;
18731e10b93dSalc 	return HAL_OK;
18741e10b93dSalc }
1875