1185377Ssam/*
2185377Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc.
4185377Ssam *
5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any
6185377Ssam * purpose with or without fee is hereby granted, provided that the above
7185377Ssam * copyright notice and this permission notice appear in all copies.
8185377Ssam *
9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16185377Ssam *
17186017Ssam * $FreeBSD: releng/10.3/sys/dev/ath/ath_hal/ah_eeprom_v3.c 221896 2011-05-14 15:12:02Z adrian $
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam#include "ah_eeprom_v3.h"
24185377Ssam
25185377Ssamstatic void
26185377SsamgetPcdacInterceptsFromPcdacMinMax(HAL_EEPROM *ee,
27185377Ssam	uint16_t pcdacMin, uint16_t pcdacMax, uint16_t *vp)
28185377Ssam{
29186017Ssam	static const uint16_t intercepts3[] =
30185377Ssam		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
31186017Ssam	static const uint16_t intercepts3_2[] =
32185377Ssam		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
33185377Ssam	const uint16_t *ip = ee->ee_version < AR_EEPROM_VER3_2 ?
34185377Ssam		intercepts3 : intercepts3_2;
35185377Ssam	int i;
36185377Ssam
37185377Ssam	/* loop for the percentages in steps or 5 */
38185377Ssam	for (i = 0; i < NUM_INTERCEPTS; i++ )
39185377Ssam		*vp++ = (ip[i] * pcdacMax + (100 - ip[i]) * pcdacMin) / 100;
40185377Ssam}
41185377Ssam
42185377Ssam/*
43185377Ssam * Get channel value from binary representation held in eeprom
44185377Ssam */
45185377Ssamstatic uint16_t
46185377Ssamfbin2freq(HAL_EEPROM *ee, uint16_t fbin)
47185377Ssam{
48185377Ssam	if (fbin == CHANNEL_UNUSED)	/* reserved value, don't convert */
49185377Ssam		return fbin;
50185377Ssam	return ee->ee_version <= AR_EEPROM_VER3_2 ?
51185377Ssam		(fbin > 62 ? 5100 + 10*62 + 5*(fbin-62) : 5100 + 10*fbin) :
52185377Ssam		4800 + 5*fbin;
53185377Ssam}
54185377Ssam
55185377Ssamstatic uint16_t
56185377Ssamfbin2freq_2p4(HAL_EEPROM *ee, uint16_t fbin)
57185377Ssam{
58185377Ssam	if (fbin == CHANNEL_UNUSED)	/* reserved value, don't convert */
59185377Ssam		return fbin;
60185377Ssam	return ee->ee_version <= AR_EEPROM_VER3_2 ?
61185377Ssam		2400 + fbin :
62185377Ssam		2300 + fbin;
63185377Ssam}
64185377Ssam
65185377Ssam/*
66185377Ssam * Now copy EEPROM frequency pier contents into the allocated space
67185377Ssam */
68185377Ssamstatic HAL_BOOL
69185377SsamreadEepromFreqPierInfo(struct ath_hal *ah, HAL_EEPROM *ee)
70185377Ssam{
71185377Ssam#define	EEREAD(_off) do {				\
72185377Ssam	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
73185377Ssam		return AH_FALSE;			\
74185377Ssam} while (0)
75185377Ssam	uint16_t eeval, off;
76185377Ssam	int i;
77185377Ssam
78185377Ssam	if (ee->ee_version >= AR_EEPROM_VER4_0 &&
79185377Ssam	    ee->ee_eepMap && !ee->ee_Amode) {
80185377Ssam		/*
81185377Ssam		 * V4.0 EEPROMs with map type 1 have frequency pier
82185377Ssam		 * data only when 11a mode is supported.
83185377Ssam		 */
84185377Ssam		return AH_TRUE;
85185377Ssam	}
86185377Ssam	if (ee->ee_version >= AR_EEPROM_VER3_3) {
87185377Ssam		off = GROUPS_OFFSET3_3 + GROUP1_OFFSET;
88185377Ssam		for (i = 0; i < ee->ee_numChannels11a; i += 2) {
89185377Ssam			EEREAD(off++);
90185377Ssam			ee->ee_channels11a[i]   = (eeval >> 8) & FREQ_MASK_3_3;
91185377Ssam			ee->ee_channels11a[i+1] = eeval & FREQ_MASK_3_3;
92185377Ssam		}
93185377Ssam	} else {
94185377Ssam		off = GROUPS_OFFSET3_2 + GROUP1_OFFSET;
95185377Ssam
96185377Ssam		EEREAD(off++);
97185377Ssam		ee->ee_channels11a[0] = (eeval >> 9) & FREQ_MASK;
98185377Ssam		ee->ee_channels11a[1] = (eeval >> 2) & FREQ_MASK;
99185377Ssam		ee->ee_channels11a[2] = (eeval << 5) & FREQ_MASK;
100185377Ssam
101185377Ssam		EEREAD(off++);
102185377Ssam		ee->ee_channels11a[2] |= (eeval >> 11) & 0x1f;
103185377Ssam		ee->ee_channels11a[3]  = (eeval >>  4) & FREQ_MASK;
104185377Ssam		ee->ee_channels11a[4]  = (eeval <<  3) & FREQ_MASK;
105185377Ssam
106185377Ssam		EEREAD(off++);
107185377Ssam		ee->ee_channels11a[4] |= (eeval >> 13) & 0x7;
108185377Ssam		ee->ee_channels11a[5]  = (eeval >>  6) & FREQ_MASK;
109185377Ssam		ee->ee_channels11a[6]  = (eeval <<  1) & FREQ_MASK;
110185377Ssam
111185377Ssam		EEREAD(off++);
112185377Ssam		ee->ee_channels11a[6] |= (eeval >> 15) & 0x1;
113185377Ssam		ee->ee_channels11a[7]  = (eeval >>  8) & FREQ_MASK;
114185377Ssam		ee->ee_channels11a[8]  = (eeval >>  1) & FREQ_MASK;
115185377Ssam		ee->ee_channels11a[9]  = (eeval <<  6) & FREQ_MASK;
116185377Ssam
117185377Ssam		EEREAD(off++);
118185377Ssam		ee->ee_channels11a[9] |= (eeval >> 10) & 0x3f;
119185377Ssam	}
120185377Ssam
121185377Ssam	for (i = 0; i < ee->ee_numChannels11a; i++)
122185377Ssam		ee->ee_channels11a[i] = fbin2freq(ee, ee->ee_channels11a[i]);
123185377Ssam
124185377Ssam	return AH_TRUE;
125185377Ssam#undef EEREAD
126185377Ssam}
127185377Ssam
128185377Ssam/*
129185377Ssam * Rev 4 Eeprom 5112 Power Extract Functions
130185377Ssam */
131185377Ssam
132185377Ssam/*
133185377Ssam * Allocate the power information based on the number of channels
134185377Ssam * recorded by the calibration.  These values are then initialized.
135185377Ssam */
136185377Ssamstatic HAL_BOOL
137185377SsameepromAllocExpnPower5112(struct ath_hal *ah,
138185377Ssam	const EEPROM_POWER_5112 *pCalDataset,
139185377Ssam	EEPROM_POWER_EXPN_5112 *pPowerExpn)
140185377Ssam{
141185377Ssam	uint16_t numChannels = pCalDataset->numChannels;
142185377Ssam	const uint16_t *pChanList = pCalDataset->pChannels;
143185377Ssam	void *data;
144185377Ssam	int i, j;
145185377Ssam
146185377Ssam	/* Allocate the channel and Power Data arrays together */
147185377Ssam	data = ath_hal_malloc(
148185377Ssam		roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)) +
149185377Ssam		sizeof(EXPN_DATA_PER_CHANNEL_5112) * numChannels);
150185377Ssam	if (data == AH_NULL) {
151185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
152185377Ssam		    "%s unable to allocate raw data struct (gen3)\n", __func__);
153185377Ssam		return AH_FALSE;
154185377Ssam	}
155185377Ssam	pPowerExpn->pChannels = data;
156185377Ssam	pPowerExpn->pDataPerChannel = (void *)(((char *)data) +
157185377Ssam		roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)));
158185377Ssam
159185377Ssam	pPowerExpn->numChannels = numChannels;
160185377Ssam	for (i = 0; i < numChannels; i++) {
161185377Ssam		pPowerExpn->pChannels[i] =
162185377Ssam			pPowerExpn->pDataPerChannel[i].channelValue =
163185377Ssam				pChanList[i];
164185377Ssam		for (j = 0; j < NUM_XPD_PER_CHANNEL; j++) {
165185377Ssam			pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].xpd_gain = j;
166185377Ssam			pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].numPcdacs = 0;
167185377Ssam		}
168185377Ssam		pPowerExpn->pDataPerChannel[i].pDataPerXPD[0].numPcdacs = 4;
169185377Ssam		pPowerExpn->pDataPerChannel[i].pDataPerXPD[3].numPcdacs = 3;
170185377Ssam	}
171185377Ssam	return AH_TRUE;
172185377Ssam}
173185377Ssam
174185377Ssam/*
175185377Ssam * Expand the dataSet from the calibration information into the
176185377Ssam * final power structure for 5112
177185377Ssam */
178185377Ssamstatic HAL_BOOL
179185377SsameepromExpandPower5112(struct ath_hal *ah,
180185377Ssam	const EEPROM_POWER_5112 *pCalDataset,
181185377Ssam	EEPROM_POWER_EXPN_5112 *pPowerExpn)
182185377Ssam{
183185377Ssam	int ii, jj, kk;
184185377Ssam	int16_t maxPower_t4;
185185377Ssam	EXPN_DATA_PER_XPD_5112 *pExpnXPD;
186185377Ssam	/* ptr to array of info held per channel */
187185377Ssam	const EEPROM_DATA_PER_CHANNEL_5112 *pCalCh;
188185377Ssam	uint16_t xgainList[2], xpdMask;
189185377Ssam
190185377Ssam	pPowerExpn->xpdMask = pCalDataset->xpdMask;
191185377Ssam
192185377Ssam	xgainList[0] = 0xDEAD;
193185377Ssam	xgainList[1] = 0xDEAD;
194185377Ssam
195185377Ssam	kk = 0;
196185377Ssam	xpdMask = pPowerExpn->xpdMask;
197185377Ssam	for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) {
198185377Ssam		if (((xpdMask >> jj) & 1) > 0) {
199185377Ssam			if (kk > 1) {
200185377Ssam				HALDEBUG(ah, HAL_DEBUG_ANY,
201185377Ssam				    "%s: too many xpdGains in dataset: %u\n",
202185377Ssam				    __func__, kk);
203185377Ssam				return AH_FALSE;
204185377Ssam			}
205185377Ssam			xgainList[kk++] = jj;
206185377Ssam		}
207185377Ssam	}
208185377Ssam
209185377Ssam	pPowerExpn->numChannels = pCalDataset->numChannels;
210185377Ssam	if (pPowerExpn->numChannels == 0) {
211185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no channels\n", __func__);
212185377Ssam		return AH_FALSE;
213185377Ssam	}
214185377Ssam
215185377Ssam	for (ii = 0; ii < pPowerExpn->numChannels; ii++) {
216185377Ssam		pCalCh = &pCalDataset->pDataPerChannel[ii];
217185377Ssam		pPowerExpn->pDataPerChannel[ii].channelValue =
218185377Ssam			pCalCh->channelValue;
219185377Ssam		pPowerExpn->pDataPerChannel[ii].maxPower_t4 =
220185377Ssam			pCalCh->maxPower_t4;
221185377Ssam		maxPower_t4 = pPowerExpn->pDataPerChannel[ii].maxPower_t4;
222185377Ssam
223185377Ssam		for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++)
224185377Ssam			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj].numPcdacs = 0;
225185377Ssam		if (xgainList[1] == 0xDEAD) {
226185377Ssam			jj = xgainList[0];
227185377Ssam			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
228185377Ssam			pExpnXPD->numPcdacs = 4;
229185377Ssam			pExpnXPD->pcdac[0] = pCalCh->pcd1_xg0;
230185377Ssam			pExpnXPD->pcdac[1] = (uint16_t)
231185377Ssam				(pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0);
232185377Ssam			pExpnXPD->pcdac[2] = (uint16_t)
233185377Ssam				(pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0);
234185377Ssam			pExpnXPD->pcdac[3] = (uint16_t)
235185377Ssam				(pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0);
236185377Ssam
237185377Ssam			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0;
238185377Ssam			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0;
239185377Ssam			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0;
240185377Ssam			pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0;
241185377Ssam
242185377Ssam		} else {
243185377Ssam			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[0]].pcdac[0] = pCalCh->pcd1_xg0;
244185377Ssam			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[0] = 20;
245185377Ssam			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[1] = 35;
246185377Ssam			pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[2] = 63;
247185377Ssam
248185377Ssam			jj = xgainList[0];
249185377Ssam			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
250185377Ssam			pExpnXPD->numPcdacs = 4;
251185377Ssam			pExpnXPD->pcdac[1] = (uint16_t)
252185377Ssam				(pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0);
253185377Ssam			pExpnXPD->pcdac[2] = (uint16_t)
254185377Ssam				(pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0);
255185377Ssam			pExpnXPD->pcdac[3] = (uint16_t)
256185377Ssam				(pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0);
257185377Ssam			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0;
258185377Ssam			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0;
259185377Ssam			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0;
260185377Ssam			pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0;
261185377Ssam
262185377Ssam			jj = xgainList[1];
263185377Ssam			pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];
264185377Ssam			pExpnXPD->numPcdacs = 3;
265185377Ssam
266185377Ssam			pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg3;
267185377Ssam			pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg3;
268185377Ssam			pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg3;
269185377Ssam		}
270185377Ssam	}
271185377Ssam	return AH_TRUE;
272185377Ssam}
273185377Ssam
274185377Ssamstatic HAL_BOOL
275185377SsamreadEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee)
276185377Ssam{
277185377Ssam#define	EEREAD(_off) do {				\
278185377Ssam	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
279185377Ssam		return AH_FALSE;			\
280185377Ssam} while (0)
281185377Ssam	const uint16_t dbmmask		 = 0xff;
282185377Ssam	const uint16_t pcdac_delta_mask = 0x1f;
283185377Ssam	const uint16_t pcdac_mask	 = 0x3f;
284185377Ssam	const uint16_t freqmask	 = 0xff;
285185377Ssam
286185377Ssam	int i, mode, numPiers;
287185377Ssam	uint32_t off;
288185377Ssam	uint16_t eeval;
289185377Ssam	uint16_t freq[NUM_11A_EEPROM_CHANNELS];
290185377Ssam        EEPROM_POWER_5112 eePower;
291185377Ssam
292185377Ssam	HALASSERT(ee->ee_version >= AR_EEPROM_VER4_0);
293185377Ssam	off = GROUPS_OFFSET3_3;
294185377Ssam	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
295185377Ssam		numPiers = 0;
296185377Ssam		switch (mode) {
297185377Ssam		case headerInfo11A:
298185377Ssam			if (!ee->ee_Amode)	/* no 11a calibration data */
299185377Ssam				continue;
300185377Ssam			while (numPiers < NUM_11A_EEPROM_CHANNELS) {
301185377Ssam				EEREAD(off++);
302185377Ssam				if ((eeval & freqmask) == 0)
303185377Ssam					break;
304185377Ssam				freq[numPiers++] = fbin2freq(ee,
305185377Ssam					eeval & freqmask);
306185377Ssam
307185377Ssam				if (((eeval >> 8) & freqmask) == 0)
308185377Ssam					break;
309185377Ssam				freq[numPiers++] = fbin2freq(ee,
310185377Ssam					(eeval>>8) & freqmask);
311185377Ssam			}
312185377Ssam			break;
313185377Ssam		case headerInfo11B:
314185377Ssam			if (!ee->ee_Bmode)	/* no 11b calibration data */
315185377Ssam				continue;
316185377Ssam			for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++)
317185377Ssam				if (ee->ee_calPier11b[i] != CHANNEL_UNUSED)
318185377Ssam					freq[numPiers++] = ee->ee_calPier11b[i];
319185377Ssam			break;
320185377Ssam		case headerInfo11G:
321185377Ssam			if (!ee->ee_Gmode)	/* no 11g calibration data */
322185377Ssam				continue;
323185377Ssam			for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++)
324185377Ssam				if (ee->ee_calPier11g[i] != CHANNEL_UNUSED)
325185377Ssam					freq[numPiers++] = ee->ee_calPier11g[i];
326185377Ssam			break;
327185377Ssam		default:
328185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
329185377Ssam			    __func__, mode);
330185377Ssam			return AH_FALSE;
331185377Ssam		}
332185377Ssam
333185377Ssam		OS_MEMZERO(&eePower, sizeof(eePower));
334185377Ssam		eePower.numChannels = numPiers;
335185377Ssam
336185377Ssam		for (i = 0; i < numPiers; i++) {
337185377Ssam			eePower.pChannels[i] = freq[i];
338185377Ssam			eePower.pDataPerChannel[i].channelValue = freq[i];
339185377Ssam
340185377Ssam			EEREAD(off++);
341185377Ssam			eePower.pDataPerChannel[i].pwr1_xg0 = (int16_t)
342185377Ssam				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
343185377Ssam			eePower.pDataPerChannel[i].pwr2_xg0 = (int16_t)
344185377Ssam				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
345185377Ssam
346185377Ssam			EEREAD(off++);
347185377Ssam			eePower.pDataPerChannel[i].pwr3_xg0 = (int16_t)
348185377Ssam				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
349185377Ssam			eePower.pDataPerChannel[i].pwr4_xg0 = (int16_t)
350185377Ssam				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
351185377Ssam
352185377Ssam			EEREAD(off++);
353185377Ssam			eePower.pDataPerChannel[i].pcd2_delta_xg0 = (uint16_t)
354185377Ssam				(eeval & pcdac_delta_mask);
355185377Ssam			eePower.pDataPerChannel[i].pcd3_delta_xg0 = (uint16_t)
356185377Ssam				((eeval >> 5) & pcdac_delta_mask);
357185377Ssam			eePower.pDataPerChannel[i].pcd4_delta_xg0 = (uint16_t)
358185377Ssam				((eeval >> 10) & pcdac_delta_mask);
359185377Ssam
360185377Ssam			EEREAD(off++);
361185377Ssam			eePower.pDataPerChannel[i].pwr1_xg3 = (int16_t)
362185377Ssam				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
363185377Ssam			eePower.pDataPerChannel[i].pwr2_xg3 = (int16_t)
364185377Ssam				(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);
365185377Ssam
366185377Ssam			EEREAD(off++);
367185377Ssam			eePower.pDataPerChannel[i].pwr3_xg3 = (int16_t)
368185377Ssam				((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);
369185377Ssam			if (ee->ee_version >= AR_EEPROM_VER4_3) {
370185377Ssam				eePower.pDataPerChannel[i].maxPower_t4 =
371185377Ssam					eePower.pDataPerChannel[i].pwr4_xg0;
372185377Ssam				eePower.pDataPerChannel[i].pcd1_xg0 = (uint16_t)
373185377Ssam					((eeval >> 8) & pcdac_mask);
374185377Ssam			} else {
375185377Ssam				eePower.pDataPerChannel[i].maxPower_t4 = (int16_t)
376185377Ssam					(((eeval >> 8) & dbmmask) -
377185377Ssam					 ((eeval >> 15) & 0x1)*256);
378185377Ssam				eePower.pDataPerChannel[i].pcd1_xg0 = 1;
379185377Ssam			}
380185377Ssam		}
381185377Ssam		eePower.xpdMask = ee->ee_xgain[mode];
382185377Ssam
383185377Ssam		if (!eepromAllocExpnPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) {
384185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY,
385185377Ssam			    "%s: did not allocate power struct\n", __func__);
386185377Ssam			return AH_FALSE;
387185377Ssam                }
388185377Ssam                if (!eepromExpandPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) {
389185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY,
390185377Ssam			    "%s: did not expand power struct\n", __func__);
391185377Ssam			return AH_FALSE;
392185377Ssam		}
393185377Ssam	}
394185377Ssam	return AH_TRUE;
395185377Ssam#undef EEREAD
396185377Ssam}
397185377Ssam
398185377Ssamstatic void
399185377SsamfreeEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee)
400185377Ssam{
401185377Ssam	int mode;
402185377Ssam	void *data;
403185377Ssam
404185377Ssam	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
405185377Ssam		EEPROM_POWER_EXPN_5112 *pPowerExpn =
406185377Ssam			&ee->ee_modePowerArray5112[mode];
407185377Ssam		data = pPowerExpn->pChannels;
408185377Ssam		if (data != AH_NULL) {
409185377Ssam			pPowerExpn->pChannels = AH_NULL;
410185377Ssam			ath_hal_free(data);
411185377Ssam		}
412185377Ssam	}
413185377Ssam}
414185377Ssam
415185377Ssamstatic void
416185377Ssamar2413SetupEEPROMDataset(EEPROM_DATA_STRUCT_2413 *pEEPROMDataset2413,
417185377Ssam	uint16_t myNumRawChannels, uint16_t *pMyRawChanList)
418185377Ssam{
419185377Ssam	uint16_t i, channelValue;
420185377Ssam	uint32_t xpd_mask;
421185377Ssam	uint16_t numPdGainsUsed;
422185377Ssam
423185377Ssam	pEEPROMDataset2413->numChannels = myNumRawChannels;
424185377Ssam
425185377Ssam	xpd_mask = pEEPROMDataset2413->xpd_mask;
426185377Ssam	numPdGainsUsed = 0;
427185377Ssam	if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++;
428185377Ssam	if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++;
429185377Ssam	if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++;
430185377Ssam	if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++;
431185377Ssam
432185377Ssam	for (i = 0; i < myNumRawChannels; i++) {
433185377Ssam		channelValue = pMyRawChanList[i];
434185377Ssam		pEEPROMDataset2413->pChannels[i] = channelValue;
435185377Ssam		pEEPROMDataset2413->pDataPerChannel[i].channelValue = channelValue;
436185377Ssam		pEEPROMDataset2413->pDataPerChannel[i].numPdGains = numPdGainsUsed;
437185377Ssam	}
438185377Ssam}
439185377Ssam
440185377Ssamstatic HAL_BOOL
441185377Ssamar2413ReadCalDataset(struct ath_hal *ah, HAL_EEPROM *ee,
442185377Ssam	EEPROM_DATA_STRUCT_2413 *pCalDataset,
443185377Ssam	uint32_t start_offset, uint32_t maxPiers, uint8_t mode)
444185377Ssam{
445185377Ssam#define	EEREAD(_off) do {				\
446185377Ssam	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
447185377Ssam		return AH_FALSE;			\
448185377Ssam} while (0)
449185377Ssam	const uint16_t dbm_I_mask = 0x1F;	/* 5-bits. 1dB step. */
450185377Ssam	const uint16_t dbm_delta_mask = 0xF;	/* 4-bits. 0.5dB step. */
451185377Ssam	const uint16_t Vpd_I_mask = 0x7F;	/* 7-bits. 0-128 */
452185377Ssam	const uint16_t Vpd_delta_mask = 0x3F;	/* 6-bits. 0-63 */
453185377Ssam	const uint16_t freqmask = 0xff;
454185377Ssam
455185377Ssam	uint16_t ii, eeval;
456185377Ssam	uint16_t idx, numPiers;
457185377Ssam	uint16_t freq[NUM_11A_EEPROM_CHANNELS];
458185377Ssam
459185377Ssam	idx = start_offset;
460185377Ssam    for (numPiers = 0; numPiers < maxPiers;) {
461185377Ssam        EEREAD(idx++);
462185377Ssam        if ((eeval & freqmask) == 0)
463185377Ssam            break;
464185377Ssam        if (mode == headerInfo11A)
465185377Ssam            freq[numPiers++] = fbin2freq(ee, (eeval & freqmask));
466185377Ssam        else
467185377Ssam            freq[numPiers++] = fbin2freq_2p4(ee, (eeval & freqmask));
468185377Ssam
469185377Ssam        if (((eeval >> 8) & freqmask) == 0)
470185377Ssam            break;
471185377Ssam        if (mode == headerInfo11A)
472185377Ssam            freq[numPiers++] = fbin2freq(ee, (eeval >> 8) & freqmask);
473185377Ssam        else
474185377Ssam            freq[numPiers++] = fbin2freq_2p4(ee, (eeval >> 8) & freqmask);
475185377Ssam    }
476185377Ssam	ar2413SetupEEPROMDataset(pCalDataset, numPiers, &freq[0]);
477185377Ssam
478185377Ssam	idx = start_offset + (maxPiers / 2);
479185377Ssam	for (ii = 0; ii < pCalDataset->numChannels; ii++) {
480185377Ssam		EEPROM_DATA_PER_CHANNEL_2413 *currCh =
481185377Ssam			&(pCalDataset->pDataPerChannel[ii]);
482185377Ssam
483185377Ssam		if (currCh->numPdGains > 0) {
484185377Ssam			/*
485185377Ssam			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
486185377Ssam			 * and Vpd values for pdgain_0
487185377Ssam			 */
488185377Ssam			EEREAD(idx++);
489185377Ssam			currCh->pwr_I[0] = eeval & dbm_I_mask;
490185377Ssam			currCh->Vpd_I[0] = (eeval >> 5) & Vpd_I_mask;
491185377Ssam			currCh->pwr_delta_t2[0][0] =
492185377Ssam				(eeval >> 12) & dbm_delta_mask;
493185377Ssam
494185377Ssam			EEREAD(idx++);
495185377Ssam			currCh->Vpd_delta[0][0] = eeval & Vpd_delta_mask;
496185377Ssam			currCh->pwr_delta_t2[1][0] =
497185377Ssam				(eeval >> 6) & dbm_delta_mask;
498185377Ssam			currCh->Vpd_delta[1][0] =
499185377Ssam				(eeval >> 10) & Vpd_delta_mask;
500185377Ssam
501185377Ssam			EEREAD(idx++);
502185377Ssam			currCh->pwr_delta_t2[2][0] = eeval & dbm_delta_mask;
503185377Ssam			currCh->Vpd_delta[2][0] = (eeval >> 4) & Vpd_delta_mask;
504185377Ssam		}
505185377Ssam
506185377Ssam		if (currCh->numPdGains > 1) {
507185377Ssam			/*
508185377Ssam			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
509185377Ssam			 * and Vpd values for pdgain_1
510185377Ssam			 */
511185377Ssam			currCh->pwr_I[1] = (eeval >> 10) & dbm_I_mask;
512185377Ssam			currCh->Vpd_I[1] = (eeval >> 15) & 0x1;
513185377Ssam
514185377Ssam			EEREAD(idx++);
515185377Ssam			/* upper 6 bits */
516185377Ssam			currCh->Vpd_I[1] |= (eeval & 0x3F) << 1;
517185377Ssam			currCh->pwr_delta_t2[0][1] =
518185377Ssam				(eeval >> 6) & dbm_delta_mask;
519185377Ssam			currCh->Vpd_delta[0][1] =
520185377Ssam				(eeval >> 10) & Vpd_delta_mask;
521185377Ssam
522185377Ssam			EEREAD(idx++);
523185377Ssam			currCh->pwr_delta_t2[1][1] = eeval & dbm_delta_mask;
524185377Ssam			currCh->Vpd_delta[1][1] = (eeval >> 4) & Vpd_delta_mask;
525185377Ssam			currCh->pwr_delta_t2[2][1] =
526185377Ssam				(eeval >> 10) & dbm_delta_mask;
527185377Ssam			currCh->Vpd_delta[2][1] = (eeval >> 14) & 0x3;
528185377Ssam
529185377Ssam			EEREAD(idx++);
530185377Ssam			/* upper 4 bits */
531185377Ssam			currCh->Vpd_delta[2][1] |= (eeval & 0xF) << 2;
532185377Ssam		} else if (currCh->numPdGains == 1) {
533185377Ssam			/*
534185377Ssam			 * Read the last pwr and Vpd values for pdgain_0
535185377Ssam			 */
536185377Ssam			currCh->pwr_delta_t2[3][0] =
537185377Ssam				(eeval >> 10) & dbm_delta_mask;
538185377Ssam			currCh->Vpd_delta[3][0] = (eeval >> 14) & 0x3;
539185377Ssam
540185377Ssam			EEREAD(idx++);
541185377Ssam			/* upper 4 bits */
542185377Ssam			currCh->Vpd_delta[3][0] |= (eeval & 0xF) << 2;
543185377Ssam
544185377Ssam			/* 4 words if numPdGains == 1 */
545185377Ssam		}
546185377Ssam
547185377Ssam		if (currCh->numPdGains > 2) {
548185377Ssam			/*
549185377Ssam			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
550185377Ssam			 * and Vpd values for pdgain_2
551185377Ssam			 */
552185377Ssam			currCh->pwr_I[2] = (eeval >> 4) & dbm_I_mask;
553185377Ssam			currCh->Vpd_I[2] = (eeval >> 9) & Vpd_I_mask;
554185377Ssam
555185377Ssam			EEREAD(idx++);
556185377Ssam			currCh->pwr_delta_t2[0][2] =
557185377Ssam				(eeval >> 0) & dbm_delta_mask;
558185377Ssam			currCh->Vpd_delta[0][2] = (eeval >> 4) & Vpd_delta_mask;
559185377Ssam			currCh->pwr_delta_t2[1][2] =
560185377Ssam				(eeval >> 10) & dbm_delta_mask;
561185377Ssam			currCh->Vpd_delta[1][2] = (eeval >> 14) & 0x3;
562185377Ssam
563185377Ssam			EEREAD(idx++);
564185377Ssam			/* upper 4 bits */
565185377Ssam			currCh->Vpd_delta[1][2] |= (eeval & 0xF) << 2;
566185377Ssam			currCh->pwr_delta_t2[2][2] =
567185377Ssam				(eeval >> 4) & dbm_delta_mask;
568185377Ssam			currCh->Vpd_delta[2][2] = (eeval >> 8) & Vpd_delta_mask;
569185377Ssam		} else if (currCh->numPdGains == 2) {
570185377Ssam			/*
571185377Ssam			 * Read the last pwr and Vpd values for pdgain_1
572185377Ssam			 */
573185377Ssam			currCh->pwr_delta_t2[3][1] =
574185377Ssam				(eeval >> 4) & dbm_delta_mask;
575185377Ssam			currCh->Vpd_delta[3][1] = (eeval >> 8) & Vpd_delta_mask;
576185377Ssam
577185377Ssam			/* 6 words if numPdGains == 2 */
578185377Ssam		}
579185377Ssam
580185377Ssam		if (currCh->numPdGains > 3) {
581185377Ssam			/*
582185377Ssam			 * Read the first NUM_POINTS_OTHER_PDGAINS pwr
583185377Ssam			 * and Vpd values for pdgain_3
584185377Ssam			 */
585185377Ssam			currCh->pwr_I[3] = (eeval >> 14) & 0x3;
586185377Ssam
587185377Ssam			EEREAD(idx++);
588185377Ssam			/* upper 3 bits */
589185377Ssam			currCh->pwr_I[3] |= ((eeval >> 0) & 0x7) << 2;
590185377Ssam			currCh->Vpd_I[3] = (eeval >> 3) & Vpd_I_mask;
591185377Ssam			currCh->pwr_delta_t2[0][3] =
592185377Ssam				(eeval >> 10) & dbm_delta_mask;
593185377Ssam			currCh->Vpd_delta[0][3] = (eeval >> 14) & 0x3;
594185377Ssam
595185377Ssam			EEREAD(idx++);
596185377Ssam			/* upper 4 bits */
597185377Ssam			currCh->Vpd_delta[0][3] |= (eeval & 0xF) << 2;
598185377Ssam			currCh->pwr_delta_t2[1][3] =
599185377Ssam				(eeval >> 4) & dbm_delta_mask;
600185377Ssam			currCh->Vpd_delta[1][3] = (eeval >> 8) & Vpd_delta_mask;
601185377Ssam			currCh->pwr_delta_t2[2][3] = (eeval >> 14) & 0x3;
602185377Ssam
603185377Ssam			EEREAD(idx++);
604185377Ssam			/* upper 2 bits */
605185377Ssam			currCh->pwr_delta_t2[2][3] |= ((eeval >> 0) & 0x3) << 2;
606185377Ssam			currCh->Vpd_delta[2][3] = (eeval >> 2) & Vpd_delta_mask;
607185377Ssam			currCh->pwr_delta_t2[3][3] =
608185377Ssam				(eeval >> 8) & dbm_delta_mask;
609185377Ssam			currCh->Vpd_delta[3][3] = (eeval >> 12) & 0xF;
610185377Ssam
611185377Ssam			EEREAD(idx++);
612185377Ssam			/* upper 2 bits */
613185377Ssam			currCh->Vpd_delta[3][3] |= ((eeval >> 0) & 0x3) << 4;
614185377Ssam
615185377Ssam			/* 12 words if numPdGains == 4 */
616185377Ssam		} else if (currCh->numPdGains == 3) {
617185377Ssam			/* read the last pwr and Vpd values for pdgain_2 */
618185377Ssam			currCh->pwr_delta_t2[3][2] = (eeval >> 14) & 0x3;
619185377Ssam
620185377Ssam			EEREAD(idx++);
621185377Ssam			/* upper 2 bits */
622185377Ssam			currCh->pwr_delta_t2[3][2] |= ((eeval >> 0) & 0x3) << 2;
623185377Ssam			currCh->Vpd_delta[3][2] = (eeval >> 2) & Vpd_delta_mask;
624185377Ssam
625185377Ssam			/* 9 words if numPdGains == 3 */
626185377Ssam		}
627185377Ssam	}
628185377Ssam	return AH_TRUE;
629185377Ssam#undef EEREAD
630185377Ssam}
631185377Ssam
632185377Ssamstatic void
633185377Ssamar2413SetupRawDataset(RAW_DATA_STRUCT_2413 *pRaw, EEPROM_DATA_STRUCT_2413 *pCal)
634185377Ssam{
635185377Ssam	uint16_t i, j, kk, channelValue;
636185377Ssam	uint16_t xpd_mask;
637185377Ssam	uint16_t numPdGainsUsed;
638185377Ssam
639185377Ssam	pRaw->numChannels = pCal->numChannels;
640185377Ssam
641185377Ssam	xpd_mask = pRaw->xpd_mask;
642185377Ssam	numPdGainsUsed = 0;
643185377Ssam	if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++;
644185377Ssam	if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++;
645185377Ssam	if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++;
646185377Ssam	if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++;
647185377Ssam
648185377Ssam	for (i = 0; i < pCal->numChannels; i++) {
649185377Ssam		channelValue = pCal->pChannels[i];
650185377Ssam
651185377Ssam		pRaw->pChannels[i] = channelValue;
652185377Ssam
653185377Ssam		pRaw->pDataPerChannel[i].channelValue = channelValue;
654185377Ssam		pRaw->pDataPerChannel[i].numPdGains = numPdGainsUsed;
655185377Ssam
656185377Ssam		kk = 0;
657185377Ssam		for (j = 0; j < MAX_NUM_PDGAINS_PER_CHANNEL; j++) {
658185377Ssam			pRaw->pDataPerChannel[i].pDataPerPDGain[j].pd_gain = j;
659185377Ssam			if ((xpd_mask >> j) & 0x1) {
660185377Ssam				pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_OTHER_PDGAINS;
661185377Ssam				kk++;
662185377Ssam				if (kk == 1) {
663185377Ssam					/*
664185377Ssam					 * lowest pd_gain corresponds
665185377Ssam					 *  to highest power and thus,
666185377Ssam					 *  has one more point
667185377Ssam					 */
668185377Ssam					pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_LAST_PDGAIN;
669185377Ssam				}
670185377Ssam			} else {
671185377Ssam				pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = 0;
672185377Ssam			}
673185377Ssam		}
674185377Ssam	}
675185377Ssam}
676185377Ssam
677185377Ssamstatic HAL_BOOL
678185377Ssamar2413EepromToRawDataset(struct ath_hal *ah,
679185377Ssam	EEPROM_DATA_STRUCT_2413 *pCal, RAW_DATA_STRUCT_2413 *pRaw)
680185377Ssam{
681185377Ssam	uint16_t ii, jj, kk, ss;
682185377Ssam	RAW_DATA_PER_PDGAIN_2413 *pRawXPD;
683185377Ssam	/* ptr to array of info held per channel */
684185377Ssam	EEPROM_DATA_PER_CHANNEL_2413 *pCalCh;
685185377Ssam	uint16_t xgain_list[MAX_NUM_PDGAINS_PER_CHANNEL];
686185377Ssam	uint16_t xpd_mask;
687185377Ssam	uint32_t numPdGainsUsed;
688185377Ssam
689185377Ssam	HALASSERT(pRaw->xpd_mask == pCal->xpd_mask);
690185377Ssam
691185377Ssam	xgain_list[0] = 0xDEAD;
692185377Ssam	xgain_list[1] = 0xDEAD;
693185377Ssam	xgain_list[2] = 0xDEAD;
694185377Ssam	xgain_list[3] = 0xDEAD;
695185377Ssam
696185377Ssam	numPdGainsUsed = 0;
697185377Ssam	xpd_mask = pRaw->xpd_mask;
698185377Ssam	for (jj = 0; jj < MAX_NUM_PDGAINS_PER_CHANNEL; jj++) {
699185377Ssam		if ((xpd_mask >> (MAX_NUM_PDGAINS_PER_CHANNEL-jj-1)) & 1)
700185377Ssam			xgain_list[numPdGainsUsed++] = MAX_NUM_PDGAINS_PER_CHANNEL-jj-1;
701185377Ssam	}
702185377Ssam
703185377Ssam	pRaw->numChannels = pCal->numChannels;
704185377Ssam	for (ii = 0; ii < pRaw->numChannels; ii++) {
705185377Ssam		pCalCh = &(pCal->pDataPerChannel[ii]);
706185377Ssam		pRaw->pDataPerChannel[ii].channelValue = pCalCh->channelValue;
707185377Ssam
708185377Ssam		/* numVpd has already been setup appropriately for the relevant pdGains */
709185377Ssam		for (jj = 0; jj < numPdGainsUsed; jj++) {
710185377Ssam			/* use jj for calDataset and ss for rawDataset */
711185377Ssam			ss = xgain_list[jj];
712185377Ssam			pRawXPD = &(pRaw->pDataPerChannel[ii].pDataPerPDGain[ss]);
713185377Ssam			HALASSERT(pRawXPD->numVpd >= 1);
714185377Ssam
715185377Ssam			pRawXPD->pwr_t4[0] = (uint16_t)(4*pCalCh->pwr_I[jj]);
716185377Ssam			pRawXPD->Vpd[0]    = pCalCh->Vpd_I[jj];
717185377Ssam
718185377Ssam			for (kk = 1; kk < pRawXPD->numVpd; kk++) {
719185377Ssam				pRawXPD->pwr_t4[kk] = (int16_t)(pRawXPD->pwr_t4[kk-1] + 2*pCalCh->pwr_delta_t2[kk-1][jj]);
720185377Ssam				pRawXPD->Vpd[kk] = (uint16_t)(pRawXPD->Vpd[kk-1] + pCalCh->Vpd_delta[kk-1][jj]);
721185377Ssam			}
722185377Ssam			/* loop over Vpds */
723185377Ssam		}
724185377Ssam		/* loop over pd_gains */
725185377Ssam	}
726185377Ssam	/* loop over channels */
727185377Ssam	return AH_TRUE;
728185377Ssam}
729185377Ssam
730185377Ssamstatic HAL_BOOL
731185377SsamreadEepromRawPowerCalInfo2413(struct ath_hal *ah, HAL_EEPROM *ee)
732185377Ssam{
733185377Ssam	/* NB: index is 1 less than numPdgains */
734185377Ssam	static const uint16_t wordsForPdgains[] = { 4, 6, 9, 12 };
735185377Ssam	EEPROM_DATA_STRUCT_2413 *pCal = AH_NULL;
736185377Ssam	RAW_DATA_STRUCT_2413 *pRaw;
737185377Ssam	int numEEPROMWordsPerChannel;
738185377Ssam	uint32_t off;
739185377Ssam	HAL_BOOL ret = AH_FALSE;
740185377Ssam
741185377Ssam	HALASSERT(ee->ee_version >= AR_EEPROM_VER5_0);
742185377Ssam	HALASSERT(ee->ee_eepMap == 2);
743185377Ssam
744185377Ssam	pCal = ath_hal_malloc(sizeof(EEPROM_DATA_STRUCT_2413));
745185377Ssam	if (pCal == AH_NULL)
746185377Ssam		goto exit;
747185377Ssam
748185377Ssam	off = ee->ee_eepMap2PowerCalStart;
749185377Ssam	if (ee->ee_Amode) {
750185377Ssam		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
751185377Ssam		pCal->xpd_mask = ee->ee_xgain[headerInfo11A];
752185377Ssam		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
753185377Ssam			NUM_11A_EEPROM_CHANNELS_2413, headerInfo11A)) {
754185377Ssam			goto exit;
755185377Ssam		}
756185377Ssam		pRaw = &ee->ee_rawDataset2413[headerInfo11A];
757185377Ssam		pRaw->xpd_mask = ee->ee_xgain[headerInfo11A];
758185377Ssam		ar2413SetupRawDataset(pRaw, pCal);
759185377Ssam		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
760185377Ssam			goto exit;
761185377Ssam		}
762185377Ssam		/* setup offsets for mode_11a next */
763185377Ssam		numEEPROMWordsPerChannel = wordsForPdgains[
764185377Ssam			pCal->pDataPerChannel[0].numPdGains - 1];
765185377Ssam		off += pCal->numChannels * numEEPROMWordsPerChannel + 5;
766185377Ssam	}
767185377Ssam	if (ee->ee_Bmode) {
768185377Ssam		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
769185377Ssam		pCal->xpd_mask = ee->ee_xgain[headerInfo11B];
770185377Ssam		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
771185377Ssam			NUM_2_4_EEPROM_CHANNELS_2413 , headerInfo11B)) {
772185377Ssam			goto exit;
773185377Ssam		}
774185377Ssam		pRaw = &ee->ee_rawDataset2413[headerInfo11B];
775185377Ssam		pRaw->xpd_mask = ee->ee_xgain[headerInfo11B];
776185377Ssam		ar2413SetupRawDataset(pRaw, pCal);
777185377Ssam		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
778185377Ssam			goto exit;
779185377Ssam		}
780185377Ssam		/* setup offsets for mode_11g next */
781185377Ssam		numEEPROMWordsPerChannel = wordsForPdgains[
782185377Ssam			pCal->pDataPerChannel[0].numPdGains - 1];
783185377Ssam		off += pCal->numChannels * numEEPROMWordsPerChannel + 2;
784185377Ssam	}
785185377Ssam	if (ee->ee_Gmode) {
786185377Ssam		OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));
787185377Ssam		pCal->xpd_mask = ee->ee_xgain[headerInfo11G];
788185377Ssam		if (!ar2413ReadCalDataset(ah, ee, pCal, off,
789185377Ssam			NUM_2_4_EEPROM_CHANNELS_2413, headerInfo11G)) {
790185377Ssam			goto exit;
791185377Ssam		}
792185377Ssam		pRaw = &ee->ee_rawDataset2413[headerInfo11G];
793185377Ssam		pRaw->xpd_mask = ee->ee_xgain[headerInfo11G];
794185377Ssam		ar2413SetupRawDataset(pRaw, pCal);
795185377Ssam		if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {
796185377Ssam			goto exit;
797185377Ssam		}
798185377Ssam	}
799185377Ssam	ret = AH_TRUE;
800185377Ssam exit:
801185377Ssam	if (pCal != AH_NULL)
802185377Ssam		ath_hal_free(pCal);
803185377Ssam	return ret;
804185377Ssam}
805185377Ssam
806185377Ssam/*
807185377Ssam * Now copy EEPROM Raw Power Calibration per frequency contents
808185377Ssam * into the allocated space
809185377Ssam */
810185377Ssamstatic HAL_BOOL
811185377SsamreadEepromRawPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee)
812185377Ssam{
813185377Ssam#define	EEREAD(_off) do {				\
814185377Ssam	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
815185377Ssam		return AH_FALSE;			\
816185377Ssam} while (0)
817185377Ssam	uint16_t eeval, nchan;
818185377Ssam	uint32_t off;
819185377Ssam	int i, j, mode;
820185377Ssam
821185377Ssam        if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1)
822185377Ssam		return readEepromRawPowerCalInfo5112(ah, ee);
823185377Ssam	if (ee->ee_version >= AR_EEPROM_VER5_0 && ee->ee_eepMap == 2)
824185377Ssam		return readEepromRawPowerCalInfo2413(ah, ee);
825185377Ssam
826185377Ssam	/*
827185377Ssam	 * Group 2:  read raw power data for all frequency piers
828185377Ssam	 *
829185377Ssam	 * NOTE: Group 2 contains the raw power calibration
830185377Ssam	 *	 information for each of the channels that
831185377Ssam	 *	 we recorded above.
832185377Ssam	 */
833185377Ssam	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
834185377Ssam		uint16_t *pChannels = AH_NULL;
835185377Ssam		DATA_PER_CHANNEL *pChannelData = AH_NULL;
836185377Ssam
837185377Ssam		off = ee->ee_version >= AR_EEPROM_VER3_3 ?
838185377Ssam			GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2;
839185377Ssam		switch (mode) {
840185377Ssam		case headerInfo11A:
841185377Ssam			off      	+= GROUP2_OFFSET;
842185377Ssam			nchan		= ee->ee_numChannels11a;
843185377Ssam			pChannelData	= ee->ee_dataPerChannel11a;
844185377Ssam			pChannels	= ee->ee_channels11a;
845185377Ssam			break;
846185377Ssam		case headerInfo11B:
847185377Ssam			if (!ee->ee_Bmode)
848185377Ssam				continue;
849185377Ssam			off		+= GROUP3_OFFSET;
850185377Ssam			nchan		= ee->ee_numChannels2_4;
851185377Ssam			pChannelData	= ee->ee_dataPerChannel11b;
852185377Ssam			pChannels	= ee->ee_channels11b;
853185377Ssam			break;
854185377Ssam		case headerInfo11G:
855185377Ssam			if (!ee->ee_Gmode)
856185377Ssam				continue;
857185377Ssam			off		+= GROUP4_OFFSET;
858185377Ssam			nchan		= ee->ee_numChannels2_4;
859185377Ssam			pChannelData	= ee->ee_dataPerChannel11g;
860185377Ssam			pChannels	= ee->ee_channels11g;
861185377Ssam			break;
862185377Ssam		default:
863185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
864185377Ssam			    __func__, mode);
865185377Ssam			return AH_FALSE;
866185377Ssam		}
867185377Ssam		for (i = 0; i < nchan; i++) {
868185377Ssam			pChannelData->channelValue = pChannels[i];
869185377Ssam
870185377Ssam			EEREAD(off++);
871185377Ssam			pChannelData->pcdacMax     = (uint16_t)((eeval >> 10) & PCDAC_MASK);
872185377Ssam			pChannelData->pcdacMin     = (uint16_t)((eeval >> 4) & PCDAC_MASK);
873185377Ssam			pChannelData->PwrValues[0] = (uint16_t)((eeval << 2) & POWER_MASK);
874185377Ssam
875185377Ssam			EEREAD(off++);
876185377Ssam			pChannelData->PwrValues[0] |= (uint16_t)((eeval >> 14) & 0x3);
877185377Ssam			pChannelData->PwrValues[1] = (uint16_t)((eeval >> 8) & POWER_MASK);
878185377Ssam			pChannelData->PwrValues[2] = (uint16_t)((eeval >> 2) & POWER_MASK);
879185377Ssam			pChannelData->PwrValues[3] = (uint16_t)((eeval << 4) & POWER_MASK);
880185377Ssam
881185377Ssam			EEREAD(off++);
882185377Ssam			pChannelData->PwrValues[3] |= (uint16_t)((eeval >> 12) & 0xf);
883185377Ssam			pChannelData->PwrValues[4] = (uint16_t)((eeval >> 6) & POWER_MASK);
884185377Ssam			pChannelData->PwrValues[5] = (uint16_t)(eeval  & POWER_MASK);
885185377Ssam
886185377Ssam			EEREAD(off++);
887185377Ssam			pChannelData->PwrValues[6] = (uint16_t)((eeval >> 10) & POWER_MASK);
888185377Ssam			pChannelData->PwrValues[7] = (uint16_t)((eeval >> 4) & POWER_MASK);
889185377Ssam			pChannelData->PwrValues[8] = (uint16_t)((eeval << 2) & POWER_MASK);
890185377Ssam
891185377Ssam			EEREAD(off++);
892185377Ssam			pChannelData->PwrValues[8] |= (uint16_t)((eeval >> 14) & 0x3);
893185377Ssam			pChannelData->PwrValues[9] = (uint16_t)((eeval >> 8) & POWER_MASK);
894185377Ssam			pChannelData->PwrValues[10] = (uint16_t)((eeval >> 2) & POWER_MASK);
895185377Ssam
896185377Ssam			getPcdacInterceptsFromPcdacMinMax(ee,
897185377Ssam				pChannelData->pcdacMin, pChannelData->pcdacMax,
898185377Ssam				pChannelData->PcdacValues) ;
899185377Ssam
900185377Ssam			for (j = 0; j < pChannelData->numPcdacValues; j++) {
901185377Ssam				pChannelData->PwrValues[j] = (uint16_t)(
902185377Ssam					PWR_STEP * pChannelData->PwrValues[j]);
903185377Ssam				/* Note these values are scaled up. */
904185377Ssam			}
905185377Ssam			pChannelData++;
906185377Ssam		}
907185377Ssam	}
908185377Ssam	return AH_TRUE;
909185377Ssam#undef EEREAD
910185377Ssam}
911185377Ssam
912185377Ssam/*
913185377Ssam * Copy EEPROM Target Power Calbration per rate contents
914185377Ssam * into the allocated space
915185377Ssam */
916185377Ssamstatic HAL_BOOL
917185377SsamreadEepromTargetPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee)
918185377Ssam{
919185377Ssam#define	EEREAD(_off) do {				\
920185377Ssam	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
921185377Ssam		return AH_FALSE;			\
922185377Ssam} while (0)
923185377Ssam	uint16_t eeval, enable24;
924185377Ssam	uint32_t off;
925185377Ssam	int i, mode, nchan;
926185377Ssam
927185377Ssam	enable24 = ee->ee_Bmode || ee->ee_Gmode;
928185377Ssam	for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {
929185377Ssam		TRGT_POWER_INFO *pPowerInfo;
930185377Ssam		uint16_t *pNumTrgtChannels;
931185377Ssam
932185377Ssam		off = ee->ee_version >= AR_EEPROM_VER4_0 ?
933185377Ssam				ee->ee_targetPowersStart - GROUP5_OFFSET :
934185377Ssam		      ee->ee_version >= AR_EEPROM_VER3_3 ?
935185377Ssam				GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2;
936185377Ssam		switch (mode) {
937185377Ssam		case headerInfo11A:
938185377Ssam			off += GROUP5_OFFSET;
939185377Ssam			nchan = NUM_TEST_FREQUENCIES;
940185377Ssam			pPowerInfo = ee->ee_trgtPwr_11a;
941185377Ssam			pNumTrgtChannels = &ee->ee_numTargetPwr_11a;
942185377Ssam			break;
943185377Ssam		case headerInfo11B:
944185377Ssam			if (!enable24)
945185377Ssam				continue;
946185377Ssam			off += GROUP6_OFFSET;
947185377Ssam			nchan = 2;
948185377Ssam			pPowerInfo = ee->ee_trgtPwr_11b;
949185377Ssam			pNumTrgtChannels = &ee->ee_numTargetPwr_11b;
950185377Ssam			break;
951185377Ssam		case headerInfo11G:
952185377Ssam			if (!enable24)
953185377Ssam				continue;
954185377Ssam			off += GROUP7_OFFSET;
955185377Ssam			nchan = 3;
956185377Ssam			pPowerInfo = ee->ee_trgtPwr_11g;
957185377Ssam			pNumTrgtChannels = &ee->ee_numTargetPwr_11g;
958185377Ssam			break;
959185377Ssam		default:
960185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",
961185377Ssam			    __func__, mode);
962185377Ssam			return AH_FALSE;
963185377Ssam		}
964185377Ssam		*pNumTrgtChannels = 0;
965185377Ssam		for (i = 0; i < nchan; i++) {
966185377Ssam			EEREAD(off++);
967185377Ssam			if (ee->ee_version >= AR_EEPROM_VER3_3) {
968185377Ssam				pPowerInfo->testChannel = (eeval >> 8) & 0xff;
969185377Ssam			} else {
970185377Ssam				pPowerInfo->testChannel = (eeval >> 9) & 0x7f;
971185377Ssam			}
972185377Ssam
973185377Ssam			if (pPowerInfo->testChannel != 0) {
974185377Ssam				/* get the channel value and read rest of info */
975185377Ssam				if (mode == headerInfo11A) {
976185377Ssam					pPowerInfo->testChannel = fbin2freq(ee, pPowerInfo->testChannel);
977185377Ssam				} else {
978185377Ssam					pPowerInfo->testChannel = fbin2freq_2p4(ee, pPowerInfo->testChannel);
979185377Ssam				}
980185377Ssam
981185377Ssam				if (ee->ee_version >= AR_EEPROM_VER3_3) {
982185377Ssam					pPowerInfo->twicePwr6_24 = (eeval >> 2) & POWER_MASK;
983185377Ssam					pPowerInfo->twicePwr36   = (eeval << 4) & POWER_MASK;
984185377Ssam				} else {
985185377Ssam					pPowerInfo->twicePwr6_24 = (eeval >> 3) & POWER_MASK;
986185377Ssam					pPowerInfo->twicePwr36   = (eeval << 3) & POWER_MASK;
987185377Ssam				}
988185377Ssam
989185377Ssam				EEREAD(off++);
990185377Ssam				if (ee->ee_version >= AR_EEPROM_VER3_3) {
991185377Ssam					pPowerInfo->twicePwr36 |= (eeval >> 12) & 0xf;
992185377Ssam					pPowerInfo->twicePwr48 = (eeval >> 6) & POWER_MASK;
993185377Ssam					pPowerInfo->twicePwr54 =  eeval & POWER_MASK;
994185377Ssam				} else {
995185377Ssam					pPowerInfo->twicePwr36 |= (eeval >> 13) & 0x7;
996185377Ssam					pPowerInfo->twicePwr48 = (eeval >> 7) & POWER_MASK;
997185377Ssam					pPowerInfo->twicePwr54 = (eeval >> 1) & POWER_MASK;
998185377Ssam				}
999185377Ssam				(*pNumTrgtChannels)++;
1000185377Ssam			}
1001185377Ssam			pPowerInfo++;
1002185377Ssam		}
1003185377Ssam	}
1004185377Ssam	return AH_TRUE;
1005185377Ssam#undef EEREAD
1006185377Ssam}
1007185377Ssam
1008185377Ssam/*
1009185377Ssam * Now copy EEPROM Coformance Testing Limits contents
1010185377Ssam * into the allocated space
1011185377Ssam */
1012185377Ssamstatic HAL_BOOL
1013185377SsamreadEepromCTLInfo(struct ath_hal *ah, HAL_EEPROM *ee)
1014185377Ssam{
1015185377Ssam#define	EEREAD(_off) do {				\
1016185377Ssam	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
1017185377Ssam		return AH_FALSE;			\
1018185377Ssam} while (0)
1019185377Ssam	RD_EDGES_POWER *rep;
1020185377Ssam	uint16_t eeval;
1021185377Ssam	uint32_t off;
1022185377Ssam	int i, j;
1023185377Ssam
1024185377Ssam	rep = ee->ee_rdEdgesPower;
1025185377Ssam
1026185377Ssam	off = GROUP8_OFFSET +
1027185377Ssam		(ee->ee_version >= AR_EEPROM_VER4_0 ?
1028185377Ssam			ee->ee_targetPowersStart - GROUP5_OFFSET :
1029185377Ssam	         ee->ee_version >= AR_EEPROM_VER3_3 ?
1030185377Ssam			GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2);
1031185377Ssam	for (i = 0; i < ee->ee_numCtls; i++) {
1032185377Ssam		if (ee->ee_ctl[i] == 0) {
1033185377Ssam			/* Move offset and edges */
1034185377Ssam			off += (ee->ee_version >= AR_EEPROM_VER3_3 ? 8 : 7);
1035185377Ssam			rep += NUM_EDGES;
1036185377Ssam			continue;
1037185377Ssam		}
1038185377Ssam		if (ee->ee_version >= AR_EEPROM_VER3_3) {
1039185377Ssam			for (j = 0; j < NUM_EDGES; j += 2) {
1040185377Ssam				EEREAD(off++);
1041185377Ssam				rep[j].rdEdge = (eeval >> 8) & FREQ_MASK_3_3;
1042185377Ssam				rep[j+1].rdEdge = eeval & FREQ_MASK_3_3;
1043185377Ssam			}
1044185377Ssam			for (j = 0; j < NUM_EDGES; j += 2) {
1045185377Ssam				EEREAD(off++);
1046185377Ssam				rep[j].twice_rdEdgePower =
1047185377Ssam					(eeval >> 8) & POWER_MASK;
1048185377Ssam				rep[j].flag = (eeval >> 14) & 1;
1049185377Ssam				rep[j+1].twice_rdEdgePower = eeval & POWER_MASK;
1050185377Ssam				rep[j+1].flag = (eeval >> 6) & 1;
1051185377Ssam			}
1052185377Ssam		} else {
1053185377Ssam			EEREAD(off++);
1054185377Ssam			rep[0].rdEdge = (eeval >> 9) & FREQ_MASK;
1055185377Ssam			rep[1].rdEdge = (eeval >> 2) & FREQ_MASK;
1056185377Ssam			rep[2].rdEdge = (eeval << 5) & FREQ_MASK;
1057185377Ssam
1058185377Ssam			EEREAD(off++);
1059185377Ssam			rep[2].rdEdge |= (eeval >> 11) & 0x1f;
1060185377Ssam			rep[3].rdEdge = (eeval >> 4) & FREQ_MASK;
1061185377Ssam			rep[4].rdEdge = (eeval << 3) & FREQ_MASK;
1062185377Ssam
1063185377Ssam			EEREAD(off++);
1064185377Ssam			rep[4].rdEdge |= (eeval >> 13) & 0x7;
1065185377Ssam			rep[5].rdEdge = (eeval >> 6) & FREQ_MASK;
1066185377Ssam			rep[6].rdEdge = (eeval << 1) & FREQ_MASK;
1067185377Ssam
1068185377Ssam			EEREAD(off++);
1069185377Ssam			rep[6].rdEdge |= (eeval >> 15) & 0x1;
1070185377Ssam			rep[7].rdEdge = (eeval >> 8) & FREQ_MASK;
1071185377Ssam
1072185377Ssam			rep[0].twice_rdEdgePower = (eeval >> 2) & POWER_MASK;
1073185377Ssam			rep[1].twice_rdEdgePower = (eeval << 4) & POWER_MASK;
1074185377Ssam
1075185377Ssam			EEREAD(off++);
1076185377Ssam			rep[1].twice_rdEdgePower |= (eeval >> 12) & 0xf;
1077185377Ssam			rep[2].twice_rdEdgePower = (eeval >> 6) & POWER_MASK;
1078185377Ssam			rep[3].twice_rdEdgePower = eeval & POWER_MASK;
1079185377Ssam
1080185377Ssam			EEREAD(off++);
1081185377Ssam			rep[4].twice_rdEdgePower = (eeval >> 10) & POWER_MASK;
1082185377Ssam			rep[5].twice_rdEdgePower = (eeval >> 4) & POWER_MASK;
1083185377Ssam			rep[6].twice_rdEdgePower = (eeval << 2) & POWER_MASK;
1084185377Ssam
1085185377Ssam			EEREAD(off++);
1086185377Ssam			rep[6].twice_rdEdgePower |= (eeval >> 14) & 0x3;
1087185377Ssam			rep[7].twice_rdEdgePower = (eeval >> 8) & POWER_MASK;
1088185377Ssam		}
1089185377Ssam
1090185377Ssam		for (j = 0; j < NUM_EDGES; j++ ) {
1091185377Ssam			if (rep[j].rdEdge != 0 || rep[j].twice_rdEdgePower != 0) {
1092185377Ssam				if ((ee->ee_ctl[i] & CTL_MODE_M) == CTL_11A ||
1093185377Ssam				    (ee->ee_ctl[i] & CTL_MODE_M) == CTL_TURBO) {
1094185377Ssam					rep[j].rdEdge = fbin2freq(ee, rep[j].rdEdge);
1095185377Ssam				} else {
1096185377Ssam					rep[j].rdEdge = fbin2freq_2p4(ee, rep[j].rdEdge);
1097185377Ssam				}
1098185377Ssam			}
1099185377Ssam		}
1100185377Ssam		rep += NUM_EDGES;
1101185377Ssam	}
1102185377Ssam	return AH_TRUE;
1103185377Ssam#undef EEREAD
1104185377Ssam}
1105185377Ssam
1106185377Ssam/*
1107185377Ssam * Read the individual header fields for a Rev 3 EEPROM
1108185377Ssam */
1109185377Ssamstatic HAL_BOOL
1110185377SsamreadHeaderInfo(struct ath_hal *ah, HAL_EEPROM *ee)
1111185377Ssam{
1112185377Ssam#define	EEREAD(_off) do {				\
1113185377Ssam	if (!ath_hal_eepromRead(ah, _off, &eeval))	\
1114185377Ssam		return AH_FALSE;			\
1115185377Ssam} while (0)
1116185377Ssam	static const uint32_t headerOffset3_0[] = {
1117185377Ssam		0x00C2, /* 0 - Mode bits, device type, max turbo power */
1118185377Ssam		0x00C4, /* 1 - 2.4 and 5 antenna gain */
1119185377Ssam		0x00C5, /* 2 - Begin 11A modal section */
1120185377Ssam		0x00D0, /* 3 - Begin 11B modal section */
1121185377Ssam		0x00DA, /* 4 - Begin 11G modal section */
1122185377Ssam		0x00E4  /* 5 - Begin CTL section */
1123185377Ssam	};
1124185377Ssam	static const uint32_t headerOffset3_3[] = {
1125185377Ssam		0x00C2, /* 0 - Mode bits, device type, max turbo power */
1126185377Ssam		0x00C3, /* 1 - 2.4 and 5 antenna gain */
1127185377Ssam		0x00D4, /* 2 - Begin 11A modal section */
1128185377Ssam		0x00F2, /* 3 - Begin 11B modal section */
1129185377Ssam		0x010D, /* 4 - Begin 11G modal section */
1130185377Ssam		0x0128  /* 5 - Begin CTL section */
1131185377Ssam	};
1132185377Ssam
1133185377Ssam	static const uint32_t regCapOffsetPre4_0 = 0x00CF;
1134185377Ssam	static const uint32_t regCapOffsetPost4_0 = 0x00CA;
1135185377Ssam
1136185377Ssam	const uint32_t *header;
1137185377Ssam	uint32_t off;
1138185377Ssam	uint16_t eeval;
1139185377Ssam	int i;
1140185377Ssam
1141185377Ssam	/* initialize cckOfdmGainDelta for < 4.2 eeprom */
1142185377Ssam	ee->ee_cckOfdmGainDelta = CCK_OFDM_GAIN_DELTA;
1143185377Ssam	ee->ee_scaledCh14FilterCckDelta = TENX_CH14_FILTER_CCK_DELTA_INIT;
1144185377Ssam
1145185377Ssam	if (ee->ee_version >= AR_EEPROM_VER3_3) {
1146185377Ssam		header = headerOffset3_3;
1147185377Ssam		ee->ee_numCtls = NUM_CTLS_3_3;
1148185377Ssam	} else {
1149185377Ssam		header = headerOffset3_0;
1150185377Ssam		ee->ee_numCtls = NUM_CTLS;
1151185377Ssam	}
1152185377Ssam	HALASSERT(ee->ee_numCtls <= NUM_CTLS_MAX);
1153185377Ssam
1154185377Ssam	EEREAD(header[0]);
1155185377Ssam	ee->ee_turbo5Disable	= (eeval >> 15) & 0x01;
1156185377Ssam	ee->ee_rfKill		= (eeval >> 14) & 0x01;
1157185377Ssam	ee->ee_deviceType	= (eeval >> 11) & 0x07;
1158185377Ssam	ee->ee_turbo2WMaxPower5	= (eeval >> 4) & 0x7F;
1159185377Ssam	if (ee->ee_version >= AR_EEPROM_VER4_0)
1160185377Ssam		ee->ee_turbo2Disable	= (eeval >> 3) & 0x01;
1161185377Ssam	else
1162185377Ssam		ee->ee_turbo2Disable	= 1;
1163185377Ssam	ee->ee_Gmode		= (eeval >> 2) & 0x01;
1164185377Ssam	ee->ee_Bmode		= (eeval >> 1) & 0x01;
1165185377Ssam	ee->ee_Amode		= (eeval & 0x01);
1166185377Ssam
1167185377Ssam	off = header[1];
1168185377Ssam	EEREAD(off++);
1169185377Ssam	ee->ee_antennaGainMax[0] = (int8_t)((eeval >> 8) & 0xFF);
1170185377Ssam	ee->ee_antennaGainMax[1] = (int8_t)(eeval & 0xFF);
1171185377Ssam	if (ee->ee_version >= AR_EEPROM_VER4_0) {
1172185377Ssam		EEREAD(off++);
1173185377Ssam		ee->ee_eepMap		 = (eeval>>14) & 0x3;
1174185377Ssam		ee->ee_disableXr5	 = (eeval>>13) & 0x1;
1175185377Ssam		ee->ee_disableXr2	 = (eeval>>12) & 0x1;
1176185377Ssam		ee->ee_earStart		 = eeval & 0xfff;
1177185377Ssam
1178185377Ssam		EEREAD(off++);
1179185377Ssam		ee->ee_targetPowersStart = eeval & 0xfff;
1180185377Ssam		ee->ee_exist32kHzCrystal = (eeval>>14) & 0x1;
1181185377Ssam
1182185377Ssam		if (ee->ee_version >= AR_EEPROM_VER5_0) {
1183185377Ssam			off += 2;
1184185377Ssam			EEREAD(off);
1185185377Ssam			ee->ee_eepMap2PowerCalStart = (eeval >> 4) & 0xfff;
1186185377Ssam			/* Properly cal'ed 5.0 devices should be non-zero */
1187185377Ssam		}
1188185377Ssam	}
1189185377Ssam
1190185377Ssam	/* Read the moded sections of the EEPROM header in the order A, B, G */
1191185377Ssam	for (i = headerInfo11A; i <= headerInfo11G; i++) {
1192185377Ssam		/* Set the offset via the index */
1193185377Ssam		off = header[2 + i];
1194185377Ssam
1195185377Ssam		EEREAD(off++);
1196185377Ssam		ee->ee_switchSettling[i] = (eeval >> 8) & 0x7f;
1197185377Ssam		ee->ee_txrxAtten[i] = (eeval >> 2) & 0x3f;
1198185377Ssam		ee->ee_antennaControl[0][i] = (eeval << 4) & 0x3f;
1199185377Ssam
1200185377Ssam		EEREAD(off++);
1201185377Ssam		ee->ee_antennaControl[0][i] |= (eeval >> 12) & 0x0f;
1202185377Ssam		ee->ee_antennaControl[1][i] = (eeval >> 6) & 0x3f;
1203185377Ssam		ee->ee_antennaControl[2][i] = eeval & 0x3f;
1204185377Ssam
1205185377Ssam		EEREAD(off++);
1206185377Ssam		ee->ee_antennaControl[3][i] = (eeval >> 10)  & 0x3f;
1207185377Ssam		ee->ee_antennaControl[4][i] = (eeval >> 4)  & 0x3f;
1208185377Ssam		ee->ee_antennaControl[5][i] = (eeval << 2)  & 0x3f;
1209185377Ssam
1210185377Ssam		EEREAD(off++);
1211185377Ssam		ee->ee_antennaControl[5][i] |= (eeval >> 14)  & 0x03;
1212185377Ssam		ee->ee_antennaControl[6][i] = (eeval >> 8)  & 0x3f;
1213185377Ssam		ee->ee_antennaControl[7][i] = (eeval >> 2)  & 0x3f;
1214185377Ssam		ee->ee_antennaControl[8][i] = (eeval << 4)  & 0x3f;
1215185377Ssam
1216185377Ssam		EEREAD(off++);
1217185377Ssam		ee->ee_antennaControl[8][i] |= (eeval >> 12)  & 0x0f;
1218185377Ssam		ee->ee_antennaControl[9][i] = (eeval >> 6)  & 0x3f;
1219185377Ssam		ee->ee_antennaControl[10][i] = eeval & 0x3f;
1220185377Ssam
1221185377Ssam		EEREAD(off++);
1222185377Ssam		ee->ee_adcDesiredSize[i] = (int8_t)((eeval >> 8)  & 0xff);
1223185377Ssam		switch (i) {
1224185377Ssam		case headerInfo11A:
1225185377Ssam			ee->ee_ob4 = (eeval >> 5)  & 0x07;
1226185377Ssam			ee->ee_db4 = (eeval >> 2)  & 0x07;
1227185377Ssam			ee->ee_ob3 = (eeval << 1)  & 0x07;
1228185377Ssam			break;
1229185377Ssam		case headerInfo11B:
1230185377Ssam			ee->ee_obFor24 = (eeval >> 4)  & 0x07;
1231185377Ssam			ee->ee_dbFor24 = eeval & 0x07;
1232185377Ssam			break;
1233185377Ssam		case headerInfo11G:
1234185377Ssam			ee->ee_obFor24g = (eeval >> 4)  & 0x07;
1235185377Ssam			ee->ee_dbFor24g = eeval & 0x07;
1236185377Ssam			break;
1237185377Ssam		}
1238185377Ssam
1239185377Ssam		if (i == headerInfo11A) {
1240185377Ssam			EEREAD(off++);
1241185377Ssam			ee->ee_ob3 |= (eeval >> 15)  & 0x01;
1242185377Ssam			ee->ee_db3 = (eeval >> 12)  & 0x07;
1243185377Ssam			ee->ee_ob2 = (eeval >> 9)  & 0x07;
1244185377Ssam			ee->ee_db2 = (eeval >> 6)  & 0x07;
1245185377Ssam			ee->ee_ob1 = (eeval >> 3)  & 0x07;
1246185377Ssam			ee->ee_db1 = eeval & 0x07;
1247185377Ssam		}
1248185377Ssam
1249185377Ssam		EEREAD(off++);
1250185377Ssam		ee->ee_txEndToXLNAOn[i] = (eeval >> 8)  & 0xff;
1251185377Ssam		ee->ee_thresh62[i] = eeval & 0xff;
1252185377Ssam
1253185377Ssam		EEREAD(off++);
1254185377Ssam		ee->ee_txEndToXPAOff[i] = (eeval >> 8)  & 0xff;
1255185377Ssam		ee->ee_txFrameToXPAOn[i] = eeval  & 0xff;
1256185377Ssam
1257185377Ssam		EEREAD(off++);
1258185377Ssam		ee->ee_pgaDesiredSize[i] = (int8_t)((eeval >> 8)  & 0xff);
1259185377Ssam		ee->ee_noiseFloorThresh[i] = eeval  & 0xff;
1260185377Ssam		if (ee->ee_noiseFloorThresh[i] & 0x80) {
1261185377Ssam			ee->ee_noiseFloorThresh[i] = 0 -
1262185377Ssam				((ee->ee_noiseFloorThresh[i] ^ 0xff) + 1);
1263185377Ssam		}
1264185377Ssam
1265185377Ssam		EEREAD(off++);
1266185377Ssam		ee->ee_xlnaGain[i] = (eeval >> 5)  & 0xff;
1267185377Ssam		ee->ee_xgain[i] = (eeval >> 1)  & 0x0f;
1268185377Ssam		ee->ee_xpd[i] = eeval  & 0x01;
1269185377Ssam		if (ee->ee_version >= AR_EEPROM_VER4_0) {
1270185377Ssam			switch (i) {
1271185377Ssam			case headerInfo11A:
1272185377Ssam				ee->ee_fixedBias5 = (eeval >> 13) & 0x1;
1273185377Ssam				break;
1274185377Ssam			case headerInfo11G:
1275185377Ssam				ee->ee_fixedBias2 = (eeval >> 13) & 0x1;
1276185377Ssam				break;
1277185377Ssam			}
1278185377Ssam		}
1279185377Ssam
1280185377Ssam		if (ee->ee_version >= AR_EEPROM_VER3_3) {
1281185377Ssam			EEREAD(off++);
1282185377Ssam			ee->ee_falseDetectBackoff[i] = (eeval >> 6) & 0x7F;
1283185377Ssam			switch (i) {
1284185377Ssam			case headerInfo11B:
1285185377Ssam				ee->ee_ob2GHz[0] = eeval & 0x7;
1286185377Ssam				ee->ee_db2GHz[0] = (eeval >> 3) & 0x7;
1287185377Ssam				break;
1288185377Ssam			case headerInfo11G:
1289185377Ssam				ee->ee_ob2GHz[1] = eeval & 0x7;
1290185377Ssam				ee->ee_db2GHz[1] = (eeval >> 3) & 0x7;
1291185377Ssam				break;
1292185377Ssam			case headerInfo11A:
1293185377Ssam				ee->ee_xrTargetPower5 = eeval & 0x3f;
1294185377Ssam				break;
1295185377Ssam			}
1296185377Ssam		}
1297185377Ssam		if (ee->ee_version >= AR_EEPROM_VER3_4) {
1298185377Ssam			ee->ee_gainI[i] = (eeval >> 13) & 0x07;
1299185377Ssam
1300185377Ssam			EEREAD(off++);
1301185377Ssam			ee->ee_gainI[i] |= (eeval << 3) & 0x38;
1302185377Ssam			if (i == headerInfo11G) {
1303185377Ssam				ee->ee_cckOfdmPwrDelta = (eeval >> 3) & 0xFF;
1304185377Ssam				if (ee->ee_version >= AR_EEPROM_VER4_6)
1305185377Ssam					ee->ee_scaledCh14FilterCckDelta =
1306185377Ssam						(eeval >> 11) & 0x1f;
1307185377Ssam			}
1308185377Ssam			if (i == headerInfo11A &&
1309185377Ssam			    ee->ee_version >= AR_EEPROM_VER4_0) {
1310185377Ssam				ee->ee_iqCalI[0] = (eeval >> 8 ) & 0x3f;
1311185377Ssam				ee->ee_iqCalQ[0] = (eeval >> 3 ) & 0x1f;
1312185377Ssam			}
1313185377Ssam		} else {
1314185377Ssam			ee->ee_gainI[i] = 10;
1315185377Ssam			ee->ee_cckOfdmPwrDelta = TENX_OFDM_CCK_DELTA_INIT;
1316185377Ssam		}
1317185377Ssam		if (ee->ee_version >= AR_EEPROM_VER4_0) {
1318185377Ssam			switch (i) {
1319185377Ssam			case headerInfo11B:
1320185377Ssam				EEREAD(off++);
1321185377Ssam				ee->ee_calPier11b[0] =
1322185377Ssam					fbin2freq_2p4(ee, eeval&0xff);
1323185377Ssam				ee->ee_calPier11b[1] =
1324185377Ssam					fbin2freq_2p4(ee, (eeval >> 8)&0xff);
1325185377Ssam				EEREAD(off++);
1326185377Ssam				ee->ee_calPier11b[2] =
1327185377Ssam					fbin2freq_2p4(ee, eeval&0xff);
1328185377Ssam				if (ee->ee_version >= AR_EEPROM_VER4_1)
1329185377Ssam					ee->ee_rxtxMargin[headerInfo11B] =
1330185377Ssam						(eeval >> 8) & 0x3f;
1331185377Ssam				break;
1332185377Ssam			case headerInfo11G:
1333185377Ssam				EEREAD(off++);
1334185377Ssam				ee->ee_calPier11g[0] =
1335185377Ssam					fbin2freq_2p4(ee, eeval & 0xff);
1336185377Ssam				ee->ee_calPier11g[1] =
1337185377Ssam					fbin2freq_2p4(ee, (eeval >> 8) & 0xff);
1338185377Ssam
1339185377Ssam				EEREAD(off++);
1340185377Ssam				ee->ee_turbo2WMaxPower2 = eeval & 0x7F;
1341185377Ssam				ee->ee_xrTargetPower2 = (eeval >> 7) & 0x3f;
1342185377Ssam
1343185377Ssam				EEREAD(off++);
1344185377Ssam				ee->ee_calPier11g[2] =
1345185377Ssam					fbin2freq_2p4(ee, eeval & 0xff);
1346185377Ssam				if (ee->ee_version >= AR_EEPROM_VER4_1)
1347185377Ssam					 ee->ee_rxtxMargin[headerInfo11G] =
1348185377Ssam						(eeval >> 8) & 0x3f;
1349185377Ssam
1350185377Ssam				EEREAD(off++);
1351185377Ssam				ee->ee_iqCalI[1] = (eeval >> 5) & 0x3F;
1352185377Ssam				ee->ee_iqCalQ[1] = eeval & 0x1F;
1353185377Ssam
1354185377Ssam				if (ee->ee_version >= AR_EEPROM_VER4_2) {
1355185377Ssam					EEREAD(off++);
1356185377Ssam					ee->ee_cckOfdmGainDelta =
1357185377Ssam						(uint8_t)(eeval & 0xFF);
1358185377Ssam					if (ee->ee_version >= AR_EEPROM_VER5_0) {
1359185377Ssam						ee->ee_switchSettlingTurbo[1] =
1360185377Ssam							(eeval >> 8) & 0x7f;
1361185377Ssam						ee->ee_txrxAttenTurbo[1] =
1362185377Ssam							(eeval >> 15) & 0x1;
1363185377Ssam						EEREAD(off++);
1364185377Ssam						ee->ee_txrxAttenTurbo[1] |=
1365185377Ssam							(eeval & 0x1F) << 1;
1366185377Ssam						ee->ee_rxtxMarginTurbo[1] =
1367185377Ssam							(eeval >> 5) & 0x3F;
1368185377Ssam						ee->ee_adcDesiredSizeTurbo[1] =
1369185377Ssam							(eeval >> 11) & 0x1F;
1370185377Ssam						EEREAD(off++);
1371185377Ssam						ee->ee_adcDesiredSizeTurbo[1] |=
1372185377Ssam							(eeval & 0x7) << 5;
1373185377Ssam						ee->ee_pgaDesiredSizeTurbo[1] =
1374185377Ssam							(eeval >> 3) & 0xFF;
1375185377Ssam					}
1376185377Ssam				}
1377185377Ssam				break;
1378185377Ssam			case headerInfo11A:
1379185377Ssam				if (ee->ee_version >= AR_EEPROM_VER4_1) {
1380185377Ssam					EEREAD(off++);
1381185377Ssam					ee->ee_rxtxMargin[headerInfo11A] =
1382185377Ssam						eeval & 0x3f;
1383185377Ssam					if (ee->ee_version >= AR_EEPROM_VER5_0) {
1384185377Ssam						ee->ee_switchSettlingTurbo[0] =
1385185377Ssam							(eeval >> 6) & 0x7f;
1386185377Ssam						ee->ee_txrxAttenTurbo[0] =
1387185377Ssam							(eeval >> 13) & 0x7;
1388185377Ssam						EEREAD(off++);
1389185377Ssam						ee->ee_txrxAttenTurbo[0] |=
1390185377Ssam							(eeval & 0x7) << 3;
1391185377Ssam						ee->ee_rxtxMarginTurbo[0] =
1392185377Ssam							(eeval >> 3) & 0x3F;
1393185377Ssam						ee->ee_adcDesiredSizeTurbo[0] =
1394185377Ssam							(eeval >> 9) & 0x7F;
1395185377Ssam						EEREAD(off++);
1396185377Ssam						ee->ee_adcDesiredSizeTurbo[0] |=
1397185377Ssam							(eeval & 0x1) << 7;
1398185377Ssam						ee->ee_pgaDesiredSizeTurbo[0] =
1399185377Ssam							(eeval >> 1) & 0xFF;
1400185377Ssam					}
1401185377Ssam				}
1402185377Ssam				break;
1403185377Ssam			}
1404185377Ssam		}
1405185377Ssam	}
1406185377Ssam	if (ee->ee_version < AR_EEPROM_VER3_3) {
1407185377Ssam		/* Version 3.1+ specific parameters */
1408185377Ssam		EEREAD(0xec);
1409185377Ssam		ee->ee_ob2GHz[0] = eeval & 0x7;
1410185377Ssam		ee->ee_db2GHz[0] = (eeval >> 3) & 0x7;
1411185377Ssam
1412185377Ssam		EEREAD(0xed);
1413185377Ssam		ee->ee_ob2GHz[1] = eeval & 0x7;
1414185377Ssam		ee->ee_db2GHz[1] = (eeval >> 3) & 0x7;
1415185377Ssam	}
1416185377Ssam
1417185377Ssam	/* Initialize corner cal (thermal tx gain adjust parameters) */
1418185377Ssam	ee->ee_cornerCal.clip = 4;
1419185377Ssam	ee->ee_cornerCal.pd90 = 1;
1420185377Ssam	ee->ee_cornerCal.pd84 = 1;
1421185377Ssam	ee->ee_cornerCal.gSel = 0;
1422185377Ssam
1423185377Ssam	/*
1424185377Ssam	* Read the conformance test limit identifiers
1425185377Ssam	* These are used to match regulatory domain testing needs with
1426185377Ssam	* the RD-specific tests that have been calibrated in the EEPROM.
1427185377Ssam	*/
1428185377Ssam	off = header[5];
1429185377Ssam	for (i = 0; i < ee->ee_numCtls; i += 2) {
1430185377Ssam		EEREAD(off++);
1431185377Ssam		ee->ee_ctl[i] = (eeval >> 8) & 0xff;
1432185377Ssam		ee->ee_ctl[i+1] = eeval & 0xff;
1433185377Ssam	}
1434185377Ssam
1435185377Ssam	if (ee->ee_version < AR_EEPROM_VER5_3) {
1436185377Ssam		/* XXX only for 5413? */
1437185377Ssam		ee->ee_spurChans[0][1] = AR_SPUR_5413_1;
1438185377Ssam		ee->ee_spurChans[1][1] = AR_SPUR_5413_2;
1439185377Ssam		ee->ee_spurChans[2][1] = AR_NO_SPUR;
1440185377Ssam		ee->ee_spurChans[0][0] = AR_NO_SPUR;
1441185377Ssam	} else {
1442185377Ssam		/* Read spur mitigation data */
1443185377Ssam		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
1444185377Ssam			EEREAD(off);
1445185377Ssam			ee->ee_spurChans[i][0] = eeval;
1446185377Ssam			EEREAD(off+AR_EEPROM_MODAL_SPURS);
1447185377Ssam			ee->ee_spurChans[i][1] = eeval;
1448185377Ssam			off++;
1449185377Ssam		}
1450185377Ssam	}
1451185377Ssam
1452185377Ssam	/* for recent changes to NF scale */
1453185377Ssam	if (ee->ee_version <= AR_EEPROM_VER3_2) {
1454185377Ssam		ee->ee_noiseFloorThresh[headerInfo11A] = -54;
1455185377Ssam		ee->ee_noiseFloorThresh[headerInfo11B] = -1;
1456185377Ssam		ee->ee_noiseFloorThresh[headerInfo11G] = -1;
1457185377Ssam	}
1458185377Ssam	/* to override thresh62 for better 2.4 and 5 operation */
1459185377Ssam	if (ee->ee_version <= AR_EEPROM_VER3_2) {
1460185377Ssam		ee->ee_thresh62[headerInfo11A] = 15;	/* 11A */
1461185377Ssam		ee->ee_thresh62[headerInfo11B] = 28;	/* 11B */
1462185377Ssam		ee->ee_thresh62[headerInfo11G] = 28;	/* 11G */
1463185377Ssam	}
1464185377Ssam
1465185377Ssam	/* Check for regulatory capabilities */
1466185377Ssam	if (ee->ee_version >= AR_EEPROM_VER4_0) {
1467185377Ssam		EEREAD(regCapOffsetPost4_0);
1468185377Ssam	} else {
1469185377Ssam		EEREAD(regCapOffsetPre4_0);
1470185377Ssam	}
1471185377Ssam
1472185377Ssam	ee->ee_regCap = eeval;
1473185377Ssam
1474185377Ssam	if (ee->ee_Amode == 0) {
1475185377Ssam		/* Check for valid Amode in upgraded h/w */
1476185377Ssam		if (ee->ee_version >= AR_EEPROM_VER4_0) {
1477185377Ssam			ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A)?1:0;
1478185377Ssam		} else {
1479185377Ssam			ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0)?1:0;
1480185377Ssam		}
1481185377Ssam	}
1482185377Ssam
1483185377Ssam	if (ee->ee_version >= AR_EEPROM_VER5_1)
1484185377Ssam		EEREAD(AR_EEPROM_CAPABILITIES_OFFSET);
1485185377Ssam	else
1486185377Ssam		eeval = 0;
1487185377Ssam	ee->ee_opCap = eeval;
1488185377Ssam
1489185377Ssam	EEREAD(AR_EEPROM_REG_DOMAIN);
1490185377Ssam	ee->ee_regdomain = eeval;
1491185377Ssam
1492185377Ssam	return AH_TRUE;
1493185377Ssam#undef EEREAD
1494185377Ssam}
1495185377Ssam
1496185377Ssam/*
1497185377Ssam * Now verify and copy EEPROM contents into the allocated space
1498185377Ssam */
1499185377Ssamstatic HAL_BOOL
1500185377SsamlegacyEepromReadContents(struct ath_hal *ah, HAL_EEPROM *ee)
1501185377Ssam{
1502185377Ssam	/* Read the header information here */
1503185377Ssam	if (!readHeaderInfo(ah, ee))
1504185377Ssam		return AH_FALSE;
1505185377Ssam#if 0
1506185377Ssam	/* Require 5112 devices to have EEPROM 4.0 EEP_MAP set */
1507185377Ssam	if (IS_5112(ah) && !ee->ee_eepMap) {
1508185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
1509185377Ssam		    "%s: 5112 devices must have EEPROM 4.0 with the "
1510185377Ssam		    "EEP_MAP set\n", __func__);
1511185377Ssam		return AH_FALSE;
1512185377Ssam	}
1513185377Ssam#endif
1514185377Ssam	/*
1515185377Ssam	 * Group 1: frequency pier locations readback
1516185377Ssam	 * check that the structure has been populated
1517185377Ssam	 * with enough space to hold the channels
1518185377Ssam	 *
1519185377Ssam	 * NOTE: Group 1 contains the 5 GHz channel numbers
1520185377Ssam	 *	 that have dBm->pcdac calibrated information.
1521185377Ssam	 */
1522185377Ssam	if (!readEepromFreqPierInfo(ah, ee))
1523185377Ssam		return AH_FALSE;
1524185377Ssam
1525185377Ssam	/*
1526185377Ssam	 * Group 2:  readback data for all frequency piers
1527185377Ssam	 *
1528185377Ssam	 * NOTE: Group 2 contains the raw power calibration
1529185377Ssam	 *	 information for each of the channels that we
1530185377Ssam	 *	 recorded above.
1531185377Ssam	 */
1532185377Ssam	if (!readEepromRawPowerCalInfo(ah, ee))
1533185377Ssam		return AH_FALSE;
1534185377Ssam
1535185377Ssam	/*
1536185377Ssam	 * Group 5: target power values per rate
1537185377Ssam	 *
1538185377Ssam	 * NOTE: Group 5 contains the recorded maximum power
1539185377Ssam	 *	 in dB that can be attained for the given rate.
1540185377Ssam	 */
1541185377Ssam	/* Read the power per rate info for test channels */
1542185377Ssam	if (!readEepromTargetPowerCalInfo(ah, ee))
1543185377Ssam		return AH_FALSE;
1544185377Ssam
1545185377Ssam	/*
1546185377Ssam	 * Group 8: Conformance Test Limits information
1547185377Ssam	 *
1548185377Ssam	 * NOTE: Group 8 contains the values to limit the
1549185377Ssam	 *	 maximum transmit power value based on any
1550185377Ssam	 *	 band edge violations.
1551185377Ssam	 */
1552185377Ssam	/* Read the RD edge power limits */
1553185377Ssam	return readEepromCTLInfo(ah, ee);
1554185377Ssam}
1555185377Ssam
1556185377Ssamstatic HAL_STATUS
1557185377SsamlegacyEepromGet(struct ath_hal *ah, int param, void *val)
1558185377Ssam{
1559185377Ssam	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1560185377Ssam	uint8_t *macaddr;
1561185377Ssam	uint16_t eeval;
1562185377Ssam	uint32_t sum;
1563185377Ssam	int i;
1564185377Ssam
1565185377Ssam	switch (param) {
1566185377Ssam	case AR_EEP_OPCAP:
1567185377Ssam		*(uint16_t *) val = ee->ee_opCap;
1568185377Ssam		return HAL_OK;
1569185377Ssam	case AR_EEP_REGDMN_0:
1570185377Ssam		*(uint16_t *) val = ee->ee_regdomain;
1571185377Ssam		return HAL_OK;
1572185377Ssam	case AR_EEP_RFSILENT:
1573185377Ssam		if (!ath_hal_eepromRead(ah, AR_EEPROM_RFSILENT, &eeval))
1574185377Ssam			return HAL_EEREAD;
1575185377Ssam		*(uint16_t *) val = eeval;
1576185377Ssam		return HAL_OK;
1577185377Ssam	case AR_EEP_MACADDR:
1578185377Ssam		sum = 0;
1579185377Ssam		macaddr = val;
1580185377Ssam		for (i = 0; i < 3; i++) {
1581185377Ssam			if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(2-i), &eeval)) {
1582185377Ssam				HALDEBUG(ah, HAL_DEBUG_ANY,
1583185377Ssam				    "%s: cannot read EEPROM location %u\n",
1584185377Ssam				    __func__, i);
1585185377Ssam				return HAL_EEREAD;
1586185377Ssam			}
1587185377Ssam			sum += eeval;
1588185377Ssam			macaddr[2*i] = eeval >> 8;
1589185377Ssam			macaddr[2*i + 1] = eeval & 0xff;
1590185377Ssam		}
1591185377Ssam		if (sum == 0 || sum == 0xffff*3) {
1592185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY,
1593185377Ssam			    "%s: mac address read failed: %s\n", __func__,
1594185377Ssam			    ath_hal_ether_sprintf(macaddr));
1595185377Ssam			return HAL_EEBADMAC;
1596185377Ssam		}
1597185377Ssam		return HAL_OK;
1598185377Ssam	case AR_EEP_RFKILL:
1599185377Ssam		HALASSERT(val == AH_NULL);
1600185377Ssam		return ee->ee_rfKill ? HAL_OK : HAL_EIO;
1601185377Ssam	case AR_EEP_AMODE:
1602185377Ssam		HALASSERT(val == AH_NULL);
1603185377Ssam		return ee->ee_Amode ? HAL_OK : HAL_EIO;
1604185377Ssam	case AR_EEP_BMODE:
1605185377Ssam		HALASSERT(val == AH_NULL);
1606185377Ssam		return ee->ee_Bmode ? HAL_OK : HAL_EIO;
1607185377Ssam	case AR_EEP_GMODE:
1608185377Ssam		HALASSERT(val == AH_NULL);
1609185377Ssam		return ee->ee_Gmode ? HAL_OK : HAL_EIO;
1610185377Ssam	case AR_EEP_TURBO5DISABLE:
1611185377Ssam		HALASSERT(val == AH_NULL);
1612185377Ssam		return ee->ee_turbo5Disable ? HAL_OK : HAL_EIO;
1613185377Ssam	case AR_EEP_TURBO2DISABLE:
1614185377Ssam		HALASSERT(val == AH_NULL);
1615185377Ssam		return ee->ee_turbo2Disable ? HAL_OK : HAL_EIO;
1616185377Ssam	case AR_EEP_ISTALON:		/* Talon detect */
1617185377Ssam		HALASSERT(val == AH_NULL);
1618185377Ssam		return (ee->ee_version >= AR_EEPROM_VER5_4 &&
1619185377Ssam		    ath_hal_eepromRead(ah, 0x0b, &eeval) && eeval == 1) ?
1620185377Ssam			HAL_OK : HAL_EIO;
1621185377Ssam	case AR_EEP_32KHZCRYSTAL:
1622185377Ssam		HALASSERT(val == AH_NULL);
1623185377Ssam		return ee->ee_exist32kHzCrystal ? HAL_OK : HAL_EIO;
1624185377Ssam	case AR_EEP_COMPRESS:
1625185377Ssam		HALASSERT(val == AH_NULL);
1626185377Ssam		return (ee->ee_opCap & AR_EEPROM_EEPCAP_COMPRESS_DIS) == 0 ?
1627185377Ssam		    HAL_OK : HAL_EIO;
1628185377Ssam	case AR_EEP_FASTFRAME:
1629185377Ssam		HALASSERT(val == AH_NULL);
1630185377Ssam		return (ee->ee_opCap & AR_EEPROM_EEPCAP_FASTFRAME_DIS) == 0 ?
1631185377Ssam		    HAL_OK : HAL_EIO;
1632185377Ssam	case AR_EEP_AES:
1633185377Ssam		HALASSERT(val == AH_NULL);
1634185377Ssam		return (ee->ee_opCap & AR_EEPROM_EEPCAP_AES_DIS) == 0 ?
1635185377Ssam		    HAL_OK : HAL_EIO;
1636185377Ssam	case AR_EEP_BURST:
1637185377Ssam		HALASSERT(val == AH_NULL);
1638185377Ssam		return (ee->ee_opCap & AR_EEPROM_EEPCAP_BURST_DIS) == 0 ?
1639185377Ssam		    HAL_OK : HAL_EIO;
1640185377Ssam	case AR_EEP_MAXQCU:
1641185377Ssam		if (ee->ee_opCap & AR_EEPROM_EEPCAP_MAXQCU) {
1642185377Ssam			*(uint16_t *) val =
1643185377Ssam			    MS(ee->ee_opCap, AR_EEPROM_EEPCAP_MAXQCU);
1644185377Ssam			return HAL_OK;
1645185377Ssam		} else
1646185377Ssam			return HAL_EIO;
1647185377Ssam	case AR_EEP_KCENTRIES:
1648185377Ssam		if (ee->ee_opCap & AR_EEPROM_EEPCAP_KC_ENTRIES) {
1649185377Ssam			*(uint16_t *) val =
1650185377Ssam			    1 << MS(ee->ee_opCap, AR_EEPROM_EEPCAP_KC_ENTRIES);
1651185377Ssam			return HAL_OK;
1652185377Ssam		} else
1653185377Ssam			return HAL_EIO;
1654185377Ssam	case AR_EEP_ANTGAINMAX_5:
1655185377Ssam		*(int8_t *) val = ee->ee_antennaGainMax[0];
1656185377Ssam		return HAL_OK;
1657185377Ssam	case AR_EEP_ANTGAINMAX_2:
1658185377Ssam		*(int8_t *) val = ee->ee_antennaGainMax[1];
1659185377Ssam		return HAL_OK;
1660185377Ssam	case AR_EEP_WRITEPROTECT:
1661185377Ssam		HALASSERT(val == AH_NULL);
1662185377Ssam		return (ee->ee_protect & AR_EEPROM_PROTECT_WP_128_191) ?
1663185377Ssam		    HAL_OK : HAL_EIO;
1664185377Ssam	}
1665185377Ssam	return HAL_EINVAL;
1666185377Ssam}
1667185377Ssam
1668221896Sadrianstatic HAL_STATUS
1669185377SsamlegacyEepromSet(struct ath_hal *ah, int param, int v)
1670185377Ssam{
1671185377Ssam	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1672185377Ssam
1673185377Ssam	switch (param) {
1674185377Ssam	case AR_EEP_AMODE:
1675185377Ssam		ee->ee_Amode = v;
1676185377Ssam		return HAL_OK;
1677185377Ssam	case AR_EEP_BMODE:
1678185377Ssam		ee->ee_Bmode = v;
1679185377Ssam		return HAL_OK;
1680185377Ssam	case AR_EEP_GMODE:
1681185377Ssam		ee->ee_Gmode = v;
1682185377Ssam		return HAL_OK;
1683185377Ssam	case AR_EEP_TURBO5DISABLE:
1684185377Ssam		ee->ee_turbo5Disable = v;
1685185377Ssam		return HAL_OK;
1686185377Ssam	case AR_EEP_TURBO2DISABLE:
1687185377Ssam		ee->ee_turbo2Disable = v;
1688185377Ssam		return HAL_OK;
1689185377Ssam	case AR_EEP_COMPRESS:
1690185377Ssam		if (v)
1691185377Ssam			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_COMPRESS_DIS;
1692185377Ssam		else
1693185377Ssam			ee->ee_opCap |= AR_EEPROM_EEPCAP_COMPRESS_DIS;
1694185377Ssam		return HAL_OK;
1695185377Ssam	case AR_EEP_FASTFRAME:
1696185377Ssam		if (v)
1697185377Ssam			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_FASTFRAME_DIS;
1698185377Ssam		else
1699185377Ssam			ee->ee_opCap |= AR_EEPROM_EEPCAP_FASTFRAME_DIS;
1700185377Ssam		return HAL_OK;
1701185377Ssam	case AR_EEP_AES:
1702185377Ssam		if (v)
1703185377Ssam			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_AES_DIS;
1704185377Ssam		else
1705185377Ssam			ee->ee_opCap |= AR_EEPROM_EEPCAP_AES_DIS;
1706185377Ssam		return HAL_OK;
1707185377Ssam	case AR_EEP_BURST:
1708185377Ssam		if (v)
1709185377Ssam			ee->ee_opCap &= ~AR_EEPROM_EEPCAP_BURST_DIS;
1710185377Ssam		else
1711185377Ssam			ee->ee_opCap |= AR_EEPROM_EEPCAP_BURST_DIS;
1712185377Ssam		return HAL_OK;
1713185377Ssam	}
1714185377Ssam	return HAL_EINVAL;
1715185377Ssam}
1716185377Ssam
1717185377Ssamstatic HAL_BOOL
1718185377SsamlegacyEepromDiag(struct ath_hal *ah, int request,
1719185377Ssam     const void *args, uint32_t argsize, void **result, uint32_t *resultsize)
1720185377Ssam{
1721185377Ssam	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1722185377Ssam	const EEPROM_POWER_EXPN_5112 *pe;
1723185377Ssam
1724185377Ssam	switch (request) {
1725185377Ssam	case HAL_DIAG_EEPROM:
1726185377Ssam		*result = ee;
1727185377Ssam		*resultsize = sizeof(*ee);
1728185377Ssam		return AH_TRUE;
1729185377Ssam	case HAL_DIAG_EEPROM_EXP_11A:
1730185377Ssam	case HAL_DIAG_EEPROM_EXP_11B:
1731185377Ssam	case HAL_DIAG_EEPROM_EXP_11G:
1732185377Ssam		pe = &ee->ee_modePowerArray5112[
1733185377Ssam		    request - HAL_DIAG_EEPROM_EXP_11A];
1734185377Ssam		*result = pe->pChannels;
1735185377Ssam		*resultsize = (*result == AH_NULL) ? 0 :
1736185377Ssam			roundup(sizeof(uint16_t) * pe->numChannels,
1737185377Ssam				sizeof(uint32_t)) +
1738185377Ssam			sizeof(EXPN_DATA_PER_CHANNEL_5112) * pe->numChannels;
1739185377Ssam		return AH_TRUE;
1740185377Ssam	}
1741185377Ssam	return AH_FALSE;
1742185377Ssam}
1743185377Ssam
1744185377Ssamstatic uint16_t
1745185377SsamlegacyEepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz)
1746185377Ssam{
1747185377Ssam	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1748185377Ssam
1749185377Ssam	HALASSERT(0 <= ix && ix < AR_EEPROM_MODAL_SPURS);
1750185377Ssam	return ee->ee_spurChans[ix][is2GHz];
1751185377Ssam}
1752185377Ssam
1753185377Ssam/*
1754185377Ssam * Reclaim any EEPROM-related storage.
1755185377Ssam */
1756185377Ssamstatic void
1757185377SsamlegacyEepromDetach(struct ath_hal *ah)
1758185377Ssam{
1759185377Ssam	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1760185377Ssam
1761185377Ssam        if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1)
1762196934Ssam		freeEepromRawPowerCalInfo5112(ah, ee);
1763185377Ssam	ath_hal_free(ee);
1764185377Ssam	AH_PRIVATE(ah)->ah_eeprom = AH_NULL;
1765185377Ssam}
1766185377Ssam
1767185377Ssam/*
1768185380Ssam * These are not valid 2.4 channels, either we change 'em
1769185380Ssam * or we need to change the coding to accept them.
1770185377Ssam */
1771185377Ssamstatic const uint16_t channels11b[] = { 2412, 2447, 2484 };
1772185377Ssamstatic const uint16_t channels11g[] = { 2312, 2412, 2484 };
1773185377Ssam
1774185377SsamHAL_STATUS
1775185377Ssamath_hal_legacyEepromAttach(struct ath_hal *ah)
1776185377Ssam{
1777185377Ssam	HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
1778185377Ssam	uint32_t sum, eepMax;
1779185377Ssam	uint16_t eeversion, eeprotect, eeval;
1780185377Ssam	u_int i;
1781185377Ssam
1782185377Ssam	HALASSERT(ee == AH_NULL);
1783185377Ssam
1784185377Ssam	if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &eeversion)) {
1785185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
1786185377Ssam		    "%s: unable to read EEPROM version\n", __func__);
1787185377Ssam		return HAL_EEREAD;
1788185377Ssam	}
1789185377Ssam	if (eeversion < AR_EEPROM_VER3) {
1790185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM version "
1791185377Ssam		    "%u (0x%x) found\n", __func__, eeversion, eeversion);
1792185377Ssam		return HAL_EEVERSION;
1793185377Ssam	}
1794185377Ssam
1795185377Ssam	if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &eeprotect)) {
1796185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read EEPROM protection "
1797185377Ssam		    "bits; read locked?\n", __func__);
1798185377Ssam		return HAL_EEREAD;
1799185377Ssam	}
1800185377Ssam	HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", eeprotect);
1801185377Ssam	/* XXX check proper access before continuing */
1802185377Ssam
1803185377Ssam	/*
1804185377Ssam	 * Read the Atheros EEPROM entries and calculate the checksum.
1805185377Ssam	 */
1806185377Ssam	if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_UPPER, &eeval)) {
1807185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
1808185377Ssam		    "%s: cannot read EEPROM upper size\n" , __func__);
1809185377Ssam		return HAL_EEREAD;
1810185377Ssam	}
1811185377Ssam	if (eeval != 0)	{
1812185377Ssam		eepMax = (eeval & AR_EEPROM_SIZE_UPPER_MASK) <<
1813185377Ssam			AR_EEPROM_SIZE_ENDLOC_SHIFT;
1814185377Ssam		if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_LOWER, &eeval)) {
1815185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY,
1816185377Ssam			    "%s: cannot read EEPROM lower size\n" , __func__);
1817185377Ssam			return HAL_EEREAD;
1818185377Ssam		}
1819185377Ssam		eepMax = (eepMax | eeval) - AR_EEPROM_ATHEROS_BASE;
1820185377Ssam	} else
1821185377Ssam		eepMax = AR_EEPROM_ATHEROS_MAX;
1822185377Ssam	sum = 0;
1823185377Ssam	for (i = 0; i < eepMax; i++) {
1824185377Ssam		if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &eeval)) {
1825185377Ssam			return HAL_EEREAD;
1826185377Ssam		}
1827185377Ssam		sum ^= eeval;
1828185377Ssam	}
1829185377Ssam	if (sum != 0xffff) {
1830185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n",
1831185377Ssam		    __func__, sum);
1832185377Ssam		return HAL_EEBADSUM;
1833185377Ssam	}
1834185377Ssam
1835185377Ssam	ee = ath_hal_malloc(sizeof(HAL_EEPROM));
1836185377Ssam	if (ee == AH_NULL) {
1837185377Ssam		/* XXX message */
1838185377Ssam		return HAL_ENOMEM;
1839185377Ssam	}
1840185377Ssam
1841185377Ssam	ee->ee_protect = eeprotect;
1842185377Ssam	ee->ee_version = eeversion;
1843185377Ssam
1844185377Ssam	ee->ee_numChannels11a = NUM_11A_EEPROM_CHANNELS;
1845185377Ssam	ee->ee_numChannels2_4 = NUM_2_4_EEPROM_CHANNELS;
1846185377Ssam
1847185377Ssam	for (i = 0; i < NUM_11A_EEPROM_CHANNELS; i ++)
1848185377Ssam		ee->ee_dataPerChannel11a[i].numPcdacValues = NUM_PCDAC_VALUES;
1849185377Ssam
1850185377Ssam	/* the channel list for 2.4 is fixed, fill this in here */
1851185377Ssam	for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++) {
1852185377Ssam		ee->ee_channels11b[i] = channels11b[i];
1853185377Ssam		/* XXX 5211 requires a hack though we don't support 11g */
1854185377Ssam		if (ah->ah_magic == 0x19570405)
1855185377Ssam			ee->ee_channels11g[i] = channels11b[i];
1856185377Ssam		else
1857185377Ssam			ee->ee_channels11g[i] = channels11g[i];
1858185377Ssam		ee->ee_dataPerChannel11b[i].numPcdacValues = NUM_PCDAC_VALUES;
1859185377Ssam		ee->ee_dataPerChannel11g[i].numPcdacValues = NUM_PCDAC_VALUES;
1860185377Ssam	}
1861185377Ssam
1862185377Ssam	if (!legacyEepromReadContents(ah, ee)) {
1863185377Ssam		/* XXX message */
1864185377Ssam		ath_hal_free(ee);
1865185377Ssam		return HAL_EEREAD;	/* XXX */
1866185377Ssam	}
1867185377Ssam
1868185377Ssam	AH_PRIVATE(ah)->ah_eeprom = ee;
1869185377Ssam	AH_PRIVATE(ah)->ah_eeversion = eeversion;
1870185377Ssam	AH_PRIVATE(ah)->ah_eepromDetach = legacyEepromDetach;
1871185377Ssam	AH_PRIVATE(ah)->ah_eepromGet = legacyEepromGet;
1872185377Ssam	AH_PRIVATE(ah)->ah_eepromSet = legacyEepromSet;
1873185377Ssam	AH_PRIVATE(ah)->ah_getSpurChan = legacyEepromGetSpurChan;
1874185377Ssam	AH_PRIVATE(ah)->ah_eepromDiag = legacyEepromDiag;
1875185377Ssam	return HAL_OK;
1876185377Ssam}
1877