xref: /dflybsd-src/sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c (revision 572ff6f6e8b95055988f178b6ba12ce77bb5b3c2)
1*572ff6f6SMatthew Dillon /*
2*572ff6f6SMatthew Dillon  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3*572ff6f6SMatthew Dillon  * Copyright (c) 2002-2008 Atheros Communications, Inc.
4*572ff6f6SMatthew Dillon  *
5*572ff6f6SMatthew Dillon  * Permission to use, copy, modify, and/or distribute this software for any
6*572ff6f6SMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
7*572ff6f6SMatthew Dillon  * copyright notice and this permission notice appear in all copies.
8*572ff6f6SMatthew Dillon  *
9*572ff6f6SMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*572ff6f6SMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*572ff6f6SMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*572ff6f6SMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*572ff6f6SMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*572ff6f6SMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*572ff6f6SMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*572ff6f6SMatthew Dillon  *
17*572ff6f6SMatthew Dillon  * $FreeBSD$
18*572ff6f6SMatthew Dillon  */
19*572ff6f6SMatthew Dillon #include "opt_ah.h"
20*572ff6f6SMatthew Dillon 
21*572ff6f6SMatthew Dillon #include "ah.h"
22*572ff6f6SMatthew Dillon #include "ah_internal.h"
23*572ff6f6SMatthew Dillon #include "ah_eeprom_v3.h"
24*572ff6f6SMatthew Dillon 
25*572ff6f6SMatthew Dillon static void
getPcdacInterceptsFromPcdacMinMax(HAL_EEPROM * ee,uint16_t pcdacMin,uint16_t pcdacMax,uint16_t * vp)26*572ff6f6SMatthew Dillon getPcdacInterceptsFromPcdacMinMax(HAL_EEPROM *ee,
27*572ff6f6SMatthew Dillon 	uint16_t pcdacMin, uint16_t pcdacMax, uint16_t *vp)
28*572ff6f6SMatthew Dillon {
29*572ff6f6SMatthew Dillon 	static const uint16_t intercepts3[] =
30*572ff6f6SMatthew Dillon 		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
31*572ff6f6SMatthew Dillon 	static const uint16_t intercepts3_2[] =
32*572ff6f6SMatthew Dillon 		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
33*572ff6f6SMatthew Dillon 	const uint16_t *ip = ee->ee_version < AR_EEPROM_VER3_2 ?
34*572ff6f6SMatthew Dillon 		intercepts3 : intercepts3_2;
35*572ff6f6SMatthew Dillon 	int i;
36*572ff6f6SMatthew Dillon 
37*572ff6f6SMatthew Dillon 	/* loop for the percentages in steps or 5 */
38*572ff6f6SMatthew Dillon 	for (i = 0; i < NUM_INTERCEPTS; i++ )
39*572ff6f6SMatthew Dillon 		*vp++ = (ip[i] * pcdacMax + (100 - ip[i]) * pcdacMin) / 100;
40*572ff6f6SMatthew Dillon }
41*572ff6f6SMatthew Dillon 
42*572ff6f6SMatthew Dillon /*
43*572ff6f6SMatthew Dillon  * Get channel value from binary representation held in eeprom
44*572ff6f6SMatthew Dillon  */
45*572ff6f6SMatthew Dillon static uint16_t
fbin2freq(HAL_EEPROM * ee,uint16_t fbin)46*572ff6f6SMatthew Dillon fbin2freq(HAL_EEPROM *ee, uint16_t fbin)
47*572ff6f6SMatthew Dillon {
48*572ff6f6SMatthew Dillon 	if (fbin == CHANNEL_UNUSED)	/* reserved value, don't convert */
49*572ff6f6SMatthew Dillon 		return fbin;
50*572ff6f6SMatthew Dillon 	return ee->ee_version <= AR_EEPROM_VER3_2 ?
51*572ff6f6SMatthew Dillon 		(fbin > 62 ? 5100 + 10*62 + 5*(fbin-62) : 5100 + 10*fbin) :
52*572ff6f6SMatthew Dillon 		4800 + 5*fbin;
53*572ff6f6SMatthew Dillon }
54*572ff6f6SMatthew Dillon 
55*572ff6f6SMatthew Dillon static uint16_t
fbin2freq_2p4(HAL_EEPROM * ee,uint16_t fbin)56*572ff6f6SMatthew Dillon fbin2freq_2p4(HAL_EEPROM *ee, uint16_t fbin)
57*572ff6f6SMatthew Dillon {
58*572ff6f6SMatthew Dillon 	if (fbin == CHANNEL_UNUSED)	/* reserved value, don't convert */
59*572ff6f6SMatthew Dillon 		return fbin;
60*572ff6f6SMatthew Dillon 	return ee->ee_version <= AR_EEPROM_VER3_2 ?
61*572ff6f6SMatthew Dillon 		2400 + fbin :
62*572ff6f6SMatthew Dillon 		2300 + fbin;
63*572ff6f6SMatthew Dillon }
64*572ff6f6SMatthew Dillon 
65*572ff6f6SMatthew Dillon /*
66*572ff6f6SMatthew Dillon  * Now copy EEPROM frequency pier contents into the allocated space
67*572ff6f6SMatthew Dillon  */
68*572ff6f6SMatthew Dillon static HAL_BOOL
readEepromFreqPierInfo(struct ath_hal * ah,HAL_EEPROM * ee)69*572ff6f6SMatthew Dillon readEepromFreqPierInfo(struct ath_hal *ah, HAL_EEPROM *ee)
70*572ff6f6SMatthew Dillon {
71*572ff6f6SMatthew Dillon #define	EEREAD(_off) do {				\
72*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
73*572ff6f6SMatthew Dillon 		return AH_FALSE;			\
74*572ff6f6SMatthew Dillon } while (0)
75*572ff6f6SMatthew Dillon 	uint16_t eeval, off;
76*572ff6f6SMatthew Dillon 	int i;
77*572ff6f6SMatthew Dillon 
78*572ff6f6SMatthew Dillon 	if (ee->ee_version >= AR_EEPROM_VER4_0 &&
79*572ff6f6SMatthew Dillon 	    ee->ee_eepMap && !ee->ee_Amode) {
80*572ff6f6SMatthew Dillon 		/*
81*572ff6f6SMatthew Dillon 		 * V4.0 EEPROMs with map type 1 have frequency pier
82*572ff6f6SMatthew Dillon 		 * data only when 11a mode is supported.
83*572ff6f6SMatthew Dillon 		 */
84*572ff6f6SMatthew Dillon 		return AH_TRUE;
85*572ff6f6SMatthew Dillon 	}
86*572ff6f6SMatthew Dillon 	if (ee->ee_version >= AR_EEPROM_VER3_3) {
87*572ff6f6SMatthew Dillon 		off = GROUPS_OFFSET3_3 + GROUP1_OFFSET;
88*572ff6f6SMatthew Dillon 		for (i = 0; i < ee->ee_numChannels11a; i += 2) {
89*572ff6f6SMatthew Dillon 			EEREAD(off++);
90*572ff6f6SMatthew Dillon 			ee->ee_channels11a[i]   = (eeval >> 8) & FREQ_MASK_3_3;
91*572ff6f6SMatthew Dillon 			ee->ee_channels11a[i+1] = eeval & FREQ_MASK_3_3;
92*572ff6f6SMatthew Dillon 		}
93*572ff6f6SMatthew Dillon 	} else {
94*572ff6f6SMatthew Dillon 		off = GROUPS_OFFSET3_2 + GROUP1_OFFSET;
95*572ff6f6SMatthew Dillon 
96*572ff6f6SMatthew Dillon 		EEREAD(off++);
97*572ff6f6SMatthew Dillon 		ee->ee_channels11a[0] = (eeval >> 9) & FREQ_MASK;
98*572ff6f6SMatthew Dillon 		ee->ee_channels11a[1] = (eeval >> 2) & FREQ_MASK;
99*572ff6f6SMatthew Dillon 		ee->ee_channels11a[2] = (eeval << 5) & FREQ_MASK;
100*572ff6f6SMatthew Dillon 
101*572ff6f6SMatthew Dillon 		EEREAD(off++);
102*572ff6f6SMatthew Dillon 		ee->ee_channels11a[2] |= (eeval >> 11) & 0x1f;
103*572ff6f6SMatthew Dillon 		ee->ee_channels11a[3]  = (eeval >>  4) & FREQ_MASK;
104*572ff6f6SMatthew Dillon 		ee->ee_channels11a[4]  = (eeval <<  3) & FREQ_MASK;
105*572ff6f6SMatthew Dillon 
106*572ff6f6SMatthew Dillon 		EEREAD(off++);
107*572ff6f6SMatthew Dillon 		ee->ee_channels11a[4] |= (eeval >> 13) & 0x7;
108*572ff6f6SMatthew Dillon 		ee->ee_channels11a[5]  = (eeval >>  6) & FREQ_MASK;
109*572ff6f6SMatthew Dillon 		ee->ee_channels11a[6]  = (eeval <<  1) & FREQ_MASK;
110*572ff6f6SMatthew Dillon 
111*572ff6f6SMatthew Dillon 		EEREAD(off++);
112*572ff6f6SMatthew Dillon 		ee->ee_channels11a[6] |= (eeval >> 15) & 0x1;
113*572ff6f6SMatthew Dillon 		ee->ee_channels11a[7]  = (eeval >>  8) & FREQ_MASK;
114*572ff6f6SMatthew Dillon 		ee->ee_channels11a[8]  = (eeval >>  1) & FREQ_MASK;
115*572ff6f6SMatthew Dillon 		ee->ee_channels11a[9]  = (eeval <<  6) & FREQ_MASK;
116*572ff6f6SMatthew Dillon 
117*572ff6f6SMatthew Dillon 		EEREAD(off++);
118*572ff6f6SMatthew Dillon 		ee->ee_channels11a[9] |= (eeval >> 10) & 0x3f;
119*572ff6f6SMatthew Dillon 	}
120*572ff6f6SMatthew Dillon 
121*572ff6f6SMatthew Dillon 	for (i = 0; i < ee->ee_numChannels11a; i++)
122*572ff6f6SMatthew Dillon 		ee->ee_channels11a[i] = fbin2freq(ee, ee->ee_channels11a[i]);
123*572ff6f6SMatthew Dillon 
124*572ff6f6SMatthew Dillon 	return AH_TRUE;
125*572ff6f6SMatthew Dillon #undef EEREAD
126*572ff6f6SMatthew Dillon }
127*572ff6f6SMatthew Dillon 
128*572ff6f6SMatthew Dillon /*
129*572ff6f6SMatthew Dillon  * Rev 4 Eeprom 5112 Power Extract Functions
130*572ff6f6SMatthew Dillon  */
131*572ff6f6SMatthew Dillon 
132*572ff6f6SMatthew Dillon /*
133*572ff6f6SMatthew Dillon  * Allocate the power information based on the number of channels
134*572ff6f6SMatthew Dillon  * recorded by the calibration.  These values are then initialized.
135*572ff6f6SMatthew Dillon  */
136*572ff6f6SMatthew Dillon static HAL_BOOL
eepromAllocExpnPower5112(struct ath_hal * ah,const EEPROM_POWER_5112 * pCalDataset,EEPROM_POWER_EXPN_5112 * pPowerExpn)137*572ff6f6SMatthew Dillon eepromAllocExpnPower5112(struct ath_hal *ah,
138*572ff6f6SMatthew Dillon 	const EEPROM_POWER_5112 *pCalDataset,
139*572ff6f6SMatthew Dillon 	EEPROM_POWER_EXPN_5112 *pPowerExpn)
140*572ff6f6SMatthew Dillon {
141*572ff6f6SMatthew Dillon 	uint16_t numChannels = pCalDataset->numChannels;
142*572ff6f6SMatthew Dillon 	const uint16_t *pChanList = pCalDataset->pChannels;
143*572ff6f6SMatthew Dillon 	void *data;
144*572ff6f6SMatthew Dillon 	int i, j;
145*572ff6f6SMatthew Dillon 
146*572ff6f6SMatthew Dillon 	/* Allocate the channel and Power Data arrays together */
147*572ff6f6SMatthew Dillon 	data = ath_hal_malloc(
148*572ff6f6SMatthew Dillon 		roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)) +
149*572ff6f6SMatthew Dillon 		sizeof(EXPN_DATA_PER_CHANNEL_5112) * numChannels);
150*572ff6f6SMatthew Dillon 	if (data == AH_NULL) {
151*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY,
152*572ff6f6SMatthew Dillon 		    "%s unable to allocate raw data struct (gen3)\n", __func__);
153*572ff6f6SMatthew Dillon 		return AH_FALSE;
154*572ff6f6SMatthew Dillon 	}
155*572ff6f6SMatthew Dillon 	pPowerExpn->pChannels = data;
156*572ff6f6SMatthew Dillon 	pPowerExpn->pDataPerChannel = (void *)(((char *)data) +
157*572ff6f6SMatthew Dillon 		roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)));
158*572ff6f6SMatthew Dillon 
159*572ff6f6SMatthew Dillon 	pPowerExpn->numChannels = numChannels;
160*572ff6f6SMatthew Dillon 	for (i = 0; i < numChannels; i++) {
161*572ff6f6SMatthew Dillon 		pPowerExpn->pChannels[i] =
162*572ff6f6SMatthew Dillon 			pPowerExpn->pDataPerChannel[i].channelValue =
163*572ff6f6SMatthew Dillon 				pChanList[i];
164*572ff6f6SMatthew Dillon 		for (j = 0; j < NUM_XPD_PER_CHANNEL; j++) {
165*572ff6f6SMatthew Dillon 			pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].xpd_gain = j;
166*572ff6f6SMatthew Dillon 			pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].numPcdacs = 0;
167*572ff6f6SMatthew Dillon 		}
168*572ff6f6SMatthew Dillon 		pPowerExpn->pDataPerChannel[i].pDataPerXPD[0].numPcdacs = 4;
169*572ff6f6SMatthew Dillon 		pPowerExpn->pDataPerChannel[i].pDataPerXPD[3].numPcdacs = 3;
170*572ff6f6SMatthew Dillon 	}
171*572ff6f6SMatthew Dillon 	return AH_TRUE;
172*572ff6f6SMatthew Dillon }
173*572ff6f6SMatthew Dillon 
174*572ff6f6SMatthew Dillon /*
175*572ff6f6SMatthew Dillon  * Expand the dataSet from the calibration information into the
176*572ff6f6SMatthew Dillon  * final power structure for 5112
177*572ff6f6SMatthew Dillon  */
178*572ff6f6SMatthew Dillon static HAL_BOOL
eepromExpandPower5112(struct ath_hal * ah,const EEPROM_POWER_5112 * pCalDataset,EEPROM_POWER_EXPN_5112 * pPowerExpn)179*572ff6f6SMatthew Dillon eepromExpandPower5112(struct ath_hal *ah,
180*572ff6f6SMatthew Dillon 	const EEPROM_POWER_5112 *pCalDataset,
181*572ff6f6SMatthew Dillon 	EEPROM_POWER_EXPN_5112 *pPowerExpn)
182*572ff6f6SMatthew Dillon {
183*572ff6f6SMatthew Dillon 	int ii, jj, kk;
184*572ff6f6SMatthew Dillon 	int16_t maxPower_t4;
185*572ff6f6SMatthew Dillon 	EXPN_DATA_PER_XPD_5112 *pExpnXPD;
186*572ff6f6SMatthew Dillon 	/* ptr to array of info held per channel */
187*572ff6f6SMatthew Dillon 	const EEPROM_DATA_PER_CHANNEL_5112 *pCalCh;
188*572ff6f6SMatthew Dillon 	uint16_t xgainList[2], xpdMask;
189*572ff6f6SMatthew Dillon 
190*572ff6f6SMatthew Dillon 	pPowerExpn->xpdMask = pCalDataset->xpdMask;
191*572ff6f6SMatthew Dillon 
192*572ff6f6SMatthew Dillon 	xgainList[0] = 0xDEAD;
193*572ff6f6SMatthew Dillon 	xgainList[1] = 0xDEAD;
194*572ff6f6SMatthew Dillon 
195*572ff6f6SMatthew Dillon 	kk = 0;
196*572ff6f6SMatthew Dillon 	xpdMask = pPowerExpn->xpdMask;
197*572ff6f6SMatthew Dillon 	for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) {
198*572ff6f6SMatthew Dillon 		if (((xpdMask >> jj) & 1) > 0) {
199*572ff6f6SMatthew Dillon 			if (kk > 1) {
200*572ff6f6SMatthew Dillon 				HALDEBUG(ah, HAL_DEBUG_ANY,
201*572ff6f6SMatthew Dillon 				    "%s: too many xpdGains in dataset: %u\n",
202*572ff6f6SMatthew Dillon 				    __func__, kk);
203*572ff6f6SMatthew Dillon 				return AH_FALSE;
204*572ff6f6SMatthew Dillon 			}
205*572ff6f6SMatthew Dillon 			xgainList[kk++] = jj;
206*572ff6f6SMatthew Dillon 		}
207*572ff6f6SMatthew Dillon 	}
208*572ff6f6SMatthew Dillon 
209*572ff6f6SMatthew Dillon 	pPowerExpn->numChannels = pCalDataset->numChannels;
210*572ff6f6SMatthew Dillon 	if (pPowerExpn->numChannels == 0) {
211*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no channels\n", __func__);
212*572ff6f6SMatthew Dillon 		return AH_FALSE;
213*572ff6f6SMatthew Dillon 	}
214*572ff6f6SMatthew Dillon 
215*572ff6f6SMatthew Dillon 	for (ii = 0; ii < pPowerExpn->numChannels; ii++) {
216*572ff6f6SMatthew Dillon 		pCalCh = &pCalDataset->pDataPerChannel[ii];
217*572ff6f6SMatthew Dillon 		pPowerExpn->pDataPerChannel[ii].channelValue =
218*572ff6f6SMatthew Dillon 			pCalCh->channelValue;
219*572ff6f6SMatthew Dillon 		pPowerExpn->pDataPerChannel[ii].maxPower_t4 =
220*572ff6f6SMatthew Dillon 			pCalCh->maxPower_t4;
221*572ff6f6SMatthew Dillon 		maxPower_t4 = pPowerExpn->pDataPerChannel[ii].maxPower_t4;
222*572ff6f6SMatthew Dillon 
223*572ff6f6SMatthew Dillon 		for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++)
224*572ff6f6SMatthew Dillon 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj].numPcdacs = 0;
225*572ff6f6SMatthew Dillon 		if (xgainList[1] == 0xDEAD) {
226*572ff6f6SMatthew Dillon 			jj = xgainList[0];
227*572ff6f6SMatthew Dillon 			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
228*572ff6f6SMatthew Dillon 			pExpnXPD->numPcdacs = 4;
229*572ff6f6SMatthew Dillon 			pExpnXPD->pcdac[0] = pCalCh->pcd1_xg0;
230*572ff6f6SMatthew Dillon 			pExpnXPD->pcdac[1] = (uint16_t)
231*572ff6f6SMatthew Dillon 				(pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0);
232*572ff6f6SMatthew Dillon 			pExpnXPD->pcdac[2] = (uint16_t)
233*572ff6f6SMatthew Dillon 				(pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0);
234*572ff6f6SMatthew Dillon 			pExpnXPD->pcdac[3] = (uint16_t)
235*572ff6f6SMatthew Dillon 				(pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0);
236*572ff6f6SMatthew Dillon 
237*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0;
238*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0;
239*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0;
240*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0;
241*572ff6f6SMatthew Dillon 
242*572ff6f6SMatthew Dillon 		} else {
243*572ff6f6SMatthew Dillon 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[0]].pcdac[0] = pCalCh->pcd1_xg0;
244*572ff6f6SMatthew Dillon 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[0] = 20;
245*572ff6f6SMatthew Dillon 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[1] = 35;
246*572ff6f6SMatthew Dillon 			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[2] = 63;
247*572ff6f6SMatthew Dillon 
248*572ff6f6SMatthew Dillon 			jj = xgainList[0];
249*572ff6f6SMatthew Dillon 			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
250*572ff6f6SMatthew Dillon 			pExpnXPD->numPcdacs = 4;
251*572ff6f6SMatthew Dillon 			pExpnXPD->pcdac[1] = (uint16_t)
252*572ff6f6SMatthew Dillon 				(pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0);
253*572ff6f6SMatthew Dillon 			pExpnXPD->pcdac[2] = (uint16_t)
254*572ff6f6SMatthew Dillon 				(pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0);
255*572ff6f6SMatthew Dillon 			pExpnXPD->pcdac[3] = (uint16_t)
256*572ff6f6SMatthew Dillon 				(pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0);
257*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0;
258*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0;
259*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0;
260*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0;
261*572ff6f6SMatthew Dillon 
262*572ff6f6SMatthew Dillon 			jj = xgainList[1];
263*572ff6f6SMatthew Dillon 			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
264*572ff6f6SMatthew Dillon 			pExpnXPD->numPcdacs = 3;
265*572ff6f6SMatthew Dillon 
266*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg3;
267*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg3;
268*572ff6f6SMatthew Dillon 			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg3;
269*572ff6f6SMatthew Dillon 		}
270*572ff6f6SMatthew Dillon 	}
271*572ff6f6SMatthew Dillon 	return AH_TRUE;
272*572ff6f6SMatthew Dillon }
273*572ff6f6SMatthew Dillon 
274*572ff6f6SMatthew Dillon static HAL_BOOL
readEepromRawPowerCalInfo5112(struct ath_hal * ah,HAL_EEPROM * ee)275*572ff6f6SMatthew Dillon readEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee)
276*572ff6f6SMatthew Dillon {
277*572ff6f6SMatthew Dillon #define	EEREAD(_off) do {				\
278*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
279*572ff6f6SMatthew Dillon 		return AH_FALSE;			\
280*572ff6f6SMatthew Dillon } while (0)
281*572ff6f6SMatthew Dillon 	const uint16_t dbmmask		 = 0xff;
282*572ff6f6SMatthew Dillon 	const uint16_t pcdac_delta_mask = 0x1f;
283*572ff6f6SMatthew Dillon 	const uint16_t pcdac_mask	 = 0x3f;
284*572ff6f6SMatthew Dillon 	const uint16_t freqmask	 = 0xff;
285*572ff6f6SMatthew Dillon 
286*572ff6f6SMatthew Dillon 	int i, mode, numPiers;
287*572ff6f6SMatthew Dillon 	uint32_t off;
288*572ff6f6SMatthew Dillon 	uint16_t eeval;
289*572ff6f6SMatthew Dillon 	uint16_t freq[NUM_11A_EEPROM_CHANNELS];
290*572ff6f6SMatthew Dillon         EEPROM_POWER_5112 eePower;
291*572ff6f6SMatthew Dillon 
292*572ff6f6SMatthew Dillon 	HALASSERT(ee->ee_version >= AR_EEPROM_VER4_0);
293*572ff6f6SMatthew Dillon 	off = GROUPS_OFFSET3_3;
294*572ff6f6SMatthew Dillon 	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
295*572ff6f6SMatthew Dillon 		numPiers = 0;
296*572ff6f6SMatthew Dillon 		switch (mode) {
297*572ff6f6SMatthew Dillon 		case headerInfo11A:
298*572ff6f6SMatthew Dillon 			if (!ee->ee_Amode)	/* no 11a calibration data */
299*572ff6f6SMatthew Dillon 				continue;
300*572ff6f6SMatthew Dillon 			while (numPiers < NUM_11A_EEPROM_CHANNELS) {
301*572ff6f6SMatthew Dillon 				EEREAD(off++);
302*572ff6f6SMatthew Dillon 				if ((eeval & freqmask) == 0)
303*572ff6f6SMatthew Dillon 					break;
304*572ff6f6SMatthew Dillon 				freq[numPiers++] = fbin2freq(ee,
305*572ff6f6SMatthew Dillon 					eeval & freqmask);
306*572ff6f6SMatthew Dillon 
307*572ff6f6SMatthew Dillon 				if (((eeval >> 8) & freqmask) == 0)
308*572ff6f6SMatthew Dillon 					break;
309*572ff6f6SMatthew Dillon 				freq[numPiers++] = fbin2freq(ee,
310*572ff6f6SMatthew Dillon 					(eeval>>8) & freqmask);
311*572ff6f6SMatthew Dillon 			}
312*572ff6f6SMatthew Dillon 			break;
313*572ff6f6SMatthew Dillon 		case headerInfo11B:
314*572ff6f6SMatthew Dillon 			if (!ee->ee_Bmode)	/* no 11b calibration data */
315*572ff6f6SMatthew Dillon 				continue;
316*572ff6f6SMatthew Dillon 			for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++)
317*572ff6f6SMatthew Dillon 				if (ee->ee_calPier11b[i] != CHANNEL_UNUSED)
318*572ff6f6SMatthew Dillon 					freq[numPiers++] = ee->ee_calPier11b[i];
319*572ff6f6SMatthew Dillon 			break;
320*572ff6f6SMatthew Dillon 		case headerInfo11G:
321*572ff6f6SMatthew Dillon 			if (!ee->ee_Gmode)	/* no 11g calibration data */
322*572ff6f6SMatthew Dillon 				continue;
323*572ff6f6SMatthew Dillon 			for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++)
324*572ff6f6SMatthew Dillon 				if (ee->ee_calPier11g[i] != CHANNEL_UNUSED)
325*572ff6f6SMatthew Dillon 					freq[numPiers++] = ee->ee_calPier11g[i];
326*572ff6f6SMatthew Dillon 			break;
327*572ff6f6SMatthew Dillon 		default:
328*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
329*572ff6f6SMatthew Dillon 			    __func__, mode);
330*572ff6f6SMatthew Dillon 			return AH_FALSE;
331*572ff6f6SMatthew Dillon 		}
332*572ff6f6SMatthew Dillon 
333*572ff6f6SMatthew Dillon 		OS_MEMZERO(&eePower, sizeof(eePower));
334*572ff6f6SMatthew Dillon 		eePower.numChannels = numPiers;
335*572ff6f6SMatthew Dillon 
336*572ff6f6SMatthew Dillon 		for (i = 0; i < numPiers; i++) {
337*572ff6f6SMatthew Dillon 			eePower.pChannels[i] = freq[i];
338*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].channelValue = freq[i];
339*572ff6f6SMatthew Dillon 
340*572ff6f6SMatthew Dillon 			EEREAD(off++);
341*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pwr1_xg0 = (int16_t)
342*572ff6f6SMatthew Dillon 				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
343*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pwr2_xg0 = (int16_t)
344*572ff6f6SMatthew Dillon 				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
345*572ff6f6SMatthew Dillon 
346*572ff6f6SMatthew Dillon 			EEREAD(off++);
347*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pwr3_xg0 = (int16_t)
348*572ff6f6SMatthew Dillon 				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
349*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pwr4_xg0 = (int16_t)
350*572ff6f6SMatthew Dillon 				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
351*572ff6f6SMatthew Dillon 
352*572ff6f6SMatthew Dillon 			EEREAD(off++);
353*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pcd2_delta_xg0 = (uint16_t)
354*572ff6f6SMatthew Dillon 				(eeval & pcdac_delta_mask);
355*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pcd3_delta_xg0 = (uint16_t)
356*572ff6f6SMatthew Dillon 				((eeval >> 5) & pcdac_delta_mask);
357*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pcd4_delta_xg0 = (uint16_t)
358*572ff6f6SMatthew Dillon 				((eeval >> 10) & pcdac_delta_mask);
359*572ff6f6SMatthew Dillon 
360*572ff6f6SMatthew Dillon 			EEREAD(off++);
361*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pwr1_xg3 = (int16_t)
362*572ff6f6SMatthew Dillon 				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
363*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pwr2_xg3 = (int16_t)
364*572ff6f6SMatthew Dillon 				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
365*572ff6f6SMatthew Dillon 
366*572ff6f6SMatthew Dillon 			EEREAD(off++);
367*572ff6f6SMatthew Dillon 			eePower.pDataPerChannel[i].pwr3_xg3 = (int16_t)
368*572ff6f6SMatthew Dillon 				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
369*572ff6f6SMatthew Dillon 			if (ee->ee_version >= AR_EEPROM_VER4_3) {
370*572ff6f6SMatthew Dillon 				eePower.pDataPerChannel[i].maxPower_t4 =
371*572ff6f6SMatthew Dillon 					eePower.pDataPerChannel[i].pwr4_xg0;
372*572ff6f6SMatthew Dillon 				eePower.pDataPerChannel[i].pcd1_xg0 = (uint16_t)
373*572ff6f6SMatthew Dillon 					((eeval >> 8) & pcdac_mask);
374*572ff6f6SMatthew Dillon 			} else {
375*572ff6f6SMatthew Dillon 				eePower.pDataPerChannel[i].maxPower_t4 = (int16_t)
376*572ff6f6SMatthew Dillon 					(((eeval >> 8) & dbmmask) -
377*572ff6f6SMatthew Dillon 					 ((eeval >> 15) & 0x1)*256);
378*572ff6f6SMatthew Dillon 				eePower.pDataPerChannel[i].pcd1_xg0 = 1;
379*572ff6f6SMatthew Dillon 			}
380*572ff6f6SMatthew Dillon 		}
381*572ff6f6SMatthew Dillon 		eePower.xpdMask = ee->ee_xgain[mode];
382*572ff6f6SMatthew Dillon 
383*572ff6f6SMatthew Dillon 		if (!eepromAllocExpnPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) {
384*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY,
385*572ff6f6SMatthew Dillon 			    "%s: did not allocate power struct\n", __func__);
386*572ff6f6SMatthew Dillon 			return AH_FALSE;
387*572ff6f6SMatthew Dillon                 }
388*572ff6f6SMatthew Dillon                 if (!eepromExpandPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) {
389*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY,
390*572ff6f6SMatthew Dillon 			    "%s: did not expand power struct\n", __func__);
391*572ff6f6SMatthew Dillon 			return AH_FALSE;
392*572ff6f6SMatthew Dillon 		}
393*572ff6f6SMatthew Dillon 	}
394*572ff6f6SMatthew Dillon 	return AH_TRUE;
395*572ff6f6SMatthew Dillon #undef EEREAD
396*572ff6f6SMatthew Dillon }
397*572ff6f6SMatthew Dillon 
398*572ff6f6SMatthew Dillon static void
freeEepromRawPowerCalInfo5112(struct ath_hal * ah,HAL_EEPROM * ee)399*572ff6f6SMatthew Dillon freeEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee)
400*572ff6f6SMatthew Dillon {
401*572ff6f6SMatthew Dillon 	int mode;
402*572ff6f6SMatthew Dillon 	void *data;
403*572ff6f6SMatthew Dillon 
404*572ff6f6SMatthew Dillon 	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
405*572ff6f6SMatthew Dillon 		EEPROM_POWER_EXPN_5112 *pPowerExpn =
406*572ff6f6SMatthew Dillon 			&ee->ee_modePowerArray5112[mode];
407*572ff6f6SMatthew Dillon 		data = pPowerExpn->pChannels;
408*572ff6f6SMatthew Dillon 		if (data != AH_NULL) {
409*572ff6f6SMatthew Dillon 			pPowerExpn->pChannels = AH_NULL;
410*572ff6f6SMatthew Dillon 			ath_hal_free(data);
411*572ff6f6SMatthew Dillon 		}
412*572ff6f6SMatthew Dillon 	}
413*572ff6f6SMatthew Dillon }
414*572ff6f6SMatthew Dillon 
415*572ff6f6SMatthew Dillon static void
ar2413SetupEEPROMDataset(EEPROM_DATA_STRUCT_2413 * pEEPROMDataset2413,uint16_t myNumRawChannels,uint16_t * pMyRawChanList)416*572ff6f6SMatthew Dillon ar2413SetupEEPROMDataset(EEPROM_DATA_STRUCT_2413 *pEEPROMDataset2413,
417*572ff6f6SMatthew Dillon 	uint16_t myNumRawChannels, uint16_t *pMyRawChanList)
418*572ff6f6SMatthew Dillon {
419*572ff6f6SMatthew Dillon 	uint16_t i, channelValue;
420*572ff6f6SMatthew Dillon 	uint32_t xpd_mask;
421*572ff6f6SMatthew Dillon 	uint16_t numPdGainsUsed;
422*572ff6f6SMatthew Dillon 
423*572ff6f6SMatthew Dillon 	pEEPROMDataset2413->numChannels = myNumRawChannels;
424*572ff6f6SMatthew Dillon 
425*572ff6f6SMatthew Dillon 	xpd_mask = pEEPROMDataset2413->xpd_mask;
426*572ff6f6SMatthew Dillon 	numPdGainsUsed = 0;
427*572ff6f6SMatthew Dillon 	if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++;
428*572ff6f6SMatthew Dillon 	if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++;
429*572ff6f6SMatthew Dillon 	if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++;
430*572ff6f6SMatthew Dillon 	if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++;
431*572ff6f6SMatthew Dillon 
432*572ff6f6SMatthew Dillon 	for (i = 0; i < myNumRawChannels; i++) {
433*572ff6f6SMatthew Dillon 		channelValue = pMyRawChanList[i];
434*572ff6f6SMatthew Dillon 		pEEPROMDataset2413->pChannels[i] = channelValue;
435*572ff6f6SMatthew Dillon 		pEEPROMDataset2413->pDataPerChannel[i].channelValue = channelValue;
436*572ff6f6SMatthew Dillon 		pEEPROMDataset2413->pDataPerChannel[i].numPdGains = numPdGainsUsed;
437*572ff6f6SMatthew Dillon 	}
438*572ff6f6SMatthew Dillon }
439*572ff6f6SMatthew Dillon 
440*572ff6f6SMatthew Dillon 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)441*572ff6f6SMatthew Dillon ar2413ReadCalDataset(struct ath_hal *ah, HAL_EEPROM *ee,
442*572ff6f6SMatthew Dillon 	EEPROM_DATA_STRUCT_2413 *pCalDataset,
443*572ff6f6SMatthew Dillon 	uint32_t start_offset, uint32_t maxPiers, uint8_t mode)
444*572ff6f6SMatthew Dillon {
445*572ff6f6SMatthew Dillon #define	EEREAD(_off) do {				\
446*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
447*572ff6f6SMatthew Dillon 		return AH_FALSE;			\
448*572ff6f6SMatthew Dillon } while (0)
449*572ff6f6SMatthew Dillon 	const uint16_t dbm_I_mask = 0x1F;	/* 5-bits. 1dB step. */
450*572ff6f6SMatthew Dillon 	const uint16_t dbm_delta_mask = 0xF;	/* 4-bits. 0.5dB step. */
451*572ff6f6SMatthew Dillon 	const uint16_t Vpd_I_mask = 0x7F;	/* 7-bits. 0-128 */
452*572ff6f6SMatthew Dillon 	const uint16_t Vpd_delta_mask = 0x3F;	/* 6-bits. 0-63 */
453*572ff6f6SMatthew Dillon 	const uint16_t freqmask = 0xff;
454*572ff6f6SMatthew Dillon 
455*572ff6f6SMatthew Dillon 	uint16_t ii, eeval;
456*572ff6f6SMatthew Dillon 	uint16_t idx, numPiers;
457*572ff6f6SMatthew Dillon 	uint16_t freq[NUM_11A_EEPROM_CHANNELS];
458*572ff6f6SMatthew Dillon 
459*572ff6f6SMatthew Dillon 	idx = start_offset;
460*572ff6f6SMatthew Dillon     for (numPiers = 0; numPiers < maxPiers;) {
461*572ff6f6SMatthew Dillon         EEREAD(idx++);
462*572ff6f6SMatthew Dillon         if ((eeval & freqmask) == 0)
463*572ff6f6SMatthew Dillon             break;
464*572ff6f6SMatthew Dillon         if (mode == headerInfo11A)
465*572ff6f6SMatthew Dillon             freq[numPiers++] = fbin2freq(ee, (eeval & freqmask));
466*572ff6f6SMatthew Dillon         else
467*572ff6f6SMatthew Dillon             freq[numPiers++] = fbin2freq_2p4(ee, (eeval & freqmask));
468*572ff6f6SMatthew Dillon 
469*572ff6f6SMatthew Dillon         if (((eeval >> 8) & freqmask) == 0)
470*572ff6f6SMatthew Dillon             break;
471*572ff6f6SMatthew Dillon         if (mode == headerInfo11A)
472*572ff6f6SMatthew Dillon             freq[numPiers++] = fbin2freq(ee, (eeval >> 8) & freqmask);
473*572ff6f6SMatthew Dillon         else
474*572ff6f6SMatthew Dillon             freq[numPiers++] = fbin2freq_2p4(ee, (eeval >> 8) & freqmask);
475*572ff6f6SMatthew Dillon     }
476*572ff6f6SMatthew Dillon 	ar2413SetupEEPROMDataset(pCalDataset, numPiers, &freq[0]);
477*572ff6f6SMatthew Dillon 
478*572ff6f6SMatthew Dillon 	idx = start_offset + (maxPiers / 2);
479*572ff6f6SMatthew Dillon 	for (ii = 0; ii < pCalDataset->numChannels; ii++) {
480*572ff6f6SMatthew Dillon 		EEPROM_DATA_PER_CHANNEL_2413 *currCh =
481*572ff6f6SMatthew Dillon 			&(pCalDataset->pDataPerChannel[ii]);
482*572ff6f6SMatthew Dillon 
483*572ff6f6SMatthew Dillon 		if (currCh->numPdGains > 0) {
484*572ff6f6SMatthew Dillon 			/*
485*572ff6f6SMatthew Dillon 			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
486*572ff6f6SMatthew Dillon 			 * and Vpd values for pdgain_0
487*572ff6f6SMatthew Dillon 			 */
488*572ff6f6SMatthew Dillon 			EEREAD(idx++);
489*572ff6f6SMatthew Dillon 			currCh->pwr_I[0] = eeval & dbm_I_mask;
490*572ff6f6SMatthew Dillon 			currCh->Vpd_I[0] = (eeval >> 5) & Vpd_I_mask;
491*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[0][0] =
492*572ff6f6SMatthew Dillon 				(eeval >> 12) & dbm_delta_mask;
493*572ff6f6SMatthew Dillon 
494*572ff6f6SMatthew Dillon 			EEREAD(idx++);
495*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[0][0] = eeval & Vpd_delta_mask;
496*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[1][0] =
497*572ff6f6SMatthew Dillon 				(eeval >> 6) & dbm_delta_mask;
498*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[1][0] =
499*572ff6f6SMatthew Dillon 				(eeval >> 10) & Vpd_delta_mask;
500*572ff6f6SMatthew Dillon 
501*572ff6f6SMatthew Dillon 			EEREAD(idx++);
502*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[2][0] = eeval & dbm_delta_mask;
503*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[2][0] = (eeval >> 4) & Vpd_delta_mask;
504*572ff6f6SMatthew Dillon 		}
505*572ff6f6SMatthew Dillon 
506*572ff6f6SMatthew Dillon 		if (currCh->numPdGains > 1) {
507*572ff6f6SMatthew Dillon 			/*
508*572ff6f6SMatthew Dillon 			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
509*572ff6f6SMatthew Dillon 			 * and Vpd values for pdgain_1
510*572ff6f6SMatthew Dillon 			 */
511*572ff6f6SMatthew Dillon 			currCh->pwr_I[1] = (eeval >> 10) & dbm_I_mask;
512*572ff6f6SMatthew Dillon 			currCh->Vpd_I[1] = (eeval >> 15) & 0x1;
513*572ff6f6SMatthew Dillon 
514*572ff6f6SMatthew Dillon 			EEREAD(idx++);
515*572ff6f6SMatthew Dillon 			/* upper 6 bits */
516*572ff6f6SMatthew Dillon 			currCh->Vpd_I[1] |= (eeval & 0x3F) << 1;
517*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[0][1] =
518*572ff6f6SMatthew Dillon 				(eeval >> 6) & dbm_delta_mask;
519*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[0][1] =
520*572ff6f6SMatthew Dillon 				(eeval >> 10) & Vpd_delta_mask;
521*572ff6f6SMatthew Dillon 
522*572ff6f6SMatthew Dillon 			EEREAD(idx++);
523*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[1][1] = eeval & dbm_delta_mask;
524*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[1][1] = (eeval >> 4) & Vpd_delta_mask;
525*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[2][1] =
526*572ff6f6SMatthew Dillon 				(eeval >> 10) & dbm_delta_mask;
527*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[2][1] = (eeval >> 14) & 0x3;
528*572ff6f6SMatthew Dillon 
529*572ff6f6SMatthew Dillon 			EEREAD(idx++);
530*572ff6f6SMatthew Dillon 			/* upper 4 bits */
531*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[2][1] |= (eeval & 0xF) << 2;
532*572ff6f6SMatthew Dillon 		} else if (currCh->numPdGains == 1) {
533*572ff6f6SMatthew Dillon 			/*
534*572ff6f6SMatthew Dillon 			 * Read the last pwr and Vpd values for pdgain_0
535*572ff6f6SMatthew Dillon 			 */
536*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[3][0] =
537*572ff6f6SMatthew Dillon 				(eeval >> 10) & dbm_delta_mask;
538*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[3][0] = (eeval >> 14) & 0x3;
539*572ff6f6SMatthew Dillon 
540*572ff6f6SMatthew Dillon 			EEREAD(idx++);
541*572ff6f6SMatthew Dillon 			/* upper 4 bits */
542*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[3][0] |= (eeval & 0xF) << 2;
543*572ff6f6SMatthew Dillon 
544*572ff6f6SMatthew Dillon 			/* 4 words if numPdGains == 1 */
545*572ff6f6SMatthew Dillon 		}
546*572ff6f6SMatthew Dillon 
547*572ff6f6SMatthew Dillon 		if (currCh->numPdGains > 2) {
548*572ff6f6SMatthew Dillon 			/*
549*572ff6f6SMatthew Dillon 			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
550*572ff6f6SMatthew Dillon 			 * and Vpd values for pdgain_2
551*572ff6f6SMatthew Dillon 			 */
552*572ff6f6SMatthew Dillon 			currCh->pwr_I[2] = (eeval >> 4) & dbm_I_mask;
553*572ff6f6SMatthew Dillon 			currCh->Vpd_I[2] = (eeval >> 9) & Vpd_I_mask;
554*572ff6f6SMatthew Dillon 
555*572ff6f6SMatthew Dillon 			EEREAD(idx++);
556*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[0][2] =
557*572ff6f6SMatthew Dillon 				(eeval >> 0) & dbm_delta_mask;
558*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[0][2] = (eeval >> 4) & Vpd_delta_mask;
559*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[1][2] =
560*572ff6f6SMatthew Dillon 				(eeval >> 10) & dbm_delta_mask;
561*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[1][2] = (eeval >> 14) & 0x3;
562*572ff6f6SMatthew Dillon 
563*572ff6f6SMatthew Dillon 			EEREAD(idx++);
564*572ff6f6SMatthew Dillon 			/* upper 4 bits */
565*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[1][2] |= (eeval & 0xF) << 2;
566*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[2][2] =
567*572ff6f6SMatthew Dillon 				(eeval >> 4) & dbm_delta_mask;
568*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[2][2] = (eeval >> 8) & Vpd_delta_mask;
569*572ff6f6SMatthew Dillon 		} else if (currCh->numPdGains == 2) {
570*572ff6f6SMatthew Dillon 			/*
571*572ff6f6SMatthew Dillon 			 * Read the last pwr and Vpd values for pdgain_1
572*572ff6f6SMatthew Dillon 			 */
573*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[3][1] =
574*572ff6f6SMatthew Dillon 				(eeval >> 4) & dbm_delta_mask;
575*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[3][1] = (eeval >> 8) & Vpd_delta_mask;
576*572ff6f6SMatthew Dillon 
577*572ff6f6SMatthew Dillon 			/* 6 words if numPdGains == 2 */
578*572ff6f6SMatthew Dillon 		}
579*572ff6f6SMatthew Dillon 
580*572ff6f6SMatthew Dillon 		if (currCh->numPdGains > 3) {
581*572ff6f6SMatthew Dillon 			/*
582*572ff6f6SMatthew Dillon 			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
583*572ff6f6SMatthew Dillon 			 * and Vpd values for pdgain_3
584*572ff6f6SMatthew Dillon 			 */
585*572ff6f6SMatthew Dillon 			currCh->pwr_I[3] = (eeval >> 14) & 0x3;
586*572ff6f6SMatthew Dillon 
587*572ff6f6SMatthew Dillon 			EEREAD(idx++);
588*572ff6f6SMatthew Dillon 			/* upper 3 bits */
589*572ff6f6SMatthew Dillon 			currCh->pwr_I[3] |= ((eeval >> 0) & 0x7) << 2;
590*572ff6f6SMatthew Dillon 			currCh->Vpd_I[3] = (eeval >> 3) & Vpd_I_mask;
591*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[0][3] =
592*572ff6f6SMatthew Dillon 				(eeval >> 10) & dbm_delta_mask;
593*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[0][3] = (eeval >> 14) & 0x3;
594*572ff6f6SMatthew Dillon 
595*572ff6f6SMatthew Dillon 			EEREAD(idx++);
596*572ff6f6SMatthew Dillon 			/* upper 4 bits */
597*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[0][3] |= (eeval & 0xF) << 2;
598*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[1][3] =
599*572ff6f6SMatthew Dillon 				(eeval >> 4) & dbm_delta_mask;
600*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[1][3] = (eeval >> 8) & Vpd_delta_mask;
601*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[2][3] = (eeval >> 14) & 0x3;
602*572ff6f6SMatthew Dillon 
603*572ff6f6SMatthew Dillon 			EEREAD(idx++);
604*572ff6f6SMatthew Dillon 			/* upper 2 bits */
605*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[2][3] |= ((eeval >> 0) & 0x3) << 2;
606*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[2][3] = (eeval >> 2) & Vpd_delta_mask;
607*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[3][3] =
608*572ff6f6SMatthew Dillon 				(eeval >> 8) & dbm_delta_mask;
609*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[3][3] = (eeval >> 12) & 0xF;
610*572ff6f6SMatthew Dillon 
611*572ff6f6SMatthew Dillon 			EEREAD(idx++);
612*572ff6f6SMatthew Dillon 			/* upper 2 bits */
613*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[3][3] |= ((eeval >> 0) & 0x3) << 4;
614*572ff6f6SMatthew Dillon 
615*572ff6f6SMatthew Dillon 			/* 12 words if numPdGains == 4 */
616*572ff6f6SMatthew Dillon 		} else if (currCh->numPdGains == 3) {
617*572ff6f6SMatthew Dillon 			/* read the last pwr and Vpd values for pdgain_2 */
618*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[3][2] = (eeval >> 14) & 0x3;
619*572ff6f6SMatthew Dillon 
620*572ff6f6SMatthew Dillon 			EEREAD(idx++);
621*572ff6f6SMatthew Dillon 			/* upper 2 bits */
622*572ff6f6SMatthew Dillon 			currCh->pwr_delta_t2[3][2] |= ((eeval >> 0) & 0x3) << 2;
623*572ff6f6SMatthew Dillon 			currCh->Vpd_delta[3][2] = (eeval >> 2) & Vpd_delta_mask;
624*572ff6f6SMatthew Dillon 
625*572ff6f6SMatthew Dillon 			/* 9 words if numPdGains == 3 */
626*572ff6f6SMatthew Dillon 		}
627*572ff6f6SMatthew Dillon 	}
628*572ff6f6SMatthew Dillon 	return AH_TRUE;
629*572ff6f6SMatthew Dillon #undef EEREAD
630*572ff6f6SMatthew Dillon }
631*572ff6f6SMatthew Dillon 
632*572ff6f6SMatthew Dillon static void
ar2413SetupRawDataset(RAW_DATA_STRUCT_2413 * pRaw,EEPROM_DATA_STRUCT_2413 * pCal)633*572ff6f6SMatthew Dillon ar2413SetupRawDataset(RAW_DATA_STRUCT_2413 *pRaw, EEPROM_DATA_STRUCT_2413 *pCal)
634*572ff6f6SMatthew Dillon {
635*572ff6f6SMatthew Dillon 	uint16_t i, j, kk, channelValue;
636*572ff6f6SMatthew Dillon 	uint16_t xpd_mask;
637*572ff6f6SMatthew Dillon 	uint16_t numPdGainsUsed;
638*572ff6f6SMatthew Dillon 
639*572ff6f6SMatthew Dillon 	pRaw->numChannels = pCal->numChannels;
640*572ff6f6SMatthew Dillon 
641*572ff6f6SMatthew Dillon 	xpd_mask = pRaw->xpd_mask;
642*572ff6f6SMatthew Dillon 	numPdGainsUsed = 0;
643*572ff6f6SMatthew Dillon 	if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++;
644*572ff6f6SMatthew Dillon 	if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++;
645*572ff6f6SMatthew Dillon 	if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++;
646*572ff6f6SMatthew Dillon 	if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++;
647*572ff6f6SMatthew Dillon 
648*572ff6f6SMatthew Dillon 	for (i = 0; i < pCal->numChannels; i++) {
649*572ff6f6SMatthew Dillon 		channelValue = pCal->pChannels[i];
650*572ff6f6SMatthew Dillon 
651*572ff6f6SMatthew Dillon 		pRaw->pChannels[i] = channelValue;
652*572ff6f6SMatthew Dillon 
653*572ff6f6SMatthew Dillon 		pRaw->pDataPerChannel[i].channelValue = channelValue;
654*572ff6f6SMatthew Dillon 		pRaw->pDataPerChannel[i].numPdGains = numPdGainsUsed;
655*572ff6f6SMatthew Dillon 
656*572ff6f6SMatthew Dillon 		kk = 0;
657*572ff6f6SMatthew Dillon 		for (j = 0; j < MAX_NUM_PDGAINS_PER_CHANNEL; j++) {
658*572ff6f6SMatthew Dillon 			pRaw->pDataPerChannel[i].pDataPerPDGain[j].pd_gain = j;
659*572ff6f6SMatthew Dillon 			if ((xpd_mask >> j) & 0x1) {
660*572ff6f6SMatthew Dillon 				pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_OTHER_PDGAINS;
661*572ff6f6SMatthew Dillon 				kk++;
662*572ff6f6SMatthew Dillon 				if (kk == 1) {
663*572ff6f6SMatthew Dillon 					/*
664*572ff6f6SMatthew Dillon 					 * lowest pd_gain corresponds
665*572ff6f6SMatthew Dillon 					 *  to highest power and thus,
666*572ff6f6SMatthew Dillon 					 *  has one more point
667*572ff6f6SMatthew Dillon 					 */
668*572ff6f6SMatthew Dillon 					pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_LAST_PDGAIN;
669*572ff6f6SMatthew Dillon 				}
670*572ff6f6SMatthew Dillon 			} else {
671*572ff6f6SMatthew Dillon 				pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = 0;
672*572ff6f6SMatthew Dillon 			}
673*572ff6f6SMatthew Dillon 		}
674*572ff6f6SMatthew Dillon 	}
675*572ff6f6SMatthew Dillon }
676*572ff6f6SMatthew Dillon 
677*572ff6f6SMatthew Dillon static HAL_BOOL
ar2413EepromToRawDataset(struct ath_hal * ah,EEPROM_DATA_STRUCT_2413 * pCal,RAW_DATA_STRUCT_2413 * pRaw)678*572ff6f6SMatthew Dillon ar2413EepromToRawDataset(struct ath_hal *ah,
679*572ff6f6SMatthew Dillon 	EEPROM_DATA_STRUCT_2413 *pCal, RAW_DATA_STRUCT_2413 *pRaw)
680*572ff6f6SMatthew Dillon {
681*572ff6f6SMatthew Dillon 	uint16_t ii, jj, kk, ss;
682*572ff6f6SMatthew Dillon 	RAW_DATA_PER_PDGAIN_2413 *pRawXPD;
683*572ff6f6SMatthew Dillon 	/* ptr to array of info held per channel */
684*572ff6f6SMatthew Dillon 	EEPROM_DATA_PER_CHANNEL_2413 *pCalCh;
685*572ff6f6SMatthew Dillon 	uint16_t xgain_list[MAX_NUM_PDGAINS_PER_CHANNEL];
686*572ff6f6SMatthew Dillon 	uint16_t xpd_mask;
687*572ff6f6SMatthew Dillon 	uint32_t numPdGainsUsed;
688*572ff6f6SMatthew Dillon 
689*572ff6f6SMatthew Dillon 	HALASSERT(pRaw->xpd_mask == pCal->xpd_mask);
690*572ff6f6SMatthew Dillon 
691*572ff6f6SMatthew Dillon 	xgain_list[0] = 0xDEAD;
692*572ff6f6SMatthew Dillon 	xgain_list[1] = 0xDEAD;
693*572ff6f6SMatthew Dillon 	xgain_list[2] = 0xDEAD;
694*572ff6f6SMatthew Dillon 	xgain_list[3] = 0xDEAD;
695*572ff6f6SMatthew Dillon 
696*572ff6f6SMatthew Dillon 	numPdGainsUsed = 0;
697*572ff6f6SMatthew Dillon 	xpd_mask = pRaw->xpd_mask;
698*572ff6f6SMatthew Dillon 	for (jj = 0; jj < MAX_NUM_PDGAINS_PER_CHANNEL; jj++) {
699*572ff6f6SMatthew Dillon 		if ((xpd_mask >> (MAX_NUM_PDGAINS_PER_CHANNEL-jj-1)) & 1)
700*572ff6f6SMatthew Dillon 			xgain_list[numPdGainsUsed++] = MAX_NUM_PDGAINS_PER_CHANNEL-jj-1;
701*572ff6f6SMatthew Dillon 	}
702*572ff6f6SMatthew Dillon 
703*572ff6f6SMatthew Dillon 	pRaw->numChannels = pCal->numChannels;
704*572ff6f6SMatthew Dillon 	for (ii = 0; ii < pRaw->numChannels; ii++) {
705*572ff6f6SMatthew Dillon 		pCalCh = &(pCal->pDataPerChannel[ii]);
706*572ff6f6SMatthew Dillon 		pRaw->pDataPerChannel[ii].channelValue = pCalCh->channelValue;
707*572ff6f6SMatthew Dillon 
708*572ff6f6SMatthew Dillon 		/* numVpd has already been setup appropriately for the relevant pdGains */
709*572ff6f6SMatthew Dillon 		for (jj = 0; jj < numPdGainsUsed; jj++) {
710*572ff6f6SMatthew Dillon 			/* use jj for calDataset and ss for rawDataset */
711*572ff6f6SMatthew Dillon 			ss = xgain_list[jj];
712*572ff6f6SMatthew Dillon 			pRawXPD = &(pRaw->pDataPerChannel[ii].pDataPerPDGain[ss]);
713*572ff6f6SMatthew Dillon 			HALASSERT(pRawXPD->numVpd >= 1);
714*572ff6f6SMatthew Dillon 
715*572ff6f6SMatthew Dillon 			pRawXPD->pwr_t4[0] = (uint16_t)(4*pCalCh->pwr_I[jj]);
716*572ff6f6SMatthew Dillon 			pRawXPD->Vpd[0]    = pCalCh->Vpd_I[jj];
717*572ff6f6SMatthew Dillon 
718*572ff6f6SMatthew Dillon 			for (kk = 1; kk < pRawXPD->numVpd; kk++) {
719*572ff6f6SMatthew Dillon 				pRawXPD->pwr_t4[kk] = (int16_t)(pRawXPD->pwr_t4[kk-1] + 2*pCalCh->pwr_delta_t2[kk-1][jj]);
720*572ff6f6SMatthew Dillon 				pRawXPD->Vpd[kk] = (uint16_t)(pRawXPD->Vpd[kk-1] + pCalCh->Vpd_delta[kk-1][jj]);
721*572ff6f6SMatthew Dillon 			}
722*572ff6f6SMatthew Dillon 			/* loop over Vpds */
723*572ff6f6SMatthew Dillon 		}
724*572ff6f6SMatthew Dillon 		/* loop over pd_gains */
725*572ff6f6SMatthew Dillon 	}
726*572ff6f6SMatthew Dillon 	/* loop over channels */
727*572ff6f6SMatthew Dillon 	return AH_TRUE;
728*572ff6f6SMatthew Dillon }
729*572ff6f6SMatthew Dillon 
730*572ff6f6SMatthew Dillon static HAL_BOOL
readEepromRawPowerCalInfo2413(struct ath_hal * ah,HAL_EEPROM * ee)731*572ff6f6SMatthew Dillon readEepromRawPowerCalInfo2413(struct ath_hal *ah, HAL_EEPROM *ee)
732*572ff6f6SMatthew Dillon {
733*572ff6f6SMatthew Dillon 	/* NB: index is 1 less than numPdgains */
734*572ff6f6SMatthew Dillon 	static const uint16_t wordsForPdgains[] = { 4, 6, 9, 12 };
735*572ff6f6SMatthew Dillon 	EEPROM_DATA_STRUCT_2413 *pCal = AH_NULL;
736*572ff6f6SMatthew Dillon 	RAW_DATA_STRUCT_2413 *pRaw;
737*572ff6f6SMatthew Dillon 	int numEEPROMWordsPerChannel;
738*572ff6f6SMatthew Dillon 	uint32_t off;
739*572ff6f6SMatthew Dillon 	HAL_BOOL ret = AH_FALSE;
740*572ff6f6SMatthew Dillon 
741*572ff6f6SMatthew Dillon 	HALASSERT(ee->ee_version >= AR_EEPROM_VER5_0);
742*572ff6f6SMatthew Dillon 	HALASSERT(ee->ee_eepMap == 2);
743*572ff6f6SMatthew Dillon 
744*572ff6f6SMatthew Dillon 	pCal = ath_hal_malloc(sizeof(EEPROM_DATA_STRUCT_2413));
745*572ff6f6SMatthew Dillon 	if (pCal == AH_NULL)
746*572ff6f6SMatthew Dillon 		goto exit;
747*572ff6f6SMatthew Dillon 
748*572ff6f6SMatthew Dillon 	off = ee->ee_eepMap2PowerCalStart;
749*572ff6f6SMatthew Dillon 	if (ee->ee_Amode) {
750*572ff6f6SMatthew Dillon 		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
751*572ff6f6SMatthew Dillon 		pCal->xpd_mask = ee->ee_xgain[headerInfo11A];
752*572ff6f6SMatthew Dillon 		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
753*572ff6f6SMatthew Dillon 			NUM_11A_EEPROM_CHANNELS_2413, headerInfo11A)) {
754*572ff6f6SMatthew Dillon 			goto exit;
755*572ff6f6SMatthew Dillon 		}
756*572ff6f6SMatthew Dillon 		pRaw = &ee->ee_rawDataset2413[headerInfo11A];
757*572ff6f6SMatthew Dillon 		pRaw->xpd_mask = ee->ee_xgain[headerInfo11A];
758*572ff6f6SMatthew Dillon 		ar2413SetupRawDataset(pRaw, pCal);
759*572ff6f6SMatthew Dillon 		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
760*572ff6f6SMatthew Dillon 			goto exit;
761*572ff6f6SMatthew Dillon 		}
762*572ff6f6SMatthew Dillon 		/* setup offsets for mode_11a next */
763*572ff6f6SMatthew Dillon 		numEEPROMWordsPerChannel = wordsForPdgains[
764*572ff6f6SMatthew Dillon 			pCal->pDataPerChannel[0].numPdGains - 1];
765*572ff6f6SMatthew Dillon 		off += pCal->numChannels * numEEPROMWordsPerChannel + 5;
766*572ff6f6SMatthew Dillon 	}
767*572ff6f6SMatthew Dillon 	if (ee->ee_Bmode) {
768*572ff6f6SMatthew Dillon 		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
769*572ff6f6SMatthew Dillon 		pCal->xpd_mask = ee->ee_xgain[headerInfo11B];
770*572ff6f6SMatthew Dillon 		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
771*572ff6f6SMatthew Dillon 			NUM_2_4_EEPROM_CHANNELS_2413 , headerInfo11B)) {
772*572ff6f6SMatthew Dillon 			goto exit;
773*572ff6f6SMatthew Dillon 		}
774*572ff6f6SMatthew Dillon 		pRaw = &ee->ee_rawDataset2413[headerInfo11B];
775*572ff6f6SMatthew Dillon 		pRaw->xpd_mask = ee->ee_xgain[headerInfo11B];
776*572ff6f6SMatthew Dillon 		ar2413SetupRawDataset(pRaw, pCal);
777*572ff6f6SMatthew Dillon 		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
778*572ff6f6SMatthew Dillon 			goto exit;
779*572ff6f6SMatthew Dillon 		}
780*572ff6f6SMatthew Dillon 		/* setup offsets for mode_11g next */
781*572ff6f6SMatthew Dillon 		numEEPROMWordsPerChannel = wordsForPdgains[
782*572ff6f6SMatthew Dillon 			pCal->pDataPerChannel[0].numPdGains - 1];
783*572ff6f6SMatthew Dillon 		off += pCal->numChannels * numEEPROMWordsPerChannel + 2;
784*572ff6f6SMatthew Dillon 	}
785*572ff6f6SMatthew Dillon 	if (ee->ee_Gmode) {
786*572ff6f6SMatthew Dillon 		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
787*572ff6f6SMatthew Dillon 		pCal->xpd_mask = ee->ee_xgain[headerInfo11G];
788*572ff6f6SMatthew Dillon 		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
789*572ff6f6SMatthew Dillon 			NUM_2_4_EEPROM_CHANNELS_2413, headerInfo11G)) {
790*572ff6f6SMatthew Dillon 			goto exit;
791*572ff6f6SMatthew Dillon 		}
792*572ff6f6SMatthew Dillon 		pRaw = &ee->ee_rawDataset2413[headerInfo11G];
793*572ff6f6SMatthew Dillon 		pRaw->xpd_mask = ee->ee_xgain[headerInfo11G];
794*572ff6f6SMatthew Dillon 		ar2413SetupRawDataset(pRaw, pCal);
795*572ff6f6SMatthew Dillon 		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
796*572ff6f6SMatthew Dillon 			goto exit;
797*572ff6f6SMatthew Dillon 		}
798*572ff6f6SMatthew Dillon 	}
799*572ff6f6SMatthew Dillon 	ret = AH_TRUE;
800*572ff6f6SMatthew Dillon  exit:
801*572ff6f6SMatthew Dillon 	if (pCal != AH_NULL)
802*572ff6f6SMatthew Dillon 		ath_hal_free(pCal);
803*572ff6f6SMatthew Dillon 	return ret;
804*572ff6f6SMatthew Dillon }
805*572ff6f6SMatthew Dillon 
806*572ff6f6SMatthew Dillon /*
807*572ff6f6SMatthew Dillon  * Now copy EEPROM Raw Power Calibration per frequency contents
808*572ff6f6SMatthew Dillon  * into the allocated space
809*572ff6f6SMatthew Dillon  */
810*572ff6f6SMatthew Dillon static HAL_BOOL
readEepromRawPowerCalInfo(struct ath_hal * ah,HAL_EEPROM * ee)811*572ff6f6SMatthew Dillon readEepromRawPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee)
812*572ff6f6SMatthew Dillon {
813*572ff6f6SMatthew Dillon #define	EEREAD(_off) do {				\
814*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
815*572ff6f6SMatthew Dillon 		return AH_FALSE;			\
816*572ff6f6SMatthew Dillon } while (0)
817*572ff6f6SMatthew Dillon 	uint16_t eeval, nchan;
818*572ff6f6SMatthew Dillon 	uint32_t off;
819*572ff6f6SMatthew Dillon 	int i, j, mode;
820*572ff6f6SMatthew Dillon 
821*572ff6f6SMatthew Dillon         if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1)
822*572ff6f6SMatthew Dillon 		return readEepromRawPowerCalInfo5112(ah, ee);
823*572ff6f6SMatthew Dillon 	if (ee->ee_version >= AR_EEPROM_VER5_0 && ee->ee_eepMap == 2)
824*572ff6f6SMatthew Dillon 		return readEepromRawPowerCalInfo2413(ah, ee);
825*572ff6f6SMatthew Dillon 
826*572ff6f6SMatthew Dillon 	/*
827*572ff6f6SMatthew Dillon 	 * Group 2:  read raw power data for all frequency piers
828*572ff6f6SMatthew Dillon 	 *
829*572ff6f6SMatthew Dillon 	 * NOTE: Group 2 contains the raw power calibration
830*572ff6f6SMatthew Dillon 	 *	 information for each of the channels that
831*572ff6f6SMatthew Dillon 	 *	 we recorded above.
832*572ff6f6SMatthew Dillon 	 */
833*572ff6f6SMatthew Dillon 	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
834*572ff6f6SMatthew Dillon 		uint16_t *pChannels = AH_NULL;
835*572ff6f6SMatthew Dillon 		DATA_PER_CHANNEL *pChannelData = AH_NULL;
836*572ff6f6SMatthew Dillon 
837*572ff6f6SMatthew Dillon 		off = ee->ee_version >= AR_EEPROM_VER3_3 ?
838*572ff6f6SMatthew Dillon 			GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2;
839*572ff6f6SMatthew Dillon 		switch (mode) {
840*572ff6f6SMatthew Dillon 		case headerInfo11A:
841*572ff6f6SMatthew Dillon 			off      	+= GROUP2_OFFSET;
842*572ff6f6SMatthew Dillon 			nchan		= ee->ee_numChannels11a;
843*572ff6f6SMatthew Dillon 			pChannelData	= ee->ee_dataPerChannel11a;
844*572ff6f6SMatthew Dillon 			pChannels	= ee->ee_channels11a;
845*572ff6f6SMatthew Dillon 			break;
846*572ff6f6SMatthew Dillon 		case headerInfo11B:
847*572ff6f6SMatthew Dillon 			if (!ee->ee_Bmode)
848*572ff6f6SMatthew Dillon 				continue;
849*572ff6f6SMatthew Dillon 			off		+= GROUP3_OFFSET;
850*572ff6f6SMatthew Dillon 			nchan		= ee->ee_numChannels2_4;
851*572ff6f6SMatthew Dillon 			pChannelData	= ee->ee_dataPerChannel11b;
852*572ff6f6SMatthew Dillon 			pChannels	= ee->ee_channels11b;
853*572ff6f6SMatthew Dillon 			break;
854*572ff6f6SMatthew Dillon 		case headerInfo11G:
855*572ff6f6SMatthew Dillon 			if (!ee->ee_Gmode)
856*572ff6f6SMatthew Dillon 				continue;
857*572ff6f6SMatthew Dillon 			off		+= GROUP4_OFFSET;
858*572ff6f6SMatthew Dillon 			nchan		= ee->ee_numChannels2_4;
859*572ff6f6SMatthew Dillon 			pChannelData	= ee->ee_dataPerChannel11g;
860*572ff6f6SMatthew Dillon 			pChannels	= ee->ee_channels11g;
861*572ff6f6SMatthew Dillon 			break;
862*572ff6f6SMatthew Dillon 		default:
863*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
864*572ff6f6SMatthew Dillon 			    __func__, mode);
865*572ff6f6SMatthew Dillon 			return AH_FALSE;
866*572ff6f6SMatthew Dillon 		}
867*572ff6f6SMatthew Dillon 		for (i = 0; i < nchan; i++) {
868*572ff6f6SMatthew Dillon 			pChannelData->channelValue = pChannels[i];
869*572ff6f6SMatthew Dillon 
870*572ff6f6SMatthew Dillon 			EEREAD(off++);
871*572ff6f6SMatthew Dillon 			pChannelData->pcdacMax     = (uint16_t)((eeval >> 10) & PCDAC_MASK);
872*572ff6f6SMatthew Dillon 			pChannelData->pcdacMin     = (uint16_t)((eeval >> 4) & PCDAC_MASK);
873*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[0] = (uint16_t)((eeval << 2) & POWER_MASK);
874*572ff6f6SMatthew Dillon 
875*572ff6f6SMatthew Dillon 			EEREAD(off++);
876*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[0] |= (uint16_t)((eeval >> 14) & 0x3);
877*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[1] = (uint16_t)((eeval >> 8) & POWER_MASK);
878*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[2] = (uint16_t)((eeval >> 2) & POWER_MASK);
879*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[3] = (uint16_t)((eeval << 4) & POWER_MASK);
880*572ff6f6SMatthew Dillon 
881*572ff6f6SMatthew Dillon 			EEREAD(off++);
882*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[3] |= (uint16_t)((eeval >> 12) & 0xf);
883*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[4] = (uint16_t)((eeval >> 6) & POWER_MASK);
884*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[5] = (uint16_t)(eeval  & POWER_MASK);
885*572ff6f6SMatthew Dillon 
886*572ff6f6SMatthew Dillon 			EEREAD(off++);
887*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[6] = (uint16_t)((eeval >> 10) & POWER_MASK);
888*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[7] = (uint16_t)((eeval >> 4) & POWER_MASK);
889*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[8] = (uint16_t)((eeval << 2) & POWER_MASK);
890*572ff6f6SMatthew Dillon 
891*572ff6f6SMatthew Dillon 			EEREAD(off++);
892*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[8] |= (uint16_t)((eeval >> 14) & 0x3);
893*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[9] = (uint16_t)((eeval >> 8) & POWER_MASK);
894*572ff6f6SMatthew Dillon 			pChannelData->PwrValues[10] = (uint16_t)((eeval >> 2) & POWER_MASK);
895*572ff6f6SMatthew Dillon 
896*572ff6f6SMatthew Dillon 			getPcdacInterceptsFromPcdacMinMax(ee,
897*572ff6f6SMatthew Dillon 				pChannelData->pcdacMin, pChannelData->pcdacMax,
898*572ff6f6SMatthew Dillon 				pChannelData->PcdacValues) ;
899*572ff6f6SMatthew Dillon 
900*572ff6f6SMatthew Dillon 			for (j = 0; j < pChannelData->numPcdacValues; j++) {
901*572ff6f6SMatthew Dillon 				pChannelData->PwrValues[j] = (uint16_t)(
902*572ff6f6SMatthew Dillon 					PWR_STEP * pChannelData->PwrValues[j]);
903*572ff6f6SMatthew Dillon 				/* Note these values are scaled up. */
904*572ff6f6SMatthew Dillon 			}
905*572ff6f6SMatthew Dillon 			pChannelData++;
906*572ff6f6SMatthew Dillon 		}
907*572ff6f6SMatthew Dillon 	}
908*572ff6f6SMatthew Dillon 	return AH_TRUE;
909*572ff6f6SMatthew Dillon #undef EEREAD
910*572ff6f6SMatthew Dillon }
911*572ff6f6SMatthew Dillon 
912*572ff6f6SMatthew Dillon /*
913*572ff6f6SMatthew Dillon  * Copy EEPROM Target Power Calbration per rate contents
914*572ff6f6SMatthew Dillon  * into the allocated space
915*572ff6f6SMatthew Dillon  */
916*572ff6f6SMatthew Dillon static HAL_BOOL
readEepromTargetPowerCalInfo(struct ath_hal * ah,HAL_EEPROM * ee)917*572ff6f6SMatthew Dillon readEepromTargetPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee)
918*572ff6f6SMatthew Dillon {
919*572ff6f6SMatthew Dillon #define	EEREAD(_off) do {				\
920*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
921*572ff6f6SMatthew Dillon 		return AH_FALSE;			\
922*572ff6f6SMatthew Dillon } while (0)
923*572ff6f6SMatthew Dillon 	uint16_t eeval, enable24;
924*572ff6f6SMatthew Dillon 	uint32_t off;
925*572ff6f6SMatthew Dillon 	int i, mode, nchan;
926*572ff6f6SMatthew Dillon 
927*572ff6f6SMatthew Dillon 	enable24 = ee->ee_Bmode || ee->ee_Gmode;
928*572ff6f6SMatthew Dillon 	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
929*572ff6f6SMatthew Dillon 		TRGT_POWER_INFO *pPowerInfo;
930*572ff6f6SMatthew Dillon 		uint16_t *pNumTrgtChannels;
931*572ff6f6SMatthew Dillon 
932*572ff6f6SMatthew Dillon 		off = ee->ee_version >= AR_EEPROM_VER4_0 ?
933*572ff6f6SMatthew Dillon 				ee->ee_targetPowersStart - GROUP5_OFFSET :
934*572ff6f6SMatthew Dillon 		      ee->ee_version >= AR_EEPROM_VER3_3 ?
935*572ff6f6SMatthew Dillon 				GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2;
936*572ff6f6SMatthew Dillon 		switch (mode) {
937*572ff6f6SMatthew Dillon 		case headerInfo11A:
938*572ff6f6SMatthew Dillon 			off += GROUP5_OFFSET;
939*572ff6f6SMatthew Dillon 			nchan = NUM_TEST_FREQUENCIES;
940*572ff6f6SMatthew Dillon 			pPowerInfo = ee->ee_trgtPwr_11a;
941*572ff6f6SMatthew Dillon 			pNumTrgtChannels = &ee->ee_numTargetPwr_11a;
942*572ff6f6SMatthew Dillon 			break;
943*572ff6f6SMatthew Dillon 		case headerInfo11B:
944*572ff6f6SMatthew Dillon 			if (!enable24)
945*572ff6f6SMatthew Dillon 				continue;
946*572ff6f6SMatthew Dillon 			off += GROUP6_OFFSET;
947*572ff6f6SMatthew Dillon 			nchan = 2;
948*572ff6f6SMatthew Dillon 			pPowerInfo = ee->ee_trgtPwr_11b;
949*572ff6f6SMatthew Dillon 			pNumTrgtChannels = &ee->ee_numTargetPwr_11b;
950*572ff6f6SMatthew Dillon 			break;
951*572ff6f6SMatthew Dillon 		case headerInfo11G:
952*572ff6f6SMatthew Dillon 			if (!enable24)
953*572ff6f6SMatthew Dillon 				continue;
954*572ff6f6SMatthew Dillon 			off += GROUP7_OFFSET;
955*572ff6f6SMatthew Dillon 			nchan = 3;
956*572ff6f6SMatthew Dillon 			pPowerInfo = ee->ee_trgtPwr_11g;
957*572ff6f6SMatthew Dillon 			pNumTrgtChannels = &ee->ee_numTargetPwr_11g;
958*572ff6f6SMatthew Dillon 			break;
959*572ff6f6SMatthew Dillon 		default:
960*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
961*572ff6f6SMatthew Dillon 			    __func__, mode);
962*572ff6f6SMatthew Dillon 			return AH_FALSE;
963*572ff6f6SMatthew Dillon 		}
964*572ff6f6SMatthew Dillon 		*pNumTrgtChannels = 0;
965*572ff6f6SMatthew Dillon 		for (i = 0; i < nchan; i++) {
966*572ff6f6SMatthew Dillon 			EEREAD(off++);
967*572ff6f6SMatthew Dillon 			if (ee->ee_version >= AR_EEPROM_VER3_3) {
968*572ff6f6SMatthew Dillon 				pPowerInfo->testChannel = (eeval >> 8) & 0xff;
969*572ff6f6SMatthew Dillon 			} else {
970*572ff6f6SMatthew Dillon 				pPowerInfo->testChannel = (eeval >> 9) & 0x7f;
971*572ff6f6SMatthew Dillon 			}
972*572ff6f6SMatthew Dillon 
973*572ff6f6SMatthew Dillon 			if (pPowerInfo->testChannel != 0) {
974*572ff6f6SMatthew Dillon 				/* get the channel value and read rest of info */
975*572ff6f6SMatthew Dillon 				if (mode == headerInfo11A) {
976*572ff6f6SMatthew Dillon 					pPowerInfo->testChannel = fbin2freq(ee, pPowerInfo->testChannel);
977*572ff6f6SMatthew Dillon 				} else {
978*572ff6f6SMatthew Dillon 					pPowerInfo->testChannel = fbin2freq_2p4(ee, pPowerInfo->testChannel);
979*572ff6f6SMatthew Dillon 				}
980*572ff6f6SMatthew Dillon 
981*572ff6f6SMatthew Dillon 				if (ee->ee_version >= AR_EEPROM_VER3_3) {
982*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr6_24 = (eeval >> 2) & POWER_MASK;
983*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr36   = (eeval << 4) & POWER_MASK;
984*572ff6f6SMatthew Dillon 				} else {
985*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr6_24 = (eeval >> 3) & POWER_MASK;
986*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr36   = (eeval << 3) & POWER_MASK;
987*572ff6f6SMatthew Dillon 				}
988*572ff6f6SMatthew Dillon 
989*572ff6f6SMatthew Dillon 				EEREAD(off++);
990*572ff6f6SMatthew Dillon 				if (ee->ee_version >= AR_EEPROM_VER3_3) {
991*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr36 |= (eeval >> 12) & 0xf;
992*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr48 = (eeval >> 6) & POWER_MASK;
993*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr54 =  eeval & POWER_MASK;
994*572ff6f6SMatthew Dillon 				} else {
995*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr36 |= (eeval >> 13) & 0x7;
996*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr48 = (eeval >> 7) & POWER_MASK;
997*572ff6f6SMatthew Dillon 					pPowerInfo->twicePwr54 = (eeval >> 1) & POWER_MASK;
998*572ff6f6SMatthew Dillon 				}
999*572ff6f6SMatthew Dillon 				(*pNumTrgtChannels)++;
1000*572ff6f6SMatthew Dillon 			}
1001*572ff6f6SMatthew Dillon 			pPowerInfo++;
1002*572ff6f6SMatthew Dillon 		}
1003*572ff6f6SMatthew Dillon 	}
1004*572ff6f6SMatthew Dillon 	return AH_TRUE;
1005*572ff6f6SMatthew Dillon #undef EEREAD
1006*572ff6f6SMatthew Dillon }
1007*572ff6f6SMatthew Dillon 
1008*572ff6f6SMatthew Dillon /*
1009*572ff6f6SMatthew Dillon  * Now copy EEPROM Coformance Testing Limits contents
1010*572ff6f6SMatthew Dillon  * into the allocated space
1011*572ff6f6SMatthew Dillon  */
1012*572ff6f6SMatthew Dillon static HAL_BOOL
readEepromCTLInfo(struct ath_hal * ah,HAL_EEPROM * ee)1013*572ff6f6SMatthew Dillon readEepromCTLInfo(struct ath_hal *ah, HAL_EEPROM *ee)
1014*572ff6f6SMatthew Dillon {
1015*572ff6f6SMatthew Dillon #define	EEREAD(_off) do {				\
1016*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
1017*572ff6f6SMatthew Dillon 		return AH_FALSE;			\
1018*572ff6f6SMatthew Dillon } while (0)
1019*572ff6f6SMatthew Dillon 	RD_EDGES_POWER *rep;
1020*572ff6f6SMatthew Dillon 	uint16_t eeval;
1021*572ff6f6SMatthew Dillon 	uint32_t off;
1022*572ff6f6SMatthew Dillon 	int i, j;
1023*572ff6f6SMatthew Dillon 
1024*572ff6f6SMatthew Dillon 	rep = ee->ee_rdEdgesPower;
1025*572ff6f6SMatthew Dillon 
1026*572ff6f6SMatthew Dillon 	off = GROUP8_OFFSET +
1027*572ff6f6SMatthew Dillon 		(ee->ee_version >= AR_EEPROM_VER4_0 ?
1028*572ff6f6SMatthew Dillon 			ee->ee_targetPowersStart - GROUP5_OFFSET :
1029*572ff6f6SMatthew Dillon 	         ee->ee_version >= AR_EEPROM_VER3_3 ?
1030*572ff6f6SMatthew Dillon 			GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2);
1031*572ff6f6SMatthew Dillon 	for (i = 0; i < ee->ee_numCtls; i++) {
1032*572ff6f6SMatthew Dillon 		if (ee->ee_ctl[i] == 0) {
1033*572ff6f6SMatthew Dillon 			/* Move offset and edges */
1034*572ff6f6SMatthew Dillon 			off += (ee->ee_version >= AR_EEPROM_VER3_3 ? 8 : 7);
1035*572ff6f6SMatthew Dillon 			rep += NUM_EDGES;
1036*572ff6f6SMatthew Dillon 			continue;
1037*572ff6f6SMatthew Dillon 		}
1038*572ff6f6SMatthew Dillon 		if (ee->ee_version >= AR_EEPROM_VER3_3) {
1039*572ff6f6SMatthew Dillon 			for (j = 0; j < NUM_EDGES; j += 2) {
1040*572ff6f6SMatthew Dillon 				EEREAD(off++);
1041*572ff6f6SMatthew Dillon 				rep[j].rdEdge = (eeval >> 8) & FREQ_MASK_3_3;
1042*572ff6f6SMatthew Dillon 				rep[j+1].rdEdge = eeval & FREQ_MASK_3_3;
1043*572ff6f6SMatthew Dillon 			}
1044*572ff6f6SMatthew Dillon 			for (j = 0; j < NUM_EDGES; j += 2) {
1045*572ff6f6SMatthew Dillon 				EEREAD(off++);
1046*572ff6f6SMatthew Dillon 				rep[j].twice_rdEdgePower =
1047*572ff6f6SMatthew Dillon 					(eeval >> 8) & POWER_MASK;
1048*572ff6f6SMatthew Dillon 				rep[j].flag = (eeval >> 14) & 1;
1049*572ff6f6SMatthew Dillon 				rep[j+1].twice_rdEdgePower = eeval & POWER_MASK;
1050*572ff6f6SMatthew Dillon 				rep[j+1].flag = (eeval >> 6) & 1;
1051*572ff6f6SMatthew Dillon 			}
1052*572ff6f6SMatthew Dillon 		} else {
1053*572ff6f6SMatthew Dillon 			EEREAD(off++);
1054*572ff6f6SMatthew Dillon 			rep[0].rdEdge = (eeval >> 9) & FREQ_MASK;
1055*572ff6f6SMatthew Dillon 			rep[1].rdEdge = (eeval >> 2) & FREQ_MASK;
1056*572ff6f6SMatthew Dillon 			rep[2].rdEdge = (eeval << 5) & FREQ_MASK;
1057*572ff6f6SMatthew Dillon 
1058*572ff6f6SMatthew Dillon 			EEREAD(off++);
1059*572ff6f6SMatthew Dillon 			rep[2].rdEdge |= (eeval >> 11) & 0x1f;
1060*572ff6f6SMatthew Dillon 			rep[3].rdEdge = (eeval >> 4) & FREQ_MASK;
1061*572ff6f6SMatthew Dillon 			rep[4].rdEdge = (eeval << 3) & FREQ_MASK;
1062*572ff6f6SMatthew Dillon 
1063*572ff6f6SMatthew Dillon 			EEREAD(off++);
1064*572ff6f6SMatthew Dillon 			rep[4].rdEdge |= (eeval >> 13) & 0x7;
1065*572ff6f6SMatthew Dillon 			rep[5].rdEdge = (eeval >> 6) & FREQ_MASK;
1066*572ff6f6SMatthew Dillon 			rep[6].rdEdge = (eeval << 1) & FREQ_MASK;
1067*572ff6f6SMatthew Dillon 
1068*572ff6f6SMatthew Dillon 			EEREAD(off++);
1069*572ff6f6SMatthew Dillon 			rep[6].rdEdge |= (eeval >> 15) & 0x1;
1070*572ff6f6SMatthew Dillon 			rep[7].rdEdge = (eeval >> 8) & FREQ_MASK;
1071*572ff6f6SMatthew Dillon 
1072*572ff6f6SMatthew Dillon 			rep[0].twice_rdEdgePower = (eeval >> 2) & POWER_MASK;
1073*572ff6f6SMatthew Dillon 			rep[1].twice_rdEdgePower = (eeval << 4) & POWER_MASK;
1074*572ff6f6SMatthew Dillon 
1075*572ff6f6SMatthew Dillon 			EEREAD(off++);
1076*572ff6f6SMatthew Dillon 			rep[1].twice_rdEdgePower |= (eeval >> 12) & 0xf;
1077*572ff6f6SMatthew Dillon 			rep[2].twice_rdEdgePower = (eeval >> 6) & POWER_MASK;
1078*572ff6f6SMatthew Dillon 			rep[3].twice_rdEdgePower = eeval & POWER_MASK;
1079*572ff6f6SMatthew Dillon 
1080*572ff6f6SMatthew Dillon 			EEREAD(off++);
1081*572ff6f6SMatthew Dillon 			rep[4].twice_rdEdgePower = (eeval >> 10) & POWER_MASK;
1082*572ff6f6SMatthew Dillon 			rep[5].twice_rdEdgePower = (eeval >> 4) & POWER_MASK;
1083*572ff6f6SMatthew Dillon 			rep[6].twice_rdEdgePower = (eeval << 2) & POWER_MASK;
1084*572ff6f6SMatthew Dillon 
1085*572ff6f6SMatthew Dillon 			EEREAD(off++);
1086*572ff6f6SMatthew Dillon 			rep[6].twice_rdEdgePower |= (eeval >> 14) & 0x3;
1087*572ff6f6SMatthew Dillon 			rep[7].twice_rdEdgePower = (eeval >> 8) & POWER_MASK;
1088*572ff6f6SMatthew Dillon 		}
1089*572ff6f6SMatthew Dillon 
1090*572ff6f6SMatthew Dillon 		for (j = 0; j < NUM_EDGES; j++ ) {
1091*572ff6f6SMatthew Dillon 			if (rep[j].rdEdge != 0 || rep[j].twice_rdEdgePower != 0) {
1092*572ff6f6SMatthew Dillon 				if ((ee->ee_ctl[i] & CTL_MODE_M) == CTL_11A ||
1093*572ff6f6SMatthew Dillon 				    (ee->ee_ctl[i] & CTL_MODE_M) == CTL_TURBO) {
1094*572ff6f6SMatthew Dillon 					rep[j].rdEdge = fbin2freq(ee, rep[j].rdEdge);
1095*572ff6f6SMatthew Dillon 				} else {
1096*572ff6f6SMatthew Dillon 					rep[j].rdEdge = fbin2freq_2p4(ee, rep[j].rdEdge);
1097*572ff6f6SMatthew Dillon 				}
1098*572ff6f6SMatthew Dillon 			}
1099*572ff6f6SMatthew Dillon 		}
1100*572ff6f6SMatthew Dillon 		rep += NUM_EDGES;
1101*572ff6f6SMatthew Dillon 	}
1102*572ff6f6SMatthew Dillon 	return AH_TRUE;
1103*572ff6f6SMatthew Dillon #undef EEREAD
1104*572ff6f6SMatthew Dillon }
1105*572ff6f6SMatthew Dillon 
1106*572ff6f6SMatthew Dillon /*
1107*572ff6f6SMatthew Dillon  * Read the individual header fields for a Rev 3 EEPROM
1108*572ff6f6SMatthew Dillon  */
1109*572ff6f6SMatthew Dillon static HAL_BOOL
readHeaderInfo(struct ath_hal * ah,HAL_EEPROM * ee)1110*572ff6f6SMatthew Dillon readHeaderInfo(struct ath_hal *ah, HAL_EEPROM *ee)
1111*572ff6f6SMatthew Dillon {
1112*572ff6f6SMatthew Dillon #define	EEREAD(_off) do {				\
1113*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
1114*572ff6f6SMatthew Dillon 		return AH_FALSE;			\
1115*572ff6f6SMatthew Dillon } while (0)
1116*572ff6f6SMatthew Dillon 	static const uint32_t headerOffset3_0[] = {
1117*572ff6f6SMatthew Dillon 		0x00C2, /* 0 - Mode bits, device type, max turbo power */
1118*572ff6f6SMatthew Dillon 		0x00C4, /* 1 - 2.4 and 5 antenna gain */
1119*572ff6f6SMatthew Dillon 		0x00C5, /* 2 - Begin 11A modal section */
1120*572ff6f6SMatthew Dillon 		0x00D0, /* 3 - Begin 11B modal section */
1121*572ff6f6SMatthew Dillon 		0x00DA, /* 4 - Begin 11G modal section */
1122*572ff6f6SMatthew Dillon 		0x00E4  /* 5 - Begin CTL section */
1123*572ff6f6SMatthew Dillon 	};
1124*572ff6f6SMatthew Dillon 	static const uint32_t headerOffset3_3[] = {
1125*572ff6f6SMatthew Dillon 		0x00C2, /* 0 - Mode bits, device type, max turbo power */
1126*572ff6f6SMatthew Dillon 		0x00C3, /* 1 - 2.4 and 5 antenna gain */
1127*572ff6f6SMatthew Dillon 		0x00D4, /* 2 - Begin 11A modal section */
1128*572ff6f6SMatthew Dillon 		0x00F2, /* 3 - Begin 11B modal section */
1129*572ff6f6SMatthew Dillon 		0x010D, /* 4 - Begin 11G modal section */
1130*572ff6f6SMatthew Dillon 		0x0128  /* 5 - Begin CTL section */
1131*572ff6f6SMatthew Dillon 	};
1132*572ff6f6SMatthew Dillon 
1133*572ff6f6SMatthew Dillon 	static const uint32_t regCapOffsetPre4_0 = 0x00CF;
1134*572ff6f6SMatthew Dillon 	static const uint32_t regCapOffsetPost4_0 = 0x00CA;
1135*572ff6f6SMatthew Dillon 
1136*572ff6f6SMatthew Dillon 	const uint32_t *header;
1137*572ff6f6SMatthew Dillon 	uint32_t off;
1138*572ff6f6SMatthew Dillon 	uint16_t eeval;
1139*572ff6f6SMatthew Dillon 	int i;
1140*572ff6f6SMatthew Dillon 
1141*572ff6f6SMatthew Dillon 	/* initialize cckOfdmGainDelta for < 4.2 eeprom */
1142*572ff6f6SMatthew Dillon 	ee->ee_cckOfdmGainDelta = CCK_OFDM_GAIN_DELTA;
1143*572ff6f6SMatthew Dillon 	ee->ee_scaledCh14FilterCckDelta = TENX_CH14_FILTER_CCK_DELTA_INIT;
1144*572ff6f6SMatthew Dillon 
1145*572ff6f6SMatthew Dillon 	if (ee->ee_version >= AR_EEPROM_VER3_3) {
1146*572ff6f6SMatthew Dillon 		header = headerOffset3_3;
1147*572ff6f6SMatthew Dillon 		ee->ee_numCtls = NUM_CTLS_3_3;
1148*572ff6f6SMatthew Dillon 	} else {
1149*572ff6f6SMatthew Dillon 		header = headerOffset3_0;
1150*572ff6f6SMatthew Dillon 		ee->ee_numCtls = NUM_CTLS;
1151*572ff6f6SMatthew Dillon 	}
1152*572ff6f6SMatthew Dillon 	HALASSERT(ee->ee_numCtls <= NUM_CTLS_MAX);
1153*572ff6f6SMatthew Dillon 
1154*572ff6f6SMatthew Dillon 	EEREAD(header[0]);
1155*572ff6f6SMatthew Dillon 	ee->ee_turbo5Disable	= (eeval >> 15) & 0x01;
1156*572ff6f6SMatthew Dillon 	ee->ee_rfKill		= (eeval >> 14) & 0x01;
1157*572ff6f6SMatthew Dillon 	ee->ee_deviceType	= (eeval >> 11) & 0x07;
1158*572ff6f6SMatthew Dillon 	ee->ee_turbo2WMaxPower5	= (eeval >> 4) & 0x7F;
1159*572ff6f6SMatthew Dillon 	if (ee->ee_version >= AR_EEPROM_VER4_0)
1160*572ff6f6SMatthew Dillon 		ee->ee_turbo2Disable	= (eeval >> 3) & 0x01;
1161*572ff6f6SMatthew Dillon 	else
1162*572ff6f6SMatthew Dillon 		ee->ee_turbo2Disable	= 1;
1163*572ff6f6SMatthew Dillon 	ee->ee_Gmode		= (eeval >> 2) & 0x01;
1164*572ff6f6SMatthew Dillon 	ee->ee_Bmode		= (eeval >> 1) & 0x01;
1165*572ff6f6SMatthew Dillon 	ee->ee_Amode		= (eeval & 0x01);
1166*572ff6f6SMatthew Dillon 
1167*572ff6f6SMatthew Dillon 	off = header[1];
1168*572ff6f6SMatthew Dillon 	EEREAD(off++);
1169*572ff6f6SMatthew Dillon 	ee->ee_antennaGainMax[0] = (int8_t)((eeval >> 8) & 0xFF);
1170*572ff6f6SMatthew Dillon 	ee->ee_antennaGainMax[1] = (int8_t)(eeval & 0xFF);
1171*572ff6f6SMatthew Dillon 	if (ee->ee_version >= AR_EEPROM_VER4_0) {
1172*572ff6f6SMatthew Dillon 		EEREAD(off++);
1173*572ff6f6SMatthew Dillon 		ee->ee_eepMap		 = (eeval>>14) & 0x3;
1174*572ff6f6SMatthew Dillon 		ee->ee_disableXr5	 = (eeval>>13) & 0x1;
1175*572ff6f6SMatthew Dillon 		ee->ee_disableXr2	 = (eeval>>12) & 0x1;
1176*572ff6f6SMatthew Dillon 		ee->ee_earStart		 = eeval & 0xfff;
1177*572ff6f6SMatthew Dillon 
1178*572ff6f6SMatthew Dillon 		EEREAD(off++);
1179*572ff6f6SMatthew Dillon 		ee->ee_targetPowersStart = eeval & 0xfff;
1180*572ff6f6SMatthew Dillon 		ee->ee_exist32kHzCrystal = (eeval>>14) & 0x1;
1181*572ff6f6SMatthew Dillon 
1182*572ff6f6SMatthew Dillon 		if (ee->ee_version >= AR_EEPROM_VER5_0) {
1183*572ff6f6SMatthew Dillon 			off += 2;
1184*572ff6f6SMatthew Dillon 			EEREAD(off);
1185*572ff6f6SMatthew Dillon 			ee->ee_eepMap2PowerCalStart = (eeval >> 4) & 0xfff;
1186*572ff6f6SMatthew Dillon 			/* Properly cal'ed 5.0 devices should be non-zero */
1187*572ff6f6SMatthew Dillon 		}
1188*572ff6f6SMatthew Dillon 	}
1189*572ff6f6SMatthew Dillon 
1190*572ff6f6SMatthew Dillon 	/* Read the moded sections of the EEPROM header in the order A, B, G */
1191*572ff6f6SMatthew Dillon 	for (i = headerInfo11A; i <= headerInfo11G; i++) {
1192*572ff6f6SMatthew Dillon 		/* Set the offset via the index */
1193*572ff6f6SMatthew Dillon 		off = header[2 + i];
1194*572ff6f6SMatthew Dillon 
1195*572ff6f6SMatthew Dillon 		EEREAD(off++);
1196*572ff6f6SMatthew Dillon 		ee->ee_switchSettling[i] = (eeval >> 8) & 0x7f;
1197*572ff6f6SMatthew Dillon 		ee->ee_txrxAtten[i] = (eeval >> 2) & 0x3f;
1198*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[0][i] = (eeval << 4) & 0x3f;
1199*572ff6f6SMatthew Dillon 
1200*572ff6f6SMatthew Dillon 		EEREAD(off++);
1201*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[0][i] |= (eeval >> 12) & 0x0f;
1202*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[1][i] = (eeval >> 6) & 0x3f;
1203*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[2][i] = eeval & 0x3f;
1204*572ff6f6SMatthew Dillon 
1205*572ff6f6SMatthew Dillon 		EEREAD(off++);
1206*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[3][i] = (eeval >> 10)  & 0x3f;
1207*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[4][i] = (eeval >> 4)  & 0x3f;
1208*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[5][i] = (eeval << 2)  & 0x3f;
1209*572ff6f6SMatthew Dillon 
1210*572ff6f6SMatthew Dillon 		EEREAD(off++);
1211*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[5][i] |= (eeval >> 14)  & 0x03;
1212*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[6][i] = (eeval >> 8)  & 0x3f;
1213*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[7][i] = (eeval >> 2)  & 0x3f;
1214*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[8][i] = (eeval << 4)  & 0x3f;
1215*572ff6f6SMatthew Dillon 
1216*572ff6f6SMatthew Dillon 		EEREAD(off++);
1217*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[8][i] |= (eeval >> 12)  & 0x0f;
1218*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[9][i] = (eeval >> 6)  & 0x3f;
1219*572ff6f6SMatthew Dillon 		ee->ee_antennaControl[10][i] = eeval & 0x3f;
1220*572ff6f6SMatthew Dillon 
1221*572ff6f6SMatthew Dillon 		EEREAD(off++);
1222*572ff6f6SMatthew Dillon 		ee->ee_adcDesiredSize[i] = (int8_t)((eeval >> 8)  & 0xff);
1223*572ff6f6SMatthew Dillon 		switch (i) {
1224*572ff6f6SMatthew Dillon 		case headerInfo11A:
1225*572ff6f6SMatthew Dillon 			ee->ee_ob4 = (eeval >> 5)  & 0x07;
1226*572ff6f6SMatthew Dillon 			ee->ee_db4 = (eeval >> 2)  & 0x07;
1227*572ff6f6SMatthew Dillon 			ee->ee_ob3 = (eeval << 1)  & 0x07;
1228*572ff6f6SMatthew Dillon 			break;
1229*572ff6f6SMatthew Dillon 		case headerInfo11B:
1230*572ff6f6SMatthew Dillon 			ee->ee_obFor24 = (eeval >> 4)  & 0x07;
1231*572ff6f6SMatthew Dillon 			ee->ee_dbFor24 = eeval & 0x07;
1232*572ff6f6SMatthew Dillon 			break;
1233*572ff6f6SMatthew Dillon 		case headerInfo11G:
1234*572ff6f6SMatthew Dillon 			ee->ee_obFor24g = (eeval >> 4)  & 0x07;
1235*572ff6f6SMatthew Dillon 			ee->ee_dbFor24g = eeval & 0x07;
1236*572ff6f6SMatthew Dillon 			break;
1237*572ff6f6SMatthew Dillon 		}
1238*572ff6f6SMatthew Dillon 
1239*572ff6f6SMatthew Dillon 		if (i == headerInfo11A) {
1240*572ff6f6SMatthew Dillon 			EEREAD(off++);
1241*572ff6f6SMatthew Dillon 			ee->ee_ob3 |= (eeval >> 15)  & 0x01;
1242*572ff6f6SMatthew Dillon 			ee->ee_db3 = (eeval >> 12)  & 0x07;
1243*572ff6f6SMatthew Dillon 			ee->ee_ob2 = (eeval >> 9)  & 0x07;
1244*572ff6f6SMatthew Dillon 			ee->ee_db2 = (eeval >> 6)  & 0x07;
1245*572ff6f6SMatthew Dillon 			ee->ee_ob1 = (eeval >> 3)  & 0x07;
1246*572ff6f6SMatthew Dillon 			ee->ee_db1 = eeval & 0x07;
1247*572ff6f6SMatthew Dillon 		}
1248*572ff6f6SMatthew Dillon 
1249*572ff6f6SMatthew Dillon 		EEREAD(off++);
1250*572ff6f6SMatthew Dillon 		ee->ee_txEndToXLNAOn[i] = (eeval >> 8)  & 0xff;
1251*572ff6f6SMatthew Dillon 		ee->ee_thresh62[i] = eeval & 0xff;
1252*572ff6f6SMatthew Dillon 
1253*572ff6f6SMatthew Dillon 		EEREAD(off++);
1254*572ff6f6SMatthew Dillon 		ee->ee_txEndToXPAOff[i] = (eeval >> 8)  & 0xff;
1255*572ff6f6SMatthew Dillon 		ee->ee_txFrameToXPAOn[i] = eeval  & 0xff;
1256*572ff6f6SMatthew Dillon 
1257*572ff6f6SMatthew Dillon 		EEREAD(off++);
1258*572ff6f6SMatthew Dillon 		ee->ee_pgaDesiredSize[i] = (int8_t)((eeval >> 8)  & 0xff);
1259*572ff6f6SMatthew Dillon 		ee->ee_noiseFloorThresh[i] = eeval  & 0xff;
1260*572ff6f6SMatthew Dillon 		if (ee->ee_noiseFloorThresh[i] & 0x80) {
1261*572ff6f6SMatthew Dillon 			ee->ee_noiseFloorThresh[i] = 0 -
1262*572ff6f6SMatthew Dillon 				((ee->ee_noiseFloorThresh[i] ^ 0xff) + 1);
1263*572ff6f6SMatthew Dillon 		}
1264*572ff6f6SMatthew Dillon 
1265*572ff6f6SMatthew Dillon 		EEREAD(off++);
1266*572ff6f6SMatthew Dillon 		ee->ee_xlnaGain[i] = (eeval >> 5)  & 0xff;
1267*572ff6f6SMatthew Dillon 		ee->ee_xgain[i] = (eeval >> 1)  & 0x0f;
1268*572ff6f6SMatthew Dillon 		ee->ee_xpd[i] = eeval  & 0x01;
1269*572ff6f6SMatthew Dillon 		if (ee->ee_version >= AR_EEPROM_VER4_0) {
1270*572ff6f6SMatthew Dillon 			switch (i) {
1271*572ff6f6SMatthew Dillon 			case headerInfo11A:
1272*572ff6f6SMatthew Dillon 				ee->ee_fixedBias5 = (eeval >> 13) & 0x1;
1273*572ff6f6SMatthew Dillon 				break;
1274*572ff6f6SMatthew Dillon 			case headerInfo11G:
1275*572ff6f6SMatthew Dillon 				ee->ee_fixedBias2 = (eeval >> 13) & 0x1;
1276*572ff6f6SMatthew Dillon 				break;
1277*572ff6f6SMatthew Dillon 			}
1278*572ff6f6SMatthew Dillon 		}
1279*572ff6f6SMatthew Dillon 
1280*572ff6f6SMatthew Dillon 		if (ee->ee_version >= AR_EEPROM_VER3_3) {
1281*572ff6f6SMatthew Dillon 			EEREAD(off++);
1282*572ff6f6SMatthew Dillon 			ee->ee_falseDetectBackoff[i] = (eeval >> 6) & 0x7F;
1283*572ff6f6SMatthew Dillon 			switch (i) {
1284*572ff6f6SMatthew Dillon 			case headerInfo11B:
1285*572ff6f6SMatthew Dillon 				ee->ee_ob2GHz[0] = eeval & 0x7;
1286*572ff6f6SMatthew Dillon 				ee->ee_db2GHz[0] = (eeval >> 3) & 0x7;
1287*572ff6f6SMatthew Dillon 				break;
1288*572ff6f6SMatthew Dillon 			case headerInfo11G:
1289*572ff6f6SMatthew Dillon 				ee->ee_ob2GHz[1] = eeval & 0x7;
1290*572ff6f6SMatthew Dillon 				ee->ee_db2GHz[1] = (eeval >> 3) & 0x7;
1291*572ff6f6SMatthew Dillon 				break;
1292*572ff6f6SMatthew Dillon 			case headerInfo11A:
1293*572ff6f6SMatthew Dillon 				ee->ee_xrTargetPower5 = eeval & 0x3f;
1294*572ff6f6SMatthew Dillon 				break;
1295*572ff6f6SMatthew Dillon 			}
1296*572ff6f6SMatthew Dillon 		}
1297*572ff6f6SMatthew Dillon 		if (ee->ee_version >= AR_EEPROM_VER3_4) {
1298*572ff6f6SMatthew Dillon 			ee->ee_gainI[i] = (eeval >> 13) & 0x07;
1299*572ff6f6SMatthew Dillon 
1300*572ff6f6SMatthew Dillon 			EEREAD(off++);
1301*572ff6f6SMatthew Dillon 			ee->ee_gainI[i] |= (eeval << 3) & 0x38;
1302*572ff6f6SMatthew Dillon 			if (i == headerInfo11G) {
1303*572ff6f6SMatthew Dillon 				ee->ee_cckOfdmPwrDelta = (eeval >> 3) & 0xFF;
1304*572ff6f6SMatthew Dillon 				if (ee->ee_version >= AR_EEPROM_VER4_6)
1305*572ff6f6SMatthew Dillon 					ee->ee_scaledCh14FilterCckDelta =
1306*572ff6f6SMatthew Dillon 						(eeval >> 11) & 0x1f;
1307*572ff6f6SMatthew Dillon 			}
1308*572ff6f6SMatthew Dillon 			if (i == headerInfo11A &&
1309*572ff6f6SMatthew Dillon 			    ee->ee_version >= AR_EEPROM_VER4_0) {
1310*572ff6f6SMatthew Dillon 				ee->ee_iqCalI[0] = (eeval >> 8 ) & 0x3f;
1311*572ff6f6SMatthew Dillon 				ee->ee_iqCalQ[0] = (eeval >> 3 ) & 0x1f;
1312*572ff6f6SMatthew Dillon 			}
1313*572ff6f6SMatthew Dillon 		} else {
1314*572ff6f6SMatthew Dillon 			ee->ee_gainI[i] = 10;
1315*572ff6f6SMatthew Dillon 			ee->ee_cckOfdmPwrDelta = TENX_OFDM_CCK_DELTA_INIT;
1316*572ff6f6SMatthew Dillon 		}
1317*572ff6f6SMatthew Dillon 		if (ee->ee_version >= AR_EEPROM_VER4_0) {
1318*572ff6f6SMatthew Dillon 			switch (i) {
1319*572ff6f6SMatthew Dillon 			case headerInfo11B:
1320*572ff6f6SMatthew Dillon 				EEREAD(off++);
1321*572ff6f6SMatthew Dillon 				ee->ee_calPier11b[0] =
1322*572ff6f6SMatthew Dillon 					fbin2freq_2p4(ee, eeval&0xff);
1323*572ff6f6SMatthew Dillon 				ee->ee_calPier11b[1] =
1324*572ff6f6SMatthew Dillon 					fbin2freq_2p4(ee, (eeval >> 8)&0xff);
1325*572ff6f6SMatthew Dillon 				EEREAD(off++);
1326*572ff6f6SMatthew Dillon 				ee->ee_calPier11b[2] =
1327*572ff6f6SMatthew Dillon 					fbin2freq_2p4(ee, eeval&0xff);
1328*572ff6f6SMatthew Dillon 				if (ee->ee_version >= AR_EEPROM_VER4_1)
1329*572ff6f6SMatthew Dillon 					ee->ee_rxtxMargin[headerInfo11B] =
1330*572ff6f6SMatthew Dillon 						(eeval >> 8) & 0x3f;
1331*572ff6f6SMatthew Dillon 				break;
1332*572ff6f6SMatthew Dillon 			case headerInfo11G:
1333*572ff6f6SMatthew Dillon 				EEREAD(off++);
1334*572ff6f6SMatthew Dillon 				ee->ee_calPier11g[0] =
1335*572ff6f6SMatthew Dillon 					fbin2freq_2p4(ee, eeval & 0xff);
1336*572ff6f6SMatthew Dillon 				ee->ee_calPier11g[1] =
1337*572ff6f6SMatthew Dillon 					fbin2freq_2p4(ee, (eeval >> 8) & 0xff);
1338*572ff6f6SMatthew Dillon 
1339*572ff6f6SMatthew Dillon 				EEREAD(off++);
1340*572ff6f6SMatthew Dillon 				ee->ee_turbo2WMaxPower2 = eeval & 0x7F;
1341*572ff6f6SMatthew Dillon 				ee->ee_xrTargetPower2 = (eeval >> 7) & 0x3f;
1342*572ff6f6SMatthew Dillon 
1343*572ff6f6SMatthew Dillon 				EEREAD(off++);
1344*572ff6f6SMatthew Dillon 				ee->ee_calPier11g[2] =
1345*572ff6f6SMatthew Dillon 					fbin2freq_2p4(ee, eeval & 0xff);
1346*572ff6f6SMatthew Dillon 				if (ee->ee_version >= AR_EEPROM_VER4_1)
1347*572ff6f6SMatthew Dillon 					 ee->ee_rxtxMargin[headerInfo11G] =
1348*572ff6f6SMatthew Dillon 						(eeval >> 8) & 0x3f;
1349*572ff6f6SMatthew Dillon 
1350*572ff6f6SMatthew Dillon 				EEREAD(off++);
1351*572ff6f6SMatthew Dillon 				ee->ee_iqCalI[1] = (eeval >> 5) & 0x3F;
1352*572ff6f6SMatthew Dillon 				ee->ee_iqCalQ[1] = eeval & 0x1F;
1353*572ff6f6SMatthew Dillon 
1354*572ff6f6SMatthew Dillon 				if (ee->ee_version >= AR_EEPROM_VER4_2) {
1355*572ff6f6SMatthew Dillon 					EEREAD(off++);
1356*572ff6f6SMatthew Dillon 					ee->ee_cckOfdmGainDelta =
1357*572ff6f6SMatthew Dillon 						(uint8_t)(eeval & 0xFF);
1358*572ff6f6SMatthew Dillon 					if (ee->ee_version >= AR_EEPROM_VER5_0) {
1359*572ff6f6SMatthew Dillon 						ee->ee_switchSettlingTurbo[1] =
1360*572ff6f6SMatthew Dillon 							(eeval >> 8) & 0x7f;
1361*572ff6f6SMatthew Dillon 						ee->ee_txrxAttenTurbo[1] =
1362*572ff6f6SMatthew Dillon 							(eeval >> 15) & 0x1;
1363*572ff6f6SMatthew Dillon 						EEREAD(off++);
1364*572ff6f6SMatthew Dillon 						ee->ee_txrxAttenTurbo[1] |=
1365*572ff6f6SMatthew Dillon 							(eeval & 0x1F) << 1;
1366*572ff6f6SMatthew Dillon 						ee->ee_rxtxMarginTurbo[1] =
1367*572ff6f6SMatthew Dillon 							(eeval >> 5) & 0x3F;
1368*572ff6f6SMatthew Dillon 						ee->ee_adcDesiredSizeTurbo[1] =
1369*572ff6f6SMatthew Dillon 							(eeval >> 11) & 0x1F;
1370*572ff6f6SMatthew Dillon 						EEREAD(off++);
1371*572ff6f6SMatthew Dillon 						ee->ee_adcDesiredSizeTurbo[1] |=
1372*572ff6f6SMatthew Dillon 							(eeval & 0x7) << 5;
1373*572ff6f6SMatthew Dillon 						ee->ee_pgaDesiredSizeTurbo[1] =
1374*572ff6f6SMatthew Dillon 							(eeval >> 3) & 0xFF;
1375*572ff6f6SMatthew Dillon 					}
1376*572ff6f6SMatthew Dillon 				}
1377*572ff6f6SMatthew Dillon 				break;
1378*572ff6f6SMatthew Dillon 			case headerInfo11A:
1379*572ff6f6SMatthew Dillon 				if (ee->ee_version >= AR_EEPROM_VER4_1) {
1380*572ff6f6SMatthew Dillon 					EEREAD(off++);
1381*572ff6f6SMatthew Dillon 					ee->ee_rxtxMargin[headerInfo11A] =
1382*572ff6f6SMatthew Dillon 						eeval & 0x3f;
1383*572ff6f6SMatthew Dillon 					if (ee->ee_version >= AR_EEPROM_VER5_0) {
1384*572ff6f6SMatthew Dillon 						ee->ee_switchSettlingTurbo[0] =
1385*572ff6f6SMatthew Dillon 							(eeval >> 6) & 0x7f;
1386*572ff6f6SMatthew Dillon 						ee->ee_txrxAttenTurbo[0] =
1387*572ff6f6SMatthew Dillon 							(eeval >> 13) & 0x7;
1388*572ff6f6SMatthew Dillon 						EEREAD(off++);
1389*572ff6f6SMatthew Dillon 						ee->ee_txrxAttenTurbo[0] |=
1390*572ff6f6SMatthew Dillon 							(eeval & 0x7) << 3;
1391*572ff6f6SMatthew Dillon 						ee->ee_rxtxMarginTurbo[0] =
1392*572ff6f6SMatthew Dillon 							(eeval >> 3) & 0x3F;
1393*572ff6f6SMatthew Dillon 						ee->ee_adcDesiredSizeTurbo[0] =
1394*572ff6f6SMatthew Dillon 							(eeval >> 9) & 0x7F;
1395*572ff6f6SMatthew Dillon 						EEREAD(off++);
1396*572ff6f6SMatthew Dillon 						ee->ee_adcDesiredSizeTurbo[0] |=
1397*572ff6f6SMatthew Dillon 							(eeval & 0x1) << 7;
1398*572ff6f6SMatthew Dillon 						ee->ee_pgaDesiredSizeTurbo[0] =
1399*572ff6f6SMatthew Dillon 							(eeval >> 1) & 0xFF;
1400*572ff6f6SMatthew Dillon 					}
1401*572ff6f6SMatthew Dillon 				}
1402*572ff6f6SMatthew Dillon 				break;
1403*572ff6f6SMatthew Dillon 			}
1404*572ff6f6SMatthew Dillon 		}
1405*572ff6f6SMatthew Dillon 	}
1406*572ff6f6SMatthew Dillon 	if (ee->ee_version < AR_EEPROM_VER3_3) {
1407*572ff6f6SMatthew Dillon 		/* Version 3.1+ specific parameters */
1408*572ff6f6SMatthew Dillon 		EEREAD(0xec);
1409*572ff6f6SMatthew Dillon 		ee->ee_ob2GHz[0] = eeval & 0x7;
1410*572ff6f6SMatthew Dillon 		ee->ee_db2GHz[0] = (eeval >> 3) & 0x7;
1411*572ff6f6SMatthew Dillon 
1412*572ff6f6SMatthew Dillon 		EEREAD(0xed);
1413*572ff6f6SMatthew Dillon 		ee->ee_ob2GHz[1] = eeval & 0x7;
1414*572ff6f6SMatthew Dillon 		ee->ee_db2GHz[1] = (eeval >> 3) & 0x7;
1415*572ff6f6SMatthew Dillon 	}
1416*572ff6f6SMatthew Dillon 
1417*572ff6f6SMatthew Dillon 	/* Initialize corner cal (thermal tx gain adjust parameters) */
1418*572ff6f6SMatthew Dillon 	ee->ee_cornerCal.clip = 4;
1419*572ff6f6SMatthew Dillon 	ee->ee_cornerCal.pd90 = 1;
1420*572ff6f6SMatthew Dillon 	ee->ee_cornerCal.pd84 = 1;
1421*572ff6f6SMatthew Dillon 	ee->ee_cornerCal.gSel = 0;
1422*572ff6f6SMatthew Dillon 
1423*572ff6f6SMatthew Dillon 	/*
1424*572ff6f6SMatthew Dillon 	* Read the conformance test limit identifiers
1425*572ff6f6SMatthew Dillon 	* These are used to match regulatory domain testing needs with
1426*572ff6f6SMatthew Dillon 	* the RD-specific tests that have been calibrated in the EEPROM.
1427*572ff6f6SMatthew Dillon 	*/
1428*572ff6f6SMatthew Dillon 	off = header[5];
1429*572ff6f6SMatthew Dillon 	for (i = 0; i < ee->ee_numCtls; i += 2) {
1430*572ff6f6SMatthew Dillon 		EEREAD(off++);
1431*572ff6f6SMatthew Dillon 		ee->ee_ctl[i] = (eeval >> 8) & 0xff;
1432*572ff6f6SMatthew Dillon 		ee->ee_ctl[i+1] = eeval & 0xff;
1433*572ff6f6SMatthew Dillon 	}
1434*572ff6f6SMatthew Dillon 
1435*572ff6f6SMatthew Dillon 	if (ee->ee_version < AR_EEPROM_VER5_3) {
1436*572ff6f6SMatthew Dillon 		/* XXX only for 5413? */
1437*572ff6f6SMatthew Dillon 		ee->ee_spurChans[0][1] = AR_SPUR_5413_1;
1438*572ff6f6SMatthew Dillon 		ee->ee_spurChans[1][1] = AR_SPUR_5413_2;
1439*572ff6f6SMatthew Dillon 		ee->ee_spurChans[2][1] = AR_NO_SPUR;
1440*572ff6f6SMatthew Dillon 		ee->ee_spurChans[0][0] = AR_NO_SPUR;
1441*572ff6f6SMatthew Dillon 	} else {
1442*572ff6f6SMatthew Dillon 		/* Read spur mitigation data */
1443*572ff6f6SMatthew Dillon 		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
1444*572ff6f6SMatthew Dillon 			EEREAD(off);
1445*572ff6f6SMatthew Dillon 			ee->ee_spurChans[i][0] = eeval;
1446*572ff6f6SMatthew Dillon 			EEREAD(off+AR_EEPROM_MODAL_SPURS);
1447*572ff6f6SMatthew Dillon 			ee->ee_spurChans[i][1] = eeval;
1448*572ff6f6SMatthew Dillon 			off++;
1449*572ff6f6SMatthew Dillon 		}
1450*572ff6f6SMatthew Dillon 	}
1451*572ff6f6SMatthew Dillon 
1452*572ff6f6SMatthew Dillon 	/* for recent changes to NF scale */
1453*572ff6f6SMatthew Dillon 	if (ee->ee_version <= AR_EEPROM_VER3_2) {
1454*572ff6f6SMatthew Dillon 		ee->ee_noiseFloorThresh[headerInfo11A] = -54;
1455*572ff6f6SMatthew Dillon 		ee->ee_noiseFloorThresh[headerInfo11B] = -1;
1456*572ff6f6SMatthew Dillon 		ee->ee_noiseFloorThresh[headerInfo11G] = -1;
1457*572ff6f6SMatthew Dillon 	}
1458*572ff6f6SMatthew Dillon 	/* to override thresh62 for better 2.4 and 5 operation */
1459*572ff6f6SMatthew Dillon 	if (ee->ee_version <= AR_EEPROM_VER3_2) {
1460*572ff6f6SMatthew Dillon 		ee->ee_thresh62[headerInfo11A] = 15;	/* 11A */
1461*572ff6f6SMatthew Dillon 		ee->ee_thresh62[headerInfo11B] = 28;	/* 11B */
1462*572ff6f6SMatthew Dillon 		ee->ee_thresh62[headerInfo11G] = 28;	/* 11G */
1463*572ff6f6SMatthew Dillon 	}
1464*572ff6f6SMatthew Dillon 
1465*572ff6f6SMatthew Dillon 	/* Check for regulatory capabilities */
1466*572ff6f6SMatthew Dillon 	if (ee->ee_version >= AR_EEPROM_VER4_0) {
1467*572ff6f6SMatthew Dillon 		EEREAD(regCapOffsetPost4_0);
1468*572ff6f6SMatthew Dillon 	} else {
1469*572ff6f6SMatthew Dillon 		EEREAD(regCapOffsetPre4_0);
1470*572ff6f6SMatthew Dillon 	}
1471*572ff6f6SMatthew Dillon 
1472*572ff6f6SMatthew Dillon 	ee->ee_regCap = eeval;
1473*572ff6f6SMatthew Dillon 
1474*572ff6f6SMatthew Dillon 	if (ee->ee_Amode == 0) {
1475*572ff6f6SMatthew Dillon 		/* Check for valid Amode in upgraded h/w */
1476*572ff6f6SMatthew Dillon 		if (ee->ee_version >= AR_EEPROM_VER4_0) {
1477*572ff6f6SMatthew Dillon 			ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A)?1:0;
1478*572ff6f6SMatthew Dillon 		} else {
1479*572ff6f6SMatthew Dillon 			ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0)?1:0;
1480*572ff6f6SMatthew Dillon 		}
1481*572ff6f6SMatthew Dillon 	}
1482*572ff6f6SMatthew Dillon 
1483*572ff6f6SMatthew Dillon 	if (ee->ee_version >= AR_EEPROM_VER5_1)
1484*572ff6f6SMatthew Dillon 		EEREAD(AR_EEPROM_CAPABILITIES_OFFSET);
1485*572ff6f6SMatthew Dillon 	else
1486*572ff6f6SMatthew Dillon 		eeval = 0;
1487*572ff6f6SMatthew Dillon 	ee->ee_opCap = eeval;
1488*572ff6f6SMatthew Dillon 
1489*572ff6f6SMatthew Dillon 	EEREAD(AR_EEPROM_REG_DOMAIN);
1490*572ff6f6SMatthew Dillon 	ee->ee_regdomain = eeval;
1491*572ff6f6SMatthew Dillon 
1492*572ff6f6SMatthew Dillon 	return AH_TRUE;
1493*572ff6f6SMatthew Dillon #undef EEREAD
1494*572ff6f6SMatthew Dillon }
1495*572ff6f6SMatthew Dillon 
1496*572ff6f6SMatthew Dillon /*
1497*572ff6f6SMatthew Dillon  * Now verify and copy EEPROM contents into the allocated space
1498*572ff6f6SMatthew Dillon  */
1499*572ff6f6SMatthew Dillon static HAL_BOOL
legacyEepromReadContents(struct ath_hal * ah,HAL_EEPROM * ee)1500*572ff6f6SMatthew Dillon legacyEepromReadContents(struct ath_hal *ah, HAL_EEPROM *ee)
1501*572ff6f6SMatthew Dillon {
1502*572ff6f6SMatthew Dillon 	/* Read the header information here */
1503*572ff6f6SMatthew Dillon 	if (!readHeaderInfo(ah, ee))
1504*572ff6f6SMatthew Dillon 		return AH_FALSE;
1505*572ff6f6SMatthew Dillon #if 0
1506*572ff6f6SMatthew Dillon 	/* Require 5112 devices to have EEPROM 4.0 EEP_MAP set */
1507*572ff6f6SMatthew Dillon 	if (IS_5112(ah) && !ee->ee_eepMap) {
1508*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY,
1509*572ff6f6SMatthew Dillon 		    "%s: 5112 devices must have EEPROM 4.0 with the "
1510*572ff6f6SMatthew Dillon 		    "EEP_MAP set\n", __func__);
1511*572ff6f6SMatthew Dillon 		return AH_FALSE;
1512*572ff6f6SMatthew Dillon 	}
1513*572ff6f6SMatthew Dillon #endif
1514*572ff6f6SMatthew Dillon 	/*
1515*572ff6f6SMatthew Dillon 	 * Group 1: frequency pier locations readback
1516*572ff6f6SMatthew Dillon 	 * check that the structure has been populated
1517*572ff6f6SMatthew Dillon 	 * with enough space to hold the channels
1518*572ff6f6SMatthew Dillon 	 *
1519*572ff6f6SMatthew Dillon 	 * NOTE: Group 1 contains the 5 GHz channel numbers
1520*572ff6f6SMatthew Dillon 	 *	 that have dBm->pcdac calibrated information.
1521*572ff6f6SMatthew Dillon 	 */
1522*572ff6f6SMatthew Dillon 	if (!readEepromFreqPierInfo(ah, ee))
1523*572ff6f6SMatthew Dillon 		return AH_FALSE;
1524*572ff6f6SMatthew Dillon 
1525*572ff6f6SMatthew Dillon 	/*
1526*572ff6f6SMatthew Dillon 	 * Group 2:  readback data for all frequency piers
1527*572ff6f6SMatthew Dillon 	 *
1528*572ff6f6SMatthew Dillon 	 * NOTE: Group 2 contains the raw power calibration
1529*572ff6f6SMatthew Dillon 	 *	 information for each of the channels that we
1530*572ff6f6SMatthew Dillon 	 *	 recorded above.
1531*572ff6f6SMatthew Dillon 	 */
1532*572ff6f6SMatthew Dillon 	if (!readEepromRawPowerCalInfo(ah, ee))
1533*572ff6f6SMatthew Dillon 		return AH_FALSE;
1534*572ff6f6SMatthew Dillon 
1535*572ff6f6SMatthew Dillon 	/*
1536*572ff6f6SMatthew Dillon 	 * Group 5: target power values per rate
1537*572ff6f6SMatthew Dillon 	 *
1538*572ff6f6SMatthew Dillon 	 * NOTE: Group 5 contains the recorded maximum power
1539*572ff6f6SMatthew Dillon 	 *	 in dB that can be attained for the given rate.
1540*572ff6f6SMatthew Dillon 	 */
1541*572ff6f6SMatthew Dillon 	/* Read the power per rate info for test channels */
1542*572ff6f6SMatthew Dillon 	if (!readEepromTargetPowerCalInfo(ah, ee))
1543*572ff6f6SMatthew Dillon 		return AH_FALSE;
1544*572ff6f6SMatthew Dillon 
1545*572ff6f6SMatthew Dillon 	/*
1546*572ff6f6SMatthew Dillon 	 * Group 8: Conformance Test Limits information
1547*572ff6f6SMatthew Dillon 	 *
1548*572ff6f6SMatthew Dillon 	 * NOTE: Group 8 contains the values to limit the
1549*572ff6f6SMatthew Dillon 	 *	 maximum transmit power value based on any
1550*572ff6f6SMatthew Dillon 	 *	 band edge violations.
1551*572ff6f6SMatthew Dillon 	 */
1552*572ff6f6SMatthew Dillon 	/* Read the RD edge power limits */
1553*572ff6f6SMatthew Dillon 	return readEepromCTLInfo(ah, ee);
1554*572ff6f6SMatthew Dillon }
1555*572ff6f6SMatthew Dillon 
1556*572ff6f6SMatthew Dillon static HAL_STATUS
legacyEepromGet(struct ath_hal * ah,int param,void * val)1557*572ff6f6SMatthew Dillon legacyEepromGet(struct ath_hal *ah, int param, void *val)
1558*572ff6f6SMatthew Dillon {
1559*572ff6f6SMatthew Dillon 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1560*572ff6f6SMatthew Dillon 	uint8_t *macaddr;
1561*572ff6f6SMatthew Dillon 	uint16_t eeval;
1562*572ff6f6SMatthew Dillon 	uint32_t sum;
1563*572ff6f6SMatthew Dillon 	int i;
1564*572ff6f6SMatthew Dillon 
1565*572ff6f6SMatthew Dillon 	switch (param) {
1566*572ff6f6SMatthew Dillon 	case AR_EEP_OPCAP:
1567*572ff6f6SMatthew Dillon 		*(uint16_t *) val = ee->ee_opCap;
1568*572ff6f6SMatthew Dillon 		return HAL_OK;
1569*572ff6f6SMatthew Dillon 	case AR_EEP_REGDMN_0:
1570*572ff6f6SMatthew Dillon 		*(uint16_t *) val = ee->ee_regdomain;
1571*572ff6f6SMatthew Dillon 		return HAL_OK;
1572*572ff6f6SMatthew Dillon 	case AR_EEP_RFSILENT:
1573*572ff6f6SMatthew Dillon 		if (!ath_hal_eepromRead(ah, AR_EEPROM_RFSILENT, &eeval))
1574*572ff6f6SMatthew Dillon 			return HAL_EEREAD;
1575*572ff6f6SMatthew Dillon 		*(uint16_t *) val = eeval;
1576*572ff6f6SMatthew Dillon 		return HAL_OK;
1577*572ff6f6SMatthew Dillon 	case AR_EEP_MACADDR:
1578*572ff6f6SMatthew Dillon 		sum = 0;
1579*572ff6f6SMatthew Dillon 		macaddr = val;
1580*572ff6f6SMatthew Dillon 		for (i = 0; i < 3; i++) {
1581*572ff6f6SMatthew Dillon 			if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(2-i), &eeval)) {
1582*572ff6f6SMatthew Dillon 				HALDEBUG(ah, HAL_DEBUG_ANY,
1583*572ff6f6SMatthew Dillon 				    "%s: cannot read EEPROM location %u\n",
1584*572ff6f6SMatthew Dillon 				    __func__, i);
1585*572ff6f6SMatthew Dillon 				return HAL_EEREAD;
1586*572ff6f6SMatthew Dillon 			}
1587*572ff6f6SMatthew Dillon 			sum += eeval;
1588*572ff6f6SMatthew Dillon 			macaddr[2*i] = eeval >> 8;
1589*572ff6f6SMatthew Dillon 			macaddr[2*i + 1] = eeval & 0xff;
1590*572ff6f6SMatthew Dillon 		}
1591*572ff6f6SMatthew Dillon 		if (sum == 0 || sum == 0xffff*3) {
1592*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY,
1593*572ff6f6SMatthew Dillon 			    "%s: mac address read failed: %s\n", __func__,
1594*572ff6f6SMatthew Dillon 			    ath_hal_ether_sprintf(macaddr));
1595*572ff6f6SMatthew Dillon 			return HAL_EEBADMAC;
1596*572ff6f6SMatthew Dillon 		}
1597*572ff6f6SMatthew Dillon 		return HAL_OK;
1598*572ff6f6SMatthew Dillon 	case AR_EEP_RFKILL:
1599*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1600*572ff6f6SMatthew Dillon 		return ee->ee_rfKill ? HAL_OK : HAL_EIO;
1601*572ff6f6SMatthew Dillon 	case AR_EEP_AMODE:
1602*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1603*572ff6f6SMatthew Dillon 		return ee->ee_Amode ? HAL_OK : HAL_EIO;
1604*572ff6f6SMatthew Dillon 	case AR_EEP_BMODE:
1605*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1606*572ff6f6SMatthew Dillon 		return ee->ee_Bmode ? HAL_OK : HAL_EIO;
1607*572ff6f6SMatthew Dillon 	case AR_EEP_GMODE:
1608*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1609*572ff6f6SMatthew Dillon 		return ee->ee_Gmode ? HAL_OK : HAL_EIO;
1610*572ff6f6SMatthew Dillon 	case AR_EEP_TURBO5DISABLE:
1611*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1612*572ff6f6SMatthew Dillon 		return ee->ee_turbo5Disable ? HAL_OK : HAL_EIO;
1613*572ff6f6SMatthew Dillon 	case AR_EEP_TURBO2DISABLE:
1614*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1615*572ff6f6SMatthew Dillon 		return ee->ee_turbo2Disable ? HAL_OK : HAL_EIO;
1616*572ff6f6SMatthew Dillon 	case AR_EEP_ISTALON:		/* Talon detect */
1617*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1618*572ff6f6SMatthew Dillon 		return (ee->ee_version >= AR_EEPROM_VER5_4 &&
1619*572ff6f6SMatthew Dillon 		    ath_hal_eepromRead(ah, 0x0b, &eeval) && eeval == 1) ?
1620*572ff6f6SMatthew Dillon 			HAL_OK : HAL_EIO;
1621*572ff6f6SMatthew Dillon 	case AR_EEP_32KHZCRYSTAL:
1622*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1623*572ff6f6SMatthew Dillon 		return ee->ee_exist32kHzCrystal ? HAL_OK : HAL_EIO;
1624*572ff6f6SMatthew Dillon 	case AR_EEP_COMPRESS:
1625*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1626*572ff6f6SMatthew Dillon 		return (ee->ee_opCap & AR_EEPROM_EEPCAP_COMPRESS_DIS) == 0 ?
1627*572ff6f6SMatthew Dillon 		    HAL_OK : HAL_EIO;
1628*572ff6f6SMatthew Dillon 	case AR_EEP_FASTFRAME:
1629*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1630*572ff6f6SMatthew Dillon 		return (ee->ee_opCap & AR_EEPROM_EEPCAP_FASTFRAME_DIS) == 0 ?
1631*572ff6f6SMatthew Dillon 		    HAL_OK : HAL_EIO;
1632*572ff6f6SMatthew Dillon 	case AR_EEP_AES:
1633*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1634*572ff6f6SMatthew Dillon 		return (ee->ee_opCap & AR_EEPROM_EEPCAP_AES_DIS) == 0 ?
1635*572ff6f6SMatthew Dillon 		    HAL_OK : HAL_EIO;
1636*572ff6f6SMatthew Dillon 	case AR_EEP_BURST:
1637*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1638*572ff6f6SMatthew Dillon 		return (ee->ee_opCap & AR_EEPROM_EEPCAP_BURST_DIS) == 0 ?
1639*572ff6f6SMatthew Dillon 		    HAL_OK : HAL_EIO;
1640*572ff6f6SMatthew Dillon 	case AR_EEP_MAXQCU:
1641*572ff6f6SMatthew Dillon 		if (ee->ee_opCap & AR_EEPROM_EEPCAP_MAXQCU) {
1642*572ff6f6SMatthew Dillon 			*(uint16_t *) val =
1643*572ff6f6SMatthew Dillon 			    MS(ee->ee_opCap, AR_EEPROM_EEPCAP_MAXQCU);
1644*572ff6f6SMatthew Dillon 			return HAL_OK;
1645*572ff6f6SMatthew Dillon 		} else
1646*572ff6f6SMatthew Dillon 			return HAL_EIO;
1647*572ff6f6SMatthew Dillon 	case AR_EEP_KCENTRIES:
1648*572ff6f6SMatthew Dillon 		if (ee->ee_opCap & AR_EEPROM_EEPCAP_KC_ENTRIES) {
1649*572ff6f6SMatthew Dillon 			*(uint16_t *) val =
1650*572ff6f6SMatthew Dillon 			    1 << MS(ee->ee_opCap, AR_EEPROM_EEPCAP_KC_ENTRIES);
1651*572ff6f6SMatthew Dillon 			return HAL_OK;
1652*572ff6f6SMatthew Dillon 		} else
1653*572ff6f6SMatthew Dillon 			return HAL_EIO;
1654*572ff6f6SMatthew Dillon 	case AR_EEP_ANTGAINMAX_5:
1655*572ff6f6SMatthew Dillon 		*(int8_t *) val = ee->ee_antennaGainMax[0];
1656*572ff6f6SMatthew Dillon 		return HAL_OK;
1657*572ff6f6SMatthew Dillon 	case AR_EEP_ANTGAINMAX_2:
1658*572ff6f6SMatthew Dillon 		*(int8_t *) val = ee->ee_antennaGainMax[1];
1659*572ff6f6SMatthew Dillon 		return HAL_OK;
1660*572ff6f6SMatthew Dillon 	case AR_EEP_WRITEPROTECT:
1661*572ff6f6SMatthew Dillon 		HALASSERT(val == AH_NULL);
1662*572ff6f6SMatthew Dillon 		return (ee->ee_protect & AR_EEPROM_PROTECT_WP_128_191) ?
1663*572ff6f6SMatthew Dillon 		    HAL_OK : HAL_EIO;
1664*572ff6f6SMatthew Dillon 	}
1665*572ff6f6SMatthew Dillon 	return HAL_EINVAL;
1666*572ff6f6SMatthew Dillon }
1667*572ff6f6SMatthew Dillon 
1668*572ff6f6SMatthew Dillon static HAL_STATUS
legacyEepromSet(struct ath_hal * ah,int param,int v)1669*572ff6f6SMatthew Dillon legacyEepromSet(struct ath_hal *ah, int param, int v)
1670*572ff6f6SMatthew Dillon {
1671*572ff6f6SMatthew Dillon 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1672*572ff6f6SMatthew Dillon 
1673*572ff6f6SMatthew Dillon 	switch (param) {
1674*572ff6f6SMatthew Dillon 	case AR_EEP_AMODE:
1675*572ff6f6SMatthew Dillon 		ee->ee_Amode = v;
1676*572ff6f6SMatthew Dillon 		return HAL_OK;
1677*572ff6f6SMatthew Dillon 	case AR_EEP_BMODE:
1678*572ff6f6SMatthew Dillon 		ee->ee_Bmode = v;
1679*572ff6f6SMatthew Dillon 		return HAL_OK;
1680*572ff6f6SMatthew Dillon 	case AR_EEP_GMODE:
1681*572ff6f6SMatthew Dillon 		ee->ee_Gmode = v;
1682*572ff6f6SMatthew Dillon 		return HAL_OK;
1683*572ff6f6SMatthew Dillon 	case AR_EEP_TURBO5DISABLE:
1684*572ff6f6SMatthew Dillon 		ee->ee_turbo5Disable = v;
1685*572ff6f6SMatthew Dillon 		return HAL_OK;
1686*572ff6f6SMatthew Dillon 	case AR_EEP_TURBO2DISABLE:
1687*572ff6f6SMatthew Dillon 		ee->ee_turbo2Disable = v;
1688*572ff6f6SMatthew Dillon 		return HAL_OK;
1689*572ff6f6SMatthew Dillon 	case AR_EEP_COMPRESS:
1690*572ff6f6SMatthew Dillon 		if (v)
1691*572ff6f6SMatthew Dillon 			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_COMPRESS_DIS;
1692*572ff6f6SMatthew Dillon 		else
1693*572ff6f6SMatthew Dillon 			ee->ee_opCap |= AR_EEPROM_EEPCAP_COMPRESS_DIS;
1694*572ff6f6SMatthew Dillon 		return HAL_OK;
1695*572ff6f6SMatthew Dillon 	case AR_EEP_FASTFRAME:
1696*572ff6f6SMatthew Dillon 		if (v)
1697*572ff6f6SMatthew Dillon 			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_FASTFRAME_DIS;
1698*572ff6f6SMatthew Dillon 		else
1699*572ff6f6SMatthew Dillon 			ee->ee_opCap |= AR_EEPROM_EEPCAP_FASTFRAME_DIS;
1700*572ff6f6SMatthew Dillon 		return HAL_OK;
1701*572ff6f6SMatthew Dillon 	case AR_EEP_AES:
1702*572ff6f6SMatthew Dillon 		if (v)
1703*572ff6f6SMatthew Dillon 			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_AES_DIS;
1704*572ff6f6SMatthew Dillon 		else
1705*572ff6f6SMatthew Dillon 			ee->ee_opCap |= AR_EEPROM_EEPCAP_AES_DIS;
1706*572ff6f6SMatthew Dillon 		return HAL_OK;
1707*572ff6f6SMatthew Dillon 	case AR_EEP_BURST:
1708*572ff6f6SMatthew Dillon 		if (v)
1709*572ff6f6SMatthew Dillon 			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_BURST_DIS;
1710*572ff6f6SMatthew Dillon 		else
1711*572ff6f6SMatthew Dillon 			ee->ee_opCap |= AR_EEPROM_EEPCAP_BURST_DIS;
1712*572ff6f6SMatthew Dillon 		return HAL_OK;
1713*572ff6f6SMatthew Dillon 	}
1714*572ff6f6SMatthew Dillon 	return HAL_EINVAL;
1715*572ff6f6SMatthew Dillon }
1716*572ff6f6SMatthew Dillon 
1717*572ff6f6SMatthew Dillon static HAL_BOOL
legacyEepromDiag(struct ath_hal * ah,int request,const void * args,uint32_t argsize,void ** result,uint32_t * resultsize)1718*572ff6f6SMatthew Dillon legacyEepromDiag(struct ath_hal *ah, int request,
1719*572ff6f6SMatthew Dillon      const void *args, uint32_t argsize, void **result, uint32_t *resultsize)
1720*572ff6f6SMatthew Dillon {
1721*572ff6f6SMatthew Dillon 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1722*572ff6f6SMatthew Dillon 	const EEPROM_POWER_EXPN_5112 *pe;
1723*572ff6f6SMatthew Dillon 
1724*572ff6f6SMatthew Dillon 	switch (request) {
1725*572ff6f6SMatthew Dillon 	case HAL_DIAG_EEPROM:
1726*572ff6f6SMatthew Dillon 		*result = ee;
1727*572ff6f6SMatthew Dillon 		*resultsize = sizeof(*ee);
1728*572ff6f6SMatthew Dillon 		return AH_TRUE;
1729*572ff6f6SMatthew Dillon 	case HAL_DIAG_EEPROM_EXP_11A:
1730*572ff6f6SMatthew Dillon 	case HAL_DIAG_EEPROM_EXP_11B:
1731*572ff6f6SMatthew Dillon 	case HAL_DIAG_EEPROM_EXP_11G:
1732*572ff6f6SMatthew Dillon 		pe = &ee->ee_modePowerArray5112[
1733*572ff6f6SMatthew Dillon 		    request - HAL_DIAG_EEPROM_EXP_11A];
1734*572ff6f6SMatthew Dillon 		*result = pe->pChannels;
1735*572ff6f6SMatthew Dillon 		*resultsize = (*result == AH_NULL) ? 0 :
1736*572ff6f6SMatthew Dillon 			roundup(sizeof(uint16_t) * pe->numChannels,
1737*572ff6f6SMatthew Dillon 				sizeof(uint32_t)) +
1738*572ff6f6SMatthew Dillon 			sizeof(EXPN_DATA_PER_CHANNEL_5112) * pe->numChannels;
1739*572ff6f6SMatthew Dillon 		return AH_TRUE;
1740*572ff6f6SMatthew Dillon 	}
1741*572ff6f6SMatthew Dillon 	return AH_FALSE;
1742*572ff6f6SMatthew Dillon }
1743*572ff6f6SMatthew Dillon 
1744*572ff6f6SMatthew Dillon static uint16_t
legacyEepromGetSpurChan(struct ath_hal * ah,int ix,HAL_BOOL is2GHz)1745*572ff6f6SMatthew Dillon legacyEepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz)
1746*572ff6f6SMatthew Dillon {
1747*572ff6f6SMatthew Dillon 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1748*572ff6f6SMatthew Dillon 
1749*572ff6f6SMatthew Dillon 	HALASSERT(0 <= ix && ix < AR_EEPROM_MODAL_SPURS);
1750*572ff6f6SMatthew Dillon 	return ee->ee_spurChans[ix][is2GHz];
1751*572ff6f6SMatthew Dillon }
1752*572ff6f6SMatthew Dillon 
1753*572ff6f6SMatthew Dillon /*
1754*572ff6f6SMatthew Dillon  * Reclaim any EEPROM-related storage.
1755*572ff6f6SMatthew Dillon  */
1756*572ff6f6SMatthew Dillon static void
legacyEepromDetach(struct ath_hal * ah)1757*572ff6f6SMatthew Dillon legacyEepromDetach(struct ath_hal *ah)
1758*572ff6f6SMatthew Dillon {
1759*572ff6f6SMatthew Dillon 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1760*572ff6f6SMatthew Dillon 
1761*572ff6f6SMatthew Dillon         if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1)
1762*572ff6f6SMatthew Dillon 		freeEepromRawPowerCalInfo5112(ah, ee);
1763*572ff6f6SMatthew Dillon 	ath_hal_free(ee);
1764*572ff6f6SMatthew Dillon 	AH_PRIVATE(ah)->ah_eeprom = AH_NULL;
1765*572ff6f6SMatthew Dillon }
1766*572ff6f6SMatthew Dillon 
1767*572ff6f6SMatthew Dillon /*
1768*572ff6f6SMatthew Dillon  * These are not valid 2.4 channels, either we change 'em
1769*572ff6f6SMatthew Dillon  * or we need to change the coding to accept them.
1770*572ff6f6SMatthew Dillon  */
1771*572ff6f6SMatthew Dillon static const uint16_t channels11b[] = { 2412, 2447, 2484 };
1772*572ff6f6SMatthew Dillon static const uint16_t channels11g[] = { 2312, 2412, 2484 };
1773*572ff6f6SMatthew Dillon 
1774*572ff6f6SMatthew Dillon HAL_STATUS
ath_hal_legacyEepromAttach(struct ath_hal * ah)1775*572ff6f6SMatthew Dillon ath_hal_legacyEepromAttach(struct ath_hal *ah)
1776*572ff6f6SMatthew Dillon {
1777*572ff6f6SMatthew Dillon 	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1778*572ff6f6SMatthew Dillon 	uint32_t sum, eepMax;
1779*572ff6f6SMatthew Dillon 	uint16_t eeversion, eeprotect, eeval;
1780*572ff6f6SMatthew Dillon 	u_int i;
1781*572ff6f6SMatthew Dillon 
1782*572ff6f6SMatthew Dillon 	HALASSERT(ee == AH_NULL);
1783*572ff6f6SMatthew Dillon 
1784*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &eeversion)) {
1785*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY,
1786*572ff6f6SMatthew Dillon 		    "%s: unable to read EEPROM version\n", __func__);
1787*572ff6f6SMatthew Dillon 		return HAL_EEREAD;
1788*572ff6f6SMatthew Dillon 	}
1789*572ff6f6SMatthew Dillon 	if (eeversion < AR_EEPROM_VER3) {
1790*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM version "
1791*572ff6f6SMatthew Dillon 		    "%u (0x%x) found\n", __func__, eeversion, eeversion);
1792*572ff6f6SMatthew Dillon 		return HAL_EEVERSION;
1793*572ff6f6SMatthew Dillon 	}
1794*572ff6f6SMatthew Dillon 
1795*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &eeprotect)) {
1796*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read EEPROM protection "
1797*572ff6f6SMatthew Dillon 		    "bits; read locked?\n", __func__);
1798*572ff6f6SMatthew Dillon 		return HAL_EEREAD;
1799*572ff6f6SMatthew Dillon 	}
1800*572ff6f6SMatthew Dillon 	HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", eeprotect);
1801*572ff6f6SMatthew Dillon 	/* XXX check proper access before continuing */
1802*572ff6f6SMatthew Dillon 
1803*572ff6f6SMatthew Dillon 	/*
1804*572ff6f6SMatthew Dillon 	 * Read the Atheros EEPROM entries and calculate the checksum.
1805*572ff6f6SMatthew Dillon 	 */
1806*572ff6f6SMatthew Dillon 	if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_UPPER, &eeval)) {
1807*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY,
1808*572ff6f6SMatthew Dillon 		    "%s: cannot read EEPROM upper size\n" , __func__);
1809*572ff6f6SMatthew Dillon 		return HAL_EEREAD;
1810*572ff6f6SMatthew Dillon 	}
1811*572ff6f6SMatthew Dillon 	if (eeval != 0)	{
1812*572ff6f6SMatthew Dillon 		eepMax = (eeval & AR_EEPROM_SIZE_UPPER_MASK) <<
1813*572ff6f6SMatthew Dillon 			AR_EEPROM_SIZE_ENDLOC_SHIFT;
1814*572ff6f6SMatthew Dillon 		if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_LOWER, &eeval)) {
1815*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY,
1816*572ff6f6SMatthew Dillon 			    "%s: cannot read EEPROM lower size\n" , __func__);
1817*572ff6f6SMatthew Dillon 			return HAL_EEREAD;
1818*572ff6f6SMatthew Dillon 		}
1819*572ff6f6SMatthew Dillon 		eepMax = (eepMax | eeval) - AR_EEPROM_ATHEROS_BASE;
1820*572ff6f6SMatthew Dillon 	} else
1821*572ff6f6SMatthew Dillon 		eepMax = AR_EEPROM_ATHEROS_MAX;
1822*572ff6f6SMatthew Dillon 	sum = 0;
1823*572ff6f6SMatthew Dillon 	for (i = 0; i < eepMax; i++) {
1824*572ff6f6SMatthew Dillon 		if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &eeval)) {
1825*572ff6f6SMatthew Dillon 			return HAL_EEREAD;
1826*572ff6f6SMatthew Dillon 		}
1827*572ff6f6SMatthew Dillon 		sum ^= eeval;
1828*572ff6f6SMatthew Dillon 	}
1829*572ff6f6SMatthew Dillon 	if (sum != 0xffff) {
1830*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n",
1831*572ff6f6SMatthew Dillon 		    __func__, sum);
1832*572ff6f6SMatthew Dillon 		return HAL_EEBADSUM;
1833*572ff6f6SMatthew Dillon 	}
1834*572ff6f6SMatthew Dillon 
1835*572ff6f6SMatthew Dillon 	ee = ath_hal_malloc(sizeof(HAL_EEPROM));
1836*572ff6f6SMatthew Dillon 	if (ee == AH_NULL) {
1837*572ff6f6SMatthew Dillon 		/* XXX message */
1838*572ff6f6SMatthew Dillon 		return HAL_ENOMEM;
1839*572ff6f6SMatthew Dillon 	}
1840*572ff6f6SMatthew Dillon 
1841*572ff6f6SMatthew Dillon 	ee->ee_protect = eeprotect;
1842*572ff6f6SMatthew Dillon 	ee->ee_version = eeversion;
1843*572ff6f6SMatthew Dillon 
1844*572ff6f6SMatthew Dillon 	ee->ee_numChannels11a = NUM_11A_EEPROM_CHANNELS;
1845*572ff6f6SMatthew Dillon 	ee->ee_numChannels2_4 = NUM_2_4_EEPROM_CHANNELS;
1846*572ff6f6SMatthew Dillon 
1847*572ff6f6SMatthew Dillon 	for (i = 0; i < NUM_11A_EEPROM_CHANNELS; i ++)
1848*572ff6f6SMatthew Dillon 		ee->ee_dataPerChannel11a[i].numPcdacValues = NUM_PCDAC_VALUES;
1849*572ff6f6SMatthew Dillon 
1850*572ff6f6SMatthew Dillon 	/* the channel list for 2.4 is fixed, fill this in here */
1851*572ff6f6SMatthew Dillon 	for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++) {
1852*572ff6f6SMatthew Dillon 		ee->ee_channels11b[i] = channels11b[i];
1853*572ff6f6SMatthew Dillon 		/* XXX 5211 requires a hack though we don't support 11g */
1854*572ff6f6SMatthew Dillon 		if (ah->ah_magic == 0x19570405)
1855*572ff6f6SMatthew Dillon 			ee->ee_channels11g[i] = channels11b[i];
1856*572ff6f6SMatthew Dillon 		else
1857*572ff6f6SMatthew Dillon 			ee->ee_channels11g[i] = channels11g[i];
1858*572ff6f6SMatthew Dillon 		ee->ee_dataPerChannel11b[i].numPcdacValues = NUM_PCDAC_VALUES;
1859*572ff6f6SMatthew Dillon 		ee->ee_dataPerChannel11g[i].numPcdacValues = NUM_PCDAC_VALUES;
1860*572ff6f6SMatthew Dillon 	}
1861*572ff6f6SMatthew Dillon 
1862*572ff6f6SMatthew Dillon 	if (!legacyEepromReadContents(ah, ee)) {
1863*572ff6f6SMatthew Dillon 		/* XXX message */
1864*572ff6f6SMatthew Dillon 		ath_hal_free(ee);
1865*572ff6f6SMatthew Dillon 		return HAL_EEREAD;	/* XXX */
1866*572ff6f6SMatthew Dillon 	}
1867*572ff6f6SMatthew Dillon 
1868*572ff6f6SMatthew Dillon 	AH_PRIVATE(ah)->ah_eeprom = ee;
1869*572ff6f6SMatthew Dillon 	AH_PRIVATE(ah)->ah_eeversion = eeversion;
1870*572ff6f6SMatthew Dillon 	AH_PRIVATE(ah)->ah_eepromDetach = legacyEepromDetach;
1871*572ff6f6SMatthew Dillon 	AH_PRIVATE(ah)->ah_eepromGet = legacyEepromGet;
1872*572ff6f6SMatthew Dillon 	AH_PRIVATE(ah)->ah_eepromSet = legacyEepromSet;
1873*572ff6f6SMatthew Dillon 	AH_PRIVATE(ah)->ah_getSpurChan = legacyEepromGetSpurChan;
1874*572ff6f6SMatthew Dillon 	AH_PRIVATE(ah)->ah_eepromDiag = legacyEepromDiag;
1875*572ff6f6SMatthew Dillon 	return HAL_OK;
1876*572ff6f6SMatthew Dillon }
1877