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