Path: blob/main/sys/dev/ath/ath_hal/ah_eeprom_v3.c
39537 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"22#include "ah_eeprom_v3.h"2324static void25getPcdacInterceptsFromPcdacMinMax(HAL_EEPROM *ee,26uint16_t pcdacMin, uint16_t pcdacMax, uint16_t *vp)27{28static const uint16_t intercepts3[] =29{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };30static const uint16_t intercepts3_2[] =31{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };32const uint16_t *ip = ee->ee_version < AR_EEPROM_VER3_2 ?33intercepts3 : intercepts3_2;34int i;3536/* loop for the percentages in steps or 5 */37for (i = 0; i < NUM_INTERCEPTS; i++ )38*vp++ = (ip[i] * pcdacMax + (100 - ip[i]) * pcdacMin) / 100;39}4041/*42* Get channel value from binary representation held in eeprom43*/44static uint16_t45fbin2freq(HAL_EEPROM *ee, uint16_t fbin)46{47if (fbin == CHANNEL_UNUSED) /* reserved value, don't convert */48return fbin;49return ee->ee_version <= AR_EEPROM_VER3_2 ?50(fbin > 62 ? 5100 + 10*62 + 5*(fbin-62) : 5100 + 10*fbin) :514800 + 5*fbin;52}5354static uint16_t55fbin2freq_2p4(HAL_EEPROM *ee, uint16_t fbin)56{57if (fbin == CHANNEL_UNUSED) /* reserved value, don't convert */58return fbin;59return ee->ee_version <= AR_EEPROM_VER3_2 ?602400 + fbin :612300 + fbin;62}6364/*65* Now copy EEPROM frequency pier contents into the allocated space66*/67static HAL_BOOL68readEepromFreqPierInfo(struct ath_hal *ah, HAL_EEPROM *ee)69{70#define EEREAD(_off) do { \71if (!ath_hal_eepromRead(ah, _off, &eeval)) \72return AH_FALSE; \73} while (0)74uint16_t eeval, off;75int i;7677if (ee->ee_version >= AR_EEPROM_VER4_0 &&78ee->ee_eepMap && !ee->ee_Amode) {79/*80* V4.0 EEPROMs with map type 1 have frequency pier81* data only when 11a mode is supported.82*/83return AH_TRUE;84}85if (ee->ee_version >= AR_EEPROM_VER3_3) {86off = GROUPS_OFFSET3_3 + GROUP1_OFFSET;87for (i = 0; i < ee->ee_numChannels11a; i += 2) {88EEREAD(off++);89ee->ee_channels11a[i] = (eeval >> 8) & FREQ_MASK_3_3;90ee->ee_channels11a[i+1] = eeval & FREQ_MASK_3_3;91}92} else {93off = GROUPS_OFFSET3_2 + GROUP1_OFFSET;9495EEREAD(off++);96ee->ee_channels11a[0] = (eeval >> 9) & FREQ_MASK;97ee->ee_channels11a[1] = (eeval >> 2) & FREQ_MASK;98ee->ee_channels11a[2] = (eeval << 5) & FREQ_MASK;99100EEREAD(off++);101ee->ee_channels11a[2] |= (eeval >> 11) & 0x1f;102ee->ee_channels11a[3] = (eeval >> 4) & FREQ_MASK;103ee->ee_channels11a[4] = (eeval << 3) & FREQ_MASK;104105EEREAD(off++);106ee->ee_channels11a[4] |= (eeval >> 13) & 0x7;107ee->ee_channels11a[5] = (eeval >> 6) & FREQ_MASK;108ee->ee_channels11a[6] = (eeval << 1) & FREQ_MASK;109110EEREAD(off++);111ee->ee_channels11a[6] |= (eeval >> 15) & 0x1;112ee->ee_channels11a[7] = (eeval >> 8) & FREQ_MASK;113ee->ee_channels11a[8] = (eeval >> 1) & FREQ_MASK;114ee->ee_channels11a[9] = (eeval << 6) & FREQ_MASK;115116EEREAD(off++);117ee->ee_channels11a[9] |= (eeval >> 10) & 0x3f;118}119120for (i = 0; i < ee->ee_numChannels11a; i++)121ee->ee_channels11a[i] = fbin2freq(ee, ee->ee_channels11a[i]);122123return AH_TRUE;124#undef EEREAD125}126127/*128* Rev 4 Eeprom 5112 Power Extract Functions129*/130131/*132* Allocate the power information based on the number of channels133* recorded by the calibration. These values are then initialized.134*/135static HAL_BOOL136eepromAllocExpnPower5112(struct ath_hal *ah,137const EEPROM_POWER_5112 *pCalDataset,138EEPROM_POWER_EXPN_5112 *pPowerExpn)139{140uint16_t numChannels = pCalDataset->numChannels;141const uint16_t *pChanList = pCalDataset->pChannels;142void *data;143int i, j;144145/* Allocate the channel and Power Data arrays together */146data = ath_hal_malloc(147roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)) +148sizeof(EXPN_DATA_PER_CHANNEL_5112) * numChannels);149if (data == AH_NULL) {150HALDEBUG(ah, HAL_DEBUG_ANY,151"%s unable to allocate raw data struct (gen3)\n", __func__);152return AH_FALSE;153}154pPowerExpn->pChannels = data;155pPowerExpn->pDataPerChannel = (void *)(((char *)data) +156roundup(sizeof(uint16_t) * numChannels, sizeof(uint32_t)));157158pPowerExpn->numChannels = numChannels;159for (i = 0; i < numChannels; i++) {160pPowerExpn->pChannels[i] =161pPowerExpn->pDataPerChannel[i].channelValue =162pChanList[i];163for (j = 0; j < NUM_XPD_PER_CHANNEL; j++) {164pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].xpd_gain = j;165pPowerExpn->pDataPerChannel[i].pDataPerXPD[j].numPcdacs = 0;166}167pPowerExpn->pDataPerChannel[i].pDataPerXPD[0].numPcdacs = 4;168pPowerExpn->pDataPerChannel[i].pDataPerXPD[3].numPcdacs = 3;169}170return AH_TRUE;171}172173/*174* Expand the dataSet from the calibration information into the175* final power structure for 5112176*/177static HAL_BOOL178eepromExpandPower5112(struct ath_hal *ah,179const EEPROM_POWER_5112 *pCalDataset,180EEPROM_POWER_EXPN_5112 *pPowerExpn)181{182int ii, jj, kk;183int16_t maxPower_t4;184EXPN_DATA_PER_XPD_5112 *pExpnXPD;185/* ptr to array of info held per channel */186const EEPROM_DATA_PER_CHANNEL_5112 *pCalCh;187uint16_t xgainList[2], xpdMask;188189pPowerExpn->xpdMask = pCalDataset->xpdMask;190191xgainList[0] = 0xDEAD;192xgainList[1] = 0xDEAD;193194kk = 0;195xpdMask = pPowerExpn->xpdMask;196for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) {197if (((xpdMask >> jj) & 1) > 0) {198if (kk > 1) {199HALDEBUG(ah, HAL_DEBUG_ANY,200"%s: too many xpdGains in dataset: %u\n",201__func__, kk);202return AH_FALSE;203}204xgainList[kk++] = jj;205}206}207208pPowerExpn->numChannels = pCalDataset->numChannels;209if (pPowerExpn->numChannels == 0) {210HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no channels\n", __func__);211return AH_FALSE;212}213214for (ii = 0; ii < pPowerExpn->numChannels; ii++) {215pCalCh = &pCalDataset->pDataPerChannel[ii];216pPowerExpn->pDataPerChannel[ii].channelValue =217pCalCh->channelValue;218pPowerExpn->pDataPerChannel[ii].maxPower_t4 =219pCalCh->maxPower_t4;220maxPower_t4 = pPowerExpn->pDataPerChannel[ii].maxPower_t4;221222for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++)223pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj].numPcdacs = 0;224if (xgainList[1] == 0xDEAD) {225jj = xgainList[0];226pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];227pExpnXPD->numPcdacs = 4;228pExpnXPD->pcdac[0] = pCalCh->pcd1_xg0;229pExpnXPD->pcdac[1] = (uint16_t)230(pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0);231pExpnXPD->pcdac[2] = (uint16_t)232(pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0);233pExpnXPD->pcdac[3] = (uint16_t)234(pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0);235236pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0;237pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0;238pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0;239pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0;240241} else {242pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[0]].pcdac[0] = pCalCh->pcd1_xg0;243pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[0] = 20;244pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[1] = 35;245pPowerExpn->pDataPerChannel[ii].pDataPerXPD[xgainList[1]].pcdac[2] = 63;246247jj = xgainList[0];248pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];249pExpnXPD->numPcdacs = 4;250pExpnXPD->pcdac[1] = (uint16_t)251(pExpnXPD->pcdac[0] + pCalCh->pcd2_delta_xg0);252pExpnXPD->pcdac[2] = (uint16_t)253(pExpnXPD->pcdac[1] + pCalCh->pcd3_delta_xg0);254pExpnXPD->pcdac[3] = (uint16_t)255(pExpnXPD->pcdac[2] + pCalCh->pcd4_delta_xg0);256pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg0;257pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg0;258pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg0;259pExpnXPD->pwr_t4[3] = pCalCh->pwr4_xg0;260261jj = xgainList[1];262pExpnXPD = &pPowerExpn->pDataPerChannel[ii].pDataPerXPD[jj];263pExpnXPD->numPcdacs = 3;264265pExpnXPD->pwr_t4[0] = pCalCh->pwr1_xg3;266pExpnXPD->pwr_t4[1] = pCalCh->pwr2_xg3;267pExpnXPD->pwr_t4[2] = pCalCh->pwr3_xg3;268}269}270return AH_TRUE;271}272273static HAL_BOOL274readEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee)275{276#define EEREAD(_off) do { \277if (!ath_hal_eepromRead(ah, _off, &eeval)) \278return AH_FALSE; \279} while (0)280const uint16_t dbmmask = 0xff;281const uint16_t pcdac_delta_mask = 0x1f;282const uint16_t pcdac_mask = 0x3f;283const uint16_t freqmask = 0xff;284285int i, mode, numPiers;286uint32_t off;287uint16_t eeval;288uint16_t freq[NUM_11A_EEPROM_CHANNELS];289EEPROM_POWER_5112 eePower;290291HALASSERT(ee->ee_version >= AR_EEPROM_VER4_0);292off = GROUPS_OFFSET3_3;293for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {294numPiers = 0;295switch (mode) {296case headerInfo11A:297if (!ee->ee_Amode) /* no 11a calibration data */298continue;299while (numPiers < NUM_11A_EEPROM_CHANNELS) {300EEREAD(off++);301if ((eeval & freqmask) == 0)302break;303freq[numPiers++] = fbin2freq(ee,304eeval & freqmask);305306if (((eeval >> 8) & freqmask) == 0)307break;308freq[numPiers++] = fbin2freq(ee,309(eeval>>8) & freqmask);310}311break;312case headerInfo11B:313if (!ee->ee_Bmode) /* no 11b calibration data */314continue;315for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++)316if (ee->ee_calPier11b[i] != CHANNEL_UNUSED)317freq[numPiers++] = ee->ee_calPier11b[i];318break;319case headerInfo11G:320if (!ee->ee_Gmode) /* no 11g calibration data */321continue;322for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++)323if (ee->ee_calPier11g[i] != CHANNEL_UNUSED)324freq[numPiers++] = ee->ee_calPier11g[i];325break;326default:327HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",328__func__, mode);329return AH_FALSE;330}331332OS_MEMZERO(&eePower, sizeof(eePower));333eePower.numChannels = numPiers;334335for (i = 0; i < numPiers; i++) {336eePower.pChannels[i] = freq[i];337eePower.pDataPerChannel[i].channelValue = freq[i];338339EEREAD(off++);340eePower.pDataPerChannel[i].pwr1_xg0 = (int16_t)341((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);342eePower.pDataPerChannel[i].pwr2_xg0 = (int16_t)343(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);344345EEREAD(off++);346eePower.pDataPerChannel[i].pwr3_xg0 = (int16_t)347((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);348eePower.pDataPerChannel[i].pwr4_xg0 = (int16_t)349(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);350351EEREAD(off++);352eePower.pDataPerChannel[i].pcd2_delta_xg0 = (uint16_t)353(eeval & pcdac_delta_mask);354eePower.pDataPerChannel[i].pcd3_delta_xg0 = (uint16_t)355((eeval >> 5) & pcdac_delta_mask);356eePower.pDataPerChannel[i].pcd4_delta_xg0 = (uint16_t)357((eeval >> 10) & pcdac_delta_mask);358359EEREAD(off++);360eePower.pDataPerChannel[i].pwr1_xg3 = (int16_t)361((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);362eePower.pDataPerChannel[i].pwr2_xg3 = (int16_t)363(((eeval >> 8) & dbmmask) - ((eeval >> 15) & 0x1)*256);364365EEREAD(off++);366eePower.pDataPerChannel[i].pwr3_xg3 = (int16_t)367((eeval & dbmmask) - ((eeval >> 7) & 0x1)*256);368if (ee->ee_version >= AR_EEPROM_VER4_3) {369eePower.pDataPerChannel[i].maxPower_t4 =370eePower.pDataPerChannel[i].pwr4_xg0;371eePower.pDataPerChannel[i].pcd1_xg0 = (uint16_t)372((eeval >> 8) & pcdac_mask);373} else {374eePower.pDataPerChannel[i].maxPower_t4 = (int16_t)375(((eeval >> 8) & dbmmask) -376((eeval >> 15) & 0x1)*256);377eePower.pDataPerChannel[i].pcd1_xg0 = 1;378}379}380eePower.xpdMask = ee->ee_xgain[mode];381382if (!eepromAllocExpnPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) {383HALDEBUG(ah, HAL_DEBUG_ANY,384"%s: did not allocate power struct\n", __func__);385return AH_FALSE;386}387if (!eepromExpandPower5112(ah, &eePower, &ee->ee_modePowerArray5112[mode])) {388HALDEBUG(ah, HAL_DEBUG_ANY,389"%s: did not expand power struct\n", __func__);390return AH_FALSE;391}392}393return AH_TRUE;394#undef EEREAD395}396397static void398freeEepromRawPowerCalInfo5112(struct ath_hal *ah, HAL_EEPROM *ee)399{400int mode;401void *data;402403for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {404EEPROM_POWER_EXPN_5112 *pPowerExpn =405&ee->ee_modePowerArray5112[mode];406data = pPowerExpn->pChannels;407if (data != AH_NULL) {408pPowerExpn->pChannels = AH_NULL;409ath_hal_free(data);410}411}412}413414static void415ar2413SetupEEPROMDataset(EEPROM_DATA_STRUCT_2413 *pEEPROMDataset2413,416uint16_t myNumRawChannels, uint16_t *pMyRawChanList)417{418uint16_t i, channelValue;419uint32_t xpd_mask;420uint16_t numPdGainsUsed;421422pEEPROMDataset2413->numChannels = myNumRawChannels;423424xpd_mask = pEEPROMDataset2413->xpd_mask;425numPdGainsUsed = 0;426if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++;427if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++;428if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++;429if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++;430431for (i = 0; i < myNumRawChannels; i++) {432channelValue = pMyRawChanList[i];433pEEPROMDataset2413->pChannels[i] = channelValue;434pEEPROMDataset2413->pDataPerChannel[i].channelValue = channelValue;435pEEPROMDataset2413->pDataPerChannel[i].numPdGains = numPdGainsUsed;436}437}438439static HAL_BOOL440ar2413ReadCalDataset(struct ath_hal *ah, HAL_EEPROM *ee,441EEPROM_DATA_STRUCT_2413 *pCalDataset,442uint32_t start_offset, uint32_t maxPiers, uint8_t mode)443{444#define EEREAD(_off) do { \445if (!ath_hal_eepromRead(ah, _off, &eeval)) \446return AH_FALSE; \447} while (0)448const uint16_t dbm_I_mask = 0x1F; /* 5-bits. 1dB step. */449const uint16_t dbm_delta_mask = 0xF; /* 4-bits. 0.5dB step. */450const uint16_t Vpd_I_mask = 0x7F; /* 7-bits. 0-128 */451const uint16_t Vpd_delta_mask = 0x3F; /* 6-bits. 0-63 */452const uint16_t freqmask = 0xff;453454uint16_t ii, eeval;455uint16_t idx, numPiers;456uint16_t freq[NUM_11A_EEPROM_CHANNELS];457458idx = start_offset;459for (numPiers = 0; numPiers < maxPiers;) {460EEREAD(idx++);461if ((eeval & freqmask) == 0)462break;463if (mode == headerInfo11A)464freq[numPiers++] = fbin2freq(ee, (eeval & freqmask));465else466freq[numPiers++] = fbin2freq_2p4(ee, (eeval & freqmask));467468if (((eeval >> 8) & freqmask) == 0)469break;470if (mode == headerInfo11A)471freq[numPiers++] = fbin2freq(ee, (eeval >> 8) & freqmask);472else473freq[numPiers++] = fbin2freq_2p4(ee, (eeval >> 8) & freqmask);474}475ar2413SetupEEPROMDataset(pCalDataset, numPiers, &freq[0]);476477idx = start_offset + (maxPiers / 2);478for (ii = 0; ii < pCalDataset->numChannels; ii++) {479EEPROM_DATA_PER_CHANNEL_2413 *currCh =480&(pCalDataset->pDataPerChannel[ii]);481482if (currCh->numPdGains > 0) {483/*484* Read the first NUM_POINTS_OTHER_PDGAINS pwr485* and Vpd values for pdgain_0486*/487EEREAD(idx++);488currCh->pwr_I[0] = eeval & dbm_I_mask;489currCh->Vpd_I[0] = (eeval >> 5) & Vpd_I_mask;490currCh->pwr_delta_t2[0][0] =491(eeval >> 12) & dbm_delta_mask;492493EEREAD(idx++);494currCh->Vpd_delta[0][0] = eeval & Vpd_delta_mask;495currCh->pwr_delta_t2[1][0] =496(eeval >> 6) & dbm_delta_mask;497currCh->Vpd_delta[1][0] =498(eeval >> 10) & Vpd_delta_mask;499500EEREAD(idx++);501currCh->pwr_delta_t2[2][0] = eeval & dbm_delta_mask;502currCh->Vpd_delta[2][0] = (eeval >> 4) & Vpd_delta_mask;503}504505if (currCh->numPdGains > 1) {506/*507* Read the first NUM_POINTS_OTHER_PDGAINS pwr508* and Vpd values for pdgain_1509*/510currCh->pwr_I[1] = (eeval >> 10) & dbm_I_mask;511currCh->Vpd_I[1] = (eeval >> 15) & 0x1;512513EEREAD(idx++);514/* upper 6 bits */515currCh->Vpd_I[1] |= (eeval & 0x3F) << 1;516currCh->pwr_delta_t2[0][1] =517(eeval >> 6) & dbm_delta_mask;518currCh->Vpd_delta[0][1] =519(eeval >> 10) & Vpd_delta_mask;520521EEREAD(idx++);522currCh->pwr_delta_t2[1][1] = eeval & dbm_delta_mask;523currCh->Vpd_delta[1][1] = (eeval >> 4) & Vpd_delta_mask;524currCh->pwr_delta_t2[2][1] =525(eeval >> 10) & dbm_delta_mask;526currCh->Vpd_delta[2][1] = (eeval >> 14) & 0x3;527528EEREAD(idx++);529/* upper 4 bits */530currCh->Vpd_delta[2][1] |= (eeval & 0xF) << 2;531} else if (currCh->numPdGains == 1) {532/*533* Read the last pwr and Vpd values for pdgain_0534*/535currCh->pwr_delta_t2[3][0] =536(eeval >> 10) & dbm_delta_mask;537currCh->Vpd_delta[3][0] = (eeval >> 14) & 0x3;538539EEREAD(idx++);540/* upper 4 bits */541currCh->Vpd_delta[3][0] |= (eeval & 0xF) << 2;542543/* 4 words if numPdGains == 1 */544}545546if (currCh->numPdGains > 2) {547/*548* Read the first NUM_POINTS_OTHER_PDGAINS pwr549* and Vpd values for pdgain_2550*/551currCh->pwr_I[2] = (eeval >> 4) & dbm_I_mask;552currCh->Vpd_I[2] = (eeval >> 9) & Vpd_I_mask;553554EEREAD(idx++);555currCh->pwr_delta_t2[0][2] =556(eeval >> 0) & dbm_delta_mask;557currCh->Vpd_delta[0][2] = (eeval >> 4) & Vpd_delta_mask;558currCh->pwr_delta_t2[1][2] =559(eeval >> 10) & dbm_delta_mask;560currCh->Vpd_delta[1][2] = (eeval >> 14) & 0x3;561562EEREAD(idx++);563/* upper 4 bits */564currCh->Vpd_delta[1][2] |= (eeval & 0xF) << 2;565currCh->pwr_delta_t2[2][2] =566(eeval >> 4) & dbm_delta_mask;567currCh->Vpd_delta[2][2] = (eeval >> 8) & Vpd_delta_mask;568} else if (currCh->numPdGains == 2) {569/*570* Read the last pwr and Vpd values for pdgain_1571*/572currCh->pwr_delta_t2[3][1] =573(eeval >> 4) & dbm_delta_mask;574currCh->Vpd_delta[3][1] = (eeval >> 8) & Vpd_delta_mask;575576/* 6 words if numPdGains == 2 */577}578579if (currCh->numPdGains > 3) {580/*581* Read the first NUM_POINTS_OTHER_PDGAINS pwr582* and Vpd values for pdgain_3583*/584currCh->pwr_I[3] = (eeval >> 14) & 0x3;585586EEREAD(idx++);587/* upper 3 bits */588currCh->pwr_I[3] |= ((eeval >> 0) & 0x7) << 2;589currCh->Vpd_I[3] = (eeval >> 3) & Vpd_I_mask;590currCh->pwr_delta_t2[0][3] =591(eeval >> 10) & dbm_delta_mask;592currCh->Vpd_delta[0][3] = (eeval >> 14) & 0x3;593594EEREAD(idx++);595/* upper 4 bits */596currCh->Vpd_delta[0][3] |= (eeval & 0xF) << 2;597currCh->pwr_delta_t2[1][3] =598(eeval >> 4) & dbm_delta_mask;599currCh->Vpd_delta[1][3] = (eeval >> 8) & Vpd_delta_mask;600currCh->pwr_delta_t2[2][3] = (eeval >> 14) & 0x3;601602EEREAD(idx++);603/* upper 2 bits */604currCh->pwr_delta_t2[2][3] |= ((eeval >> 0) & 0x3) << 2;605currCh->Vpd_delta[2][3] = (eeval >> 2) & Vpd_delta_mask;606currCh->pwr_delta_t2[3][3] =607(eeval >> 8) & dbm_delta_mask;608currCh->Vpd_delta[3][3] = (eeval >> 12) & 0xF;609610EEREAD(idx++);611/* upper 2 bits */612currCh->Vpd_delta[3][3] |= ((eeval >> 0) & 0x3) << 4;613614/* 12 words if numPdGains == 4 */615} else if (currCh->numPdGains == 3) {616/* read the last pwr and Vpd values for pdgain_2 */617currCh->pwr_delta_t2[3][2] = (eeval >> 14) & 0x3;618619EEREAD(idx++);620/* upper 2 bits */621currCh->pwr_delta_t2[3][2] |= ((eeval >> 0) & 0x3) << 2;622currCh->Vpd_delta[3][2] = (eeval >> 2) & Vpd_delta_mask;623624/* 9 words if numPdGains == 3 */625}626}627return AH_TRUE;628#undef EEREAD629}630631static void632ar2413SetupRawDataset(RAW_DATA_STRUCT_2413 *pRaw, EEPROM_DATA_STRUCT_2413 *pCal)633{634uint16_t i, j, kk, channelValue;635uint16_t xpd_mask;636uint16_t numPdGainsUsed;637638pRaw->numChannels = pCal->numChannels;639640xpd_mask = pRaw->xpd_mask;641numPdGainsUsed = 0;642if ((xpd_mask >> 0) & 0x1) numPdGainsUsed++;643if ((xpd_mask >> 1) & 0x1) numPdGainsUsed++;644if ((xpd_mask >> 2) & 0x1) numPdGainsUsed++;645if ((xpd_mask >> 3) & 0x1) numPdGainsUsed++;646647for (i = 0; i < pCal->numChannels; i++) {648channelValue = pCal->pChannels[i];649650pRaw->pChannels[i] = channelValue;651652pRaw->pDataPerChannel[i].channelValue = channelValue;653pRaw->pDataPerChannel[i].numPdGains = numPdGainsUsed;654655kk = 0;656for (j = 0; j < MAX_NUM_PDGAINS_PER_CHANNEL; j++) {657pRaw->pDataPerChannel[i].pDataPerPDGain[j].pd_gain = j;658if ((xpd_mask >> j) & 0x1) {659pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_OTHER_PDGAINS;660kk++;661if (kk == 1) {662/*663* lowest pd_gain corresponds664* to highest power and thus,665* has one more point666*/667pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = NUM_POINTS_LAST_PDGAIN;668}669} else {670pRaw->pDataPerChannel[i].pDataPerPDGain[j].numVpd = 0;671}672}673}674}675676static HAL_BOOL677ar2413EepromToRawDataset(struct ath_hal *ah,678EEPROM_DATA_STRUCT_2413 *pCal, RAW_DATA_STRUCT_2413 *pRaw)679{680uint16_t ii, jj, kk, ss;681RAW_DATA_PER_PDGAIN_2413 *pRawXPD;682/* ptr to array of info held per channel */683EEPROM_DATA_PER_CHANNEL_2413 *pCalCh;684uint16_t xgain_list[MAX_NUM_PDGAINS_PER_CHANNEL];685uint16_t xpd_mask;686uint32_t numPdGainsUsed;687688HALASSERT(pRaw->xpd_mask == pCal->xpd_mask);689690xgain_list[0] = 0xDEAD;691xgain_list[1] = 0xDEAD;692xgain_list[2] = 0xDEAD;693xgain_list[3] = 0xDEAD;694695numPdGainsUsed = 0;696xpd_mask = pRaw->xpd_mask;697for (jj = 0; jj < MAX_NUM_PDGAINS_PER_CHANNEL; jj++) {698if ((xpd_mask >> (MAX_NUM_PDGAINS_PER_CHANNEL-jj-1)) & 1)699xgain_list[numPdGainsUsed++] = MAX_NUM_PDGAINS_PER_CHANNEL-jj-1;700}701702pRaw->numChannels = pCal->numChannels;703for (ii = 0; ii < pRaw->numChannels; ii++) {704pCalCh = &(pCal->pDataPerChannel[ii]);705pRaw->pDataPerChannel[ii].channelValue = pCalCh->channelValue;706707/* numVpd has already been setup appropriately for the relevant pdGains */708for (jj = 0; jj < numPdGainsUsed; jj++) {709/* use jj for calDataset and ss for rawDataset */710ss = xgain_list[jj];711pRawXPD = &(pRaw->pDataPerChannel[ii].pDataPerPDGain[ss]);712HALASSERT(pRawXPD->numVpd >= 1);713714pRawXPD->pwr_t4[0] = (uint16_t)(4*pCalCh->pwr_I[jj]);715pRawXPD->Vpd[0] = pCalCh->Vpd_I[jj];716717for (kk = 1; kk < pRawXPD->numVpd; kk++) {718pRawXPD->pwr_t4[kk] = (int16_t)(pRawXPD->pwr_t4[kk-1] + 2*pCalCh->pwr_delta_t2[kk-1][jj]);719pRawXPD->Vpd[kk] = (uint16_t)(pRawXPD->Vpd[kk-1] + pCalCh->Vpd_delta[kk-1][jj]);720}721/* loop over Vpds */722}723/* loop over pd_gains */724}725/* loop over channels */726return AH_TRUE;727}728729static HAL_BOOL730readEepromRawPowerCalInfo2413(struct ath_hal *ah, HAL_EEPROM *ee)731{732/* NB: index is 1 less than numPdgains */733static const uint16_t wordsForPdgains[] = { 4, 6, 9, 12 };734EEPROM_DATA_STRUCT_2413 *pCal = AH_NULL;735RAW_DATA_STRUCT_2413 *pRaw;736int numEEPROMWordsPerChannel;737uint32_t off;738HAL_BOOL ret = AH_FALSE;739740HALASSERT(ee->ee_version >= AR_EEPROM_VER5_0);741HALASSERT(ee->ee_eepMap == 2);742743pCal = ath_hal_malloc(sizeof(EEPROM_DATA_STRUCT_2413));744if (pCal == AH_NULL)745goto exit;746747off = ee->ee_eepMap2PowerCalStart;748if (ee->ee_Amode) {749OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));750pCal->xpd_mask = ee->ee_xgain[headerInfo11A];751if (!ar2413ReadCalDataset(ah, ee, pCal, off,752NUM_11A_EEPROM_CHANNELS_2413, headerInfo11A)) {753goto exit;754}755pRaw = &ee->ee_rawDataset2413[headerInfo11A];756pRaw->xpd_mask = ee->ee_xgain[headerInfo11A];757ar2413SetupRawDataset(pRaw, pCal);758if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {759goto exit;760}761/* setup offsets for mode_11a next */762numEEPROMWordsPerChannel = wordsForPdgains[763pCal->pDataPerChannel[0].numPdGains - 1];764off += pCal->numChannels * numEEPROMWordsPerChannel + 5;765}766if (ee->ee_Bmode) {767OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));768pCal->xpd_mask = ee->ee_xgain[headerInfo11B];769if (!ar2413ReadCalDataset(ah, ee, pCal, off,770NUM_2_4_EEPROM_CHANNELS_2413 , headerInfo11B)) {771goto exit;772}773pRaw = &ee->ee_rawDataset2413[headerInfo11B];774pRaw->xpd_mask = ee->ee_xgain[headerInfo11B];775ar2413SetupRawDataset(pRaw, pCal);776if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {777goto exit;778}779/* setup offsets for mode_11g next */780numEEPROMWordsPerChannel = wordsForPdgains[781pCal->pDataPerChannel[0].numPdGains - 1];782off += pCal->numChannels * numEEPROMWordsPerChannel + 2;783}784if (ee->ee_Gmode) {785OS_MEMZERO(pCal, sizeof(EEPROM_DATA_STRUCT_2413));786pCal->xpd_mask = ee->ee_xgain[headerInfo11G];787if (!ar2413ReadCalDataset(ah, ee, pCal, off,788NUM_2_4_EEPROM_CHANNELS_2413, headerInfo11G)) {789goto exit;790}791pRaw = &ee->ee_rawDataset2413[headerInfo11G];792pRaw->xpd_mask = ee->ee_xgain[headerInfo11G];793ar2413SetupRawDataset(pRaw, pCal);794if (!ar2413EepromToRawDataset(ah, pCal, pRaw)) {795goto exit;796}797}798ret = AH_TRUE;799exit:800if (pCal != AH_NULL)801ath_hal_free(pCal);802return ret;803}804805/*806* Now copy EEPROM Raw Power Calibration per frequency contents807* into the allocated space808*/809static HAL_BOOL810readEepromRawPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee)811{812#define EEREAD(_off) do { \813if (!ath_hal_eepromRead(ah, _off, &eeval)) \814return AH_FALSE; \815} while (0)816uint16_t eeval, nchan;817uint32_t off;818int i, j, mode;819820if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1)821return readEepromRawPowerCalInfo5112(ah, ee);822if (ee->ee_version >= AR_EEPROM_VER5_0 && ee->ee_eepMap == 2)823return readEepromRawPowerCalInfo2413(ah, ee);824825/*826* Group 2: read raw power data for all frequency piers827*828* NOTE: Group 2 contains the raw power calibration829* information for each of the channels that830* we recorded above.831*/832for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {833uint16_t *pChannels = AH_NULL;834DATA_PER_CHANNEL *pChannelData = AH_NULL;835836off = ee->ee_version >= AR_EEPROM_VER3_3 ?837GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2;838switch (mode) {839case headerInfo11A:840off += GROUP2_OFFSET;841nchan = ee->ee_numChannels11a;842pChannelData = ee->ee_dataPerChannel11a;843pChannels = ee->ee_channels11a;844break;845case headerInfo11B:846if (!ee->ee_Bmode)847continue;848off += GROUP3_OFFSET;849nchan = ee->ee_numChannels2_4;850pChannelData = ee->ee_dataPerChannel11b;851pChannels = ee->ee_channels11b;852break;853case headerInfo11G:854if (!ee->ee_Gmode)855continue;856off += GROUP4_OFFSET;857nchan = ee->ee_numChannels2_4;858pChannelData = ee->ee_dataPerChannel11g;859pChannels = ee->ee_channels11g;860break;861default:862HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",863__func__, mode);864return AH_FALSE;865}866for (i = 0; i < nchan; i++) {867pChannelData->channelValue = pChannels[i];868869EEREAD(off++);870pChannelData->pcdacMax = (uint16_t)((eeval >> 10) & PCDAC_MASK);871pChannelData->pcdacMin = (uint16_t)((eeval >> 4) & PCDAC_MASK);872pChannelData->PwrValues[0] = (uint16_t)((eeval << 2) & POWER_MASK);873874EEREAD(off++);875pChannelData->PwrValues[0] |= (uint16_t)((eeval >> 14) & 0x3);876pChannelData->PwrValues[1] = (uint16_t)((eeval >> 8) & POWER_MASK);877pChannelData->PwrValues[2] = (uint16_t)((eeval >> 2) & POWER_MASK);878pChannelData->PwrValues[3] = (uint16_t)((eeval << 4) & POWER_MASK);879880EEREAD(off++);881pChannelData->PwrValues[3] |= (uint16_t)((eeval >> 12) & 0xf);882pChannelData->PwrValues[4] = (uint16_t)((eeval >> 6) & POWER_MASK);883pChannelData->PwrValues[5] = (uint16_t)(eeval & POWER_MASK);884885EEREAD(off++);886pChannelData->PwrValues[6] = (uint16_t)((eeval >> 10) & POWER_MASK);887pChannelData->PwrValues[7] = (uint16_t)((eeval >> 4) & POWER_MASK);888pChannelData->PwrValues[8] = (uint16_t)((eeval << 2) & POWER_MASK);889890EEREAD(off++);891pChannelData->PwrValues[8] |= (uint16_t)((eeval >> 14) & 0x3);892pChannelData->PwrValues[9] = (uint16_t)((eeval >> 8) & POWER_MASK);893pChannelData->PwrValues[10] = (uint16_t)((eeval >> 2) & POWER_MASK);894895getPcdacInterceptsFromPcdacMinMax(ee,896pChannelData->pcdacMin, pChannelData->pcdacMax,897pChannelData->PcdacValues) ;898899for (j = 0; j < pChannelData->numPcdacValues; j++) {900pChannelData->PwrValues[j] = (uint16_t)(901PWR_STEP * pChannelData->PwrValues[j]);902/* Note these values are scaled up. */903}904pChannelData++;905}906}907return AH_TRUE;908#undef EEREAD909}910911/*912* Copy EEPROM Target Power Calbration per rate contents913* into the allocated space914*/915static HAL_BOOL916readEepromTargetPowerCalInfo(struct ath_hal *ah, HAL_EEPROM *ee)917{918#define EEREAD(_off) do { \919if (!ath_hal_eepromRead(ah, _off, &eeval)) \920return AH_FALSE; \921} while (0)922uint16_t eeval, enable24;923uint32_t off;924int i, mode, nchan;925926enable24 = ee->ee_Bmode || ee->ee_Gmode;927for (mode = headerInfo11A; mode <= headerInfo11G; mode++) {928TRGT_POWER_INFO *pPowerInfo;929uint16_t *pNumTrgtChannels;930931off = ee->ee_version >= AR_EEPROM_VER4_0 ?932ee->ee_targetPowersStart - GROUP5_OFFSET :933ee->ee_version >= AR_EEPROM_VER3_3 ?934GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2;935switch (mode) {936case headerInfo11A:937off += GROUP5_OFFSET;938nchan = NUM_TEST_FREQUENCIES;939pPowerInfo = ee->ee_trgtPwr_11a;940pNumTrgtChannels = &ee->ee_numTargetPwr_11a;941break;942case headerInfo11B:943if (!enable24)944continue;945off += GROUP6_OFFSET;946nchan = 2;947pPowerInfo = ee->ee_trgtPwr_11b;948pNumTrgtChannels = &ee->ee_numTargetPwr_11b;949break;950case headerInfo11G:951if (!enable24)952continue;953off += GROUP7_OFFSET;954nchan = 3;955pPowerInfo = ee->ee_trgtPwr_11g;956pNumTrgtChannels = &ee->ee_numTargetPwr_11g;957break;958default:959HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n",960__func__, mode);961return AH_FALSE;962}963*pNumTrgtChannels = 0;964for (i = 0; i < nchan; i++) {965EEREAD(off++);966if (ee->ee_version >= AR_EEPROM_VER3_3) {967pPowerInfo->testChannel = (eeval >> 8) & 0xff;968} else {969pPowerInfo->testChannel = (eeval >> 9) & 0x7f;970}971972if (pPowerInfo->testChannel != 0) {973/* get the channel value and read rest of info */974if (mode == headerInfo11A) {975pPowerInfo->testChannel = fbin2freq(ee, pPowerInfo->testChannel);976} else {977pPowerInfo->testChannel = fbin2freq_2p4(ee, pPowerInfo->testChannel);978}979980if (ee->ee_version >= AR_EEPROM_VER3_3) {981pPowerInfo->twicePwr6_24 = (eeval >> 2) & POWER_MASK;982pPowerInfo->twicePwr36 = (eeval << 4) & POWER_MASK;983} else {984pPowerInfo->twicePwr6_24 = (eeval >> 3) & POWER_MASK;985pPowerInfo->twicePwr36 = (eeval << 3) & POWER_MASK;986}987988EEREAD(off++);989if (ee->ee_version >= AR_EEPROM_VER3_3) {990pPowerInfo->twicePwr36 |= (eeval >> 12) & 0xf;991pPowerInfo->twicePwr48 = (eeval >> 6) & POWER_MASK;992pPowerInfo->twicePwr54 = eeval & POWER_MASK;993} else {994pPowerInfo->twicePwr36 |= (eeval >> 13) & 0x7;995pPowerInfo->twicePwr48 = (eeval >> 7) & POWER_MASK;996pPowerInfo->twicePwr54 = (eeval >> 1) & POWER_MASK;997}998(*pNumTrgtChannels)++;999}1000pPowerInfo++;1001}1002}1003return AH_TRUE;1004#undef EEREAD1005}10061007/*1008* Now copy EEPROM Coformance Testing Limits contents1009* into the allocated space1010*/1011static HAL_BOOL1012readEepromCTLInfo(struct ath_hal *ah, HAL_EEPROM *ee)1013{1014#define EEREAD(_off) do { \1015if (!ath_hal_eepromRead(ah, _off, &eeval)) \1016return AH_FALSE; \1017} while (0)1018RD_EDGES_POWER *rep;1019uint16_t eeval;1020uint32_t off;1021int i, j;10221023rep = ee->ee_rdEdgesPower;10241025off = GROUP8_OFFSET +1026(ee->ee_version >= AR_EEPROM_VER4_0 ?1027ee->ee_targetPowersStart - GROUP5_OFFSET :1028ee->ee_version >= AR_EEPROM_VER3_3 ?1029GROUPS_OFFSET3_3 : GROUPS_OFFSET3_2);1030for (i = 0; i < ee->ee_numCtls; i++) {1031if (ee->ee_ctl[i] == 0) {1032/* Move offset and edges */1033off += (ee->ee_version >= AR_EEPROM_VER3_3 ? 8 : 7);1034rep += NUM_EDGES;1035continue;1036}1037if (ee->ee_version >= AR_EEPROM_VER3_3) {1038for (j = 0; j < NUM_EDGES; j += 2) {1039EEREAD(off++);1040rep[j].rdEdge = (eeval >> 8) & FREQ_MASK_3_3;1041rep[j+1].rdEdge = eeval & FREQ_MASK_3_3;1042}1043for (j = 0; j < NUM_EDGES; j += 2) {1044EEREAD(off++);1045rep[j].twice_rdEdgePower =1046(eeval >> 8) & POWER_MASK;1047rep[j].flag = (eeval >> 14) & 1;1048rep[j+1].twice_rdEdgePower = eeval & POWER_MASK;1049rep[j+1].flag = (eeval >> 6) & 1;1050}1051} else {1052EEREAD(off++);1053rep[0].rdEdge = (eeval >> 9) & FREQ_MASK;1054rep[1].rdEdge = (eeval >> 2) & FREQ_MASK;1055rep[2].rdEdge = (eeval << 5) & FREQ_MASK;10561057EEREAD(off++);1058rep[2].rdEdge |= (eeval >> 11) & 0x1f;1059rep[3].rdEdge = (eeval >> 4) & FREQ_MASK;1060rep[4].rdEdge = (eeval << 3) & FREQ_MASK;10611062EEREAD(off++);1063rep[4].rdEdge |= (eeval >> 13) & 0x7;1064rep[5].rdEdge = (eeval >> 6) & FREQ_MASK;1065rep[6].rdEdge = (eeval << 1) & FREQ_MASK;10661067EEREAD(off++);1068rep[6].rdEdge |= (eeval >> 15) & 0x1;1069rep[7].rdEdge = (eeval >> 8) & FREQ_MASK;10701071rep[0].twice_rdEdgePower = (eeval >> 2) & POWER_MASK;1072rep[1].twice_rdEdgePower = (eeval << 4) & POWER_MASK;10731074EEREAD(off++);1075rep[1].twice_rdEdgePower |= (eeval >> 12) & 0xf;1076rep[2].twice_rdEdgePower = (eeval >> 6) & POWER_MASK;1077rep[3].twice_rdEdgePower = eeval & POWER_MASK;10781079EEREAD(off++);1080rep[4].twice_rdEdgePower = (eeval >> 10) & POWER_MASK;1081rep[5].twice_rdEdgePower = (eeval >> 4) & POWER_MASK;1082rep[6].twice_rdEdgePower = (eeval << 2) & POWER_MASK;10831084EEREAD(off++);1085rep[6].twice_rdEdgePower |= (eeval >> 14) & 0x3;1086rep[7].twice_rdEdgePower = (eeval >> 8) & POWER_MASK;1087}10881089for (j = 0; j < NUM_EDGES; j++ ) {1090if (rep[j].rdEdge != 0 || rep[j].twice_rdEdgePower != 0) {1091if ((ee->ee_ctl[i] & CTL_MODE_M) == CTL_11A ||1092(ee->ee_ctl[i] & CTL_MODE_M) == CTL_TURBO) {1093rep[j].rdEdge = fbin2freq(ee, rep[j].rdEdge);1094} else {1095rep[j].rdEdge = fbin2freq_2p4(ee, rep[j].rdEdge);1096}1097}1098}1099rep += NUM_EDGES;1100}1101return AH_TRUE;1102#undef EEREAD1103}11041105/*1106* Read the individual header fields for a Rev 3 EEPROM1107*/1108static HAL_BOOL1109readHeaderInfo(struct ath_hal *ah, HAL_EEPROM *ee)1110{1111#define EEREAD(_off) do { \1112if (!ath_hal_eepromRead(ah, _off, &eeval)) \1113return AH_FALSE; \1114} while (0)1115static const uint32_t headerOffset3_0[] = {11160x00C2, /* 0 - Mode bits, device type, max turbo power */11170x00C4, /* 1 - 2.4 and 5 antenna gain */11180x00C5, /* 2 - Begin 11A modal section */11190x00D0, /* 3 - Begin 11B modal section */11200x00DA, /* 4 - Begin 11G modal section */11210x00E4 /* 5 - Begin CTL section */1122};1123static const uint32_t headerOffset3_3[] = {11240x00C2, /* 0 - Mode bits, device type, max turbo power */11250x00C3, /* 1 - 2.4 and 5 antenna gain */11260x00D4, /* 2 - Begin 11A modal section */11270x00F2, /* 3 - Begin 11B modal section */11280x010D, /* 4 - Begin 11G modal section */11290x0128 /* 5 - Begin CTL section */1130};11311132static const uint32_t regCapOffsetPre4_0 = 0x00CF;1133static const uint32_t regCapOffsetPost4_0 = 0x00CA;11341135const uint32_t *header;1136uint32_t off;1137uint16_t eeval;1138int i;11391140/* initialize cckOfdmGainDelta for < 4.2 eeprom */1141ee->ee_cckOfdmGainDelta = CCK_OFDM_GAIN_DELTA;1142ee->ee_scaledCh14FilterCckDelta = TENX_CH14_FILTER_CCK_DELTA_INIT;11431144if (ee->ee_version >= AR_EEPROM_VER3_3) {1145header = headerOffset3_3;1146ee->ee_numCtls = NUM_CTLS_3_3;1147} else {1148header = headerOffset3_0;1149ee->ee_numCtls = NUM_CTLS;1150}1151HALASSERT(ee->ee_numCtls <= NUM_CTLS_MAX);11521153EEREAD(header[0]);1154ee->ee_turbo5Disable = (eeval >> 15) & 0x01;1155ee->ee_rfKill = (eeval >> 14) & 0x01;1156ee->ee_deviceType = (eeval >> 11) & 0x07;1157ee->ee_turbo2WMaxPower5 = (eeval >> 4) & 0x7F;1158if (ee->ee_version >= AR_EEPROM_VER4_0)1159ee->ee_turbo2Disable = (eeval >> 3) & 0x01;1160else1161ee->ee_turbo2Disable = 1;1162ee->ee_Gmode = (eeval >> 2) & 0x01;1163ee->ee_Bmode = (eeval >> 1) & 0x01;1164ee->ee_Amode = (eeval & 0x01);11651166off = header[1];1167EEREAD(off++);1168ee->ee_antennaGainMax[0] = (int8_t)((eeval >> 8) & 0xFF);1169ee->ee_antennaGainMax[1] = (int8_t)(eeval & 0xFF);1170if (ee->ee_version >= AR_EEPROM_VER4_0) {1171EEREAD(off++);1172ee->ee_eepMap = (eeval>>14) & 0x3;1173ee->ee_disableXr5 = (eeval>>13) & 0x1;1174ee->ee_disableXr2 = (eeval>>12) & 0x1;1175ee->ee_earStart = eeval & 0xfff;11761177EEREAD(off++);1178ee->ee_targetPowersStart = eeval & 0xfff;1179ee->ee_exist32kHzCrystal = (eeval>>14) & 0x1;11801181if (ee->ee_version >= AR_EEPROM_VER5_0) {1182off += 2;1183EEREAD(off);1184ee->ee_eepMap2PowerCalStart = (eeval >> 4) & 0xfff;1185/* Properly cal'ed 5.0 devices should be non-zero */1186}1187}11881189/* Read the moded sections of the EEPROM header in the order A, B, G */1190for (i = headerInfo11A; i <= headerInfo11G; i++) {1191/* Set the offset via the index */1192off = header[2 + i];11931194EEREAD(off++);1195ee->ee_switchSettling[i] = (eeval >> 8) & 0x7f;1196ee->ee_txrxAtten[i] = (eeval >> 2) & 0x3f;1197ee->ee_antennaControl[0][i] = (eeval << 4) & 0x3f;11981199EEREAD(off++);1200ee->ee_antennaControl[0][i] |= (eeval >> 12) & 0x0f;1201ee->ee_antennaControl[1][i] = (eeval >> 6) & 0x3f;1202ee->ee_antennaControl[2][i] = eeval & 0x3f;12031204EEREAD(off++);1205ee->ee_antennaControl[3][i] = (eeval >> 10) & 0x3f;1206ee->ee_antennaControl[4][i] = (eeval >> 4) & 0x3f;1207ee->ee_antennaControl[5][i] = (eeval << 2) & 0x3f;12081209EEREAD(off++);1210ee->ee_antennaControl[5][i] |= (eeval >> 14) & 0x03;1211ee->ee_antennaControl[6][i] = (eeval >> 8) & 0x3f;1212ee->ee_antennaControl[7][i] = (eeval >> 2) & 0x3f;1213ee->ee_antennaControl[8][i] = (eeval << 4) & 0x3f;12141215EEREAD(off++);1216ee->ee_antennaControl[8][i] |= (eeval >> 12) & 0x0f;1217ee->ee_antennaControl[9][i] = (eeval >> 6) & 0x3f;1218ee->ee_antennaControl[10][i] = eeval & 0x3f;12191220EEREAD(off++);1221ee->ee_adcDesiredSize[i] = (int8_t)((eeval >> 8) & 0xff);1222switch (i) {1223case headerInfo11A:1224ee->ee_ob4 = (eeval >> 5) & 0x07;1225ee->ee_db4 = (eeval >> 2) & 0x07;1226ee->ee_ob3 = (eeval << 1) & 0x07;1227break;1228case headerInfo11B:1229ee->ee_obFor24 = (eeval >> 4) & 0x07;1230ee->ee_dbFor24 = eeval & 0x07;1231break;1232case headerInfo11G:1233ee->ee_obFor24g = (eeval >> 4) & 0x07;1234ee->ee_dbFor24g = eeval & 0x07;1235break;1236}12371238if (i == headerInfo11A) {1239EEREAD(off++);1240ee->ee_ob3 |= (eeval >> 15) & 0x01;1241ee->ee_db3 = (eeval >> 12) & 0x07;1242ee->ee_ob2 = (eeval >> 9) & 0x07;1243ee->ee_db2 = (eeval >> 6) & 0x07;1244ee->ee_ob1 = (eeval >> 3) & 0x07;1245ee->ee_db1 = eeval & 0x07;1246}12471248EEREAD(off++);1249ee->ee_txEndToXLNAOn[i] = (eeval >> 8) & 0xff;1250ee->ee_thresh62[i] = eeval & 0xff;12511252EEREAD(off++);1253ee->ee_txEndToXPAOff[i] = (eeval >> 8) & 0xff;1254ee->ee_txFrameToXPAOn[i] = eeval & 0xff;12551256EEREAD(off++);1257ee->ee_pgaDesiredSize[i] = (int8_t)((eeval >> 8) & 0xff);1258ee->ee_noiseFloorThresh[i] = eeval & 0xff;1259if (ee->ee_noiseFloorThresh[i] & 0x80) {1260ee->ee_noiseFloorThresh[i] = 0 -1261((ee->ee_noiseFloorThresh[i] ^ 0xff) + 1);1262}12631264EEREAD(off++);1265ee->ee_xlnaGain[i] = (eeval >> 5) & 0xff;1266ee->ee_xgain[i] = (eeval >> 1) & 0x0f;1267ee->ee_xpd[i] = eeval & 0x01;1268if (ee->ee_version >= AR_EEPROM_VER4_0) {1269switch (i) {1270case headerInfo11A:1271ee->ee_fixedBias5 = (eeval >> 13) & 0x1;1272break;1273case headerInfo11G:1274ee->ee_fixedBias2 = (eeval >> 13) & 0x1;1275break;1276}1277}12781279if (ee->ee_version >= AR_EEPROM_VER3_3) {1280EEREAD(off++);1281ee->ee_falseDetectBackoff[i] = (eeval >> 6) & 0x7F;1282switch (i) {1283case headerInfo11B:1284ee->ee_ob2GHz[0] = eeval & 0x7;1285ee->ee_db2GHz[0] = (eeval >> 3) & 0x7;1286break;1287case headerInfo11G:1288ee->ee_ob2GHz[1] = eeval & 0x7;1289ee->ee_db2GHz[1] = (eeval >> 3) & 0x7;1290break;1291case headerInfo11A:1292ee->ee_xrTargetPower5 = eeval & 0x3f;1293break;1294}1295}1296if (ee->ee_version >= AR_EEPROM_VER3_4) {1297ee->ee_gainI[i] = (eeval >> 13) & 0x07;12981299EEREAD(off++);1300ee->ee_gainI[i] |= (eeval << 3) & 0x38;1301if (i == headerInfo11G) {1302ee->ee_cckOfdmPwrDelta = (eeval >> 3) & 0xFF;1303if (ee->ee_version >= AR_EEPROM_VER4_6)1304ee->ee_scaledCh14FilterCckDelta =1305(eeval >> 11) & 0x1f;1306}1307if (i == headerInfo11A &&1308ee->ee_version >= AR_EEPROM_VER4_0) {1309ee->ee_iqCalI[0] = (eeval >> 8 ) & 0x3f;1310ee->ee_iqCalQ[0] = (eeval >> 3 ) & 0x1f;1311}1312} else {1313ee->ee_gainI[i] = 10;1314ee->ee_cckOfdmPwrDelta = TENX_OFDM_CCK_DELTA_INIT;1315}1316if (ee->ee_version >= AR_EEPROM_VER4_0) {1317switch (i) {1318case headerInfo11B:1319EEREAD(off++);1320ee->ee_calPier11b[0] =1321fbin2freq_2p4(ee, eeval&0xff);1322ee->ee_calPier11b[1] =1323fbin2freq_2p4(ee, (eeval >> 8)&0xff);1324EEREAD(off++);1325ee->ee_calPier11b[2] =1326fbin2freq_2p4(ee, eeval&0xff);1327if (ee->ee_version >= AR_EEPROM_VER4_1)1328ee->ee_rxtxMargin[headerInfo11B] =1329(eeval >> 8) & 0x3f;1330break;1331case headerInfo11G:1332EEREAD(off++);1333ee->ee_calPier11g[0] =1334fbin2freq_2p4(ee, eeval & 0xff);1335ee->ee_calPier11g[1] =1336fbin2freq_2p4(ee, (eeval >> 8) & 0xff);13371338EEREAD(off++);1339ee->ee_turbo2WMaxPower2 = eeval & 0x7F;1340ee->ee_xrTargetPower2 = (eeval >> 7) & 0x3f;13411342EEREAD(off++);1343ee->ee_calPier11g[2] =1344fbin2freq_2p4(ee, eeval & 0xff);1345if (ee->ee_version >= AR_EEPROM_VER4_1)1346ee->ee_rxtxMargin[headerInfo11G] =1347(eeval >> 8) & 0x3f;13481349EEREAD(off++);1350ee->ee_iqCalI[1] = (eeval >> 5) & 0x3F;1351ee->ee_iqCalQ[1] = eeval & 0x1F;13521353if (ee->ee_version >= AR_EEPROM_VER4_2) {1354EEREAD(off++);1355ee->ee_cckOfdmGainDelta =1356(uint8_t)(eeval & 0xFF);1357if (ee->ee_version >= AR_EEPROM_VER5_0) {1358ee->ee_switchSettlingTurbo[1] =1359(eeval >> 8) & 0x7f;1360ee->ee_txrxAttenTurbo[1] =1361(eeval >> 15) & 0x1;1362EEREAD(off++);1363ee->ee_txrxAttenTurbo[1] |=1364(eeval & 0x1F) << 1;1365ee->ee_rxtxMarginTurbo[1] =1366(eeval >> 5) & 0x3F;1367ee->ee_adcDesiredSizeTurbo[1] =1368(eeval >> 11) & 0x1F;1369EEREAD(off++);1370ee->ee_adcDesiredSizeTurbo[1] |=1371(eeval & 0x7) << 5;1372ee->ee_pgaDesiredSizeTurbo[1] =1373(eeval >> 3) & 0xFF;1374}1375}1376break;1377case headerInfo11A:1378if (ee->ee_version >= AR_EEPROM_VER4_1) {1379EEREAD(off++);1380ee->ee_rxtxMargin[headerInfo11A] =1381eeval & 0x3f;1382if (ee->ee_version >= AR_EEPROM_VER5_0) {1383ee->ee_switchSettlingTurbo[0] =1384(eeval >> 6) & 0x7f;1385ee->ee_txrxAttenTurbo[0] =1386(eeval >> 13) & 0x7;1387EEREAD(off++);1388ee->ee_txrxAttenTurbo[0] |=1389(eeval & 0x7) << 3;1390ee->ee_rxtxMarginTurbo[0] =1391(eeval >> 3) & 0x3F;1392ee->ee_adcDesiredSizeTurbo[0] =1393(eeval >> 9) & 0x7F;1394EEREAD(off++);1395ee->ee_adcDesiredSizeTurbo[0] |=1396(eeval & 0x1) << 7;1397ee->ee_pgaDesiredSizeTurbo[0] =1398(eeval >> 1) & 0xFF;1399}1400}1401break;1402}1403}1404}1405if (ee->ee_version < AR_EEPROM_VER3_3) {1406/* Version 3.1+ specific parameters */1407EEREAD(0xec);1408ee->ee_ob2GHz[0] = eeval & 0x7;1409ee->ee_db2GHz[0] = (eeval >> 3) & 0x7;14101411EEREAD(0xed);1412ee->ee_ob2GHz[1] = eeval & 0x7;1413ee->ee_db2GHz[1] = (eeval >> 3) & 0x7;1414}14151416/* Initialize corner cal (thermal tx gain adjust parameters) */1417ee->ee_cornerCal.clip = 4;1418ee->ee_cornerCal.pd90 = 1;1419ee->ee_cornerCal.pd84 = 1;1420ee->ee_cornerCal.gSel = 0;14211422/*1423* Read the conformance test limit identifiers1424* These are used to match regulatory domain testing needs with1425* the RD-specific tests that have been calibrated in the EEPROM.1426*/1427off = header[5];1428for (i = 0; i < ee->ee_numCtls; i += 2) {1429EEREAD(off++);1430ee->ee_ctl[i] = (eeval >> 8) & 0xff;1431ee->ee_ctl[i+1] = eeval & 0xff;1432}14331434if (ee->ee_version < AR_EEPROM_VER5_3) {1435/* XXX only for 5413? */1436ee->ee_spurChans[0][1] = AR_SPUR_5413_1;1437ee->ee_spurChans[1][1] = AR_SPUR_5413_2;1438ee->ee_spurChans[2][1] = AR_NO_SPUR;1439ee->ee_spurChans[0][0] = AR_NO_SPUR;1440} else {1441/* Read spur mitigation data */1442for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {1443EEREAD(off);1444ee->ee_spurChans[i][0] = eeval;1445EEREAD(off+AR_EEPROM_MODAL_SPURS);1446ee->ee_spurChans[i][1] = eeval;1447off++;1448}1449}14501451/* for recent changes to NF scale */1452if (ee->ee_version <= AR_EEPROM_VER3_2) {1453ee->ee_noiseFloorThresh[headerInfo11A] = -54;1454ee->ee_noiseFloorThresh[headerInfo11B] = -1;1455ee->ee_noiseFloorThresh[headerInfo11G] = -1;1456}1457/* to override thresh62 for better 2.4 and 5 operation */1458if (ee->ee_version <= AR_EEPROM_VER3_2) {1459ee->ee_thresh62[headerInfo11A] = 15; /* 11A */1460ee->ee_thresh62[headerInfo11B] = 28; /* 11B */1461ee->ee_thresh62[headerInfo11G] = 28; /* 11G */1462}14631464/* Check for regulatory capabilities */1465if (ee->ee_version >= AR_EEPROM_VER4_0) {1466EEREAD(regCapOffsetPost4_0);1467} else {1468EEREAD(regCapOffsetPre4_0);1469}14701471ee->ee_regCap = eeval;14721473if (ee->ee_Amode == 0) {1474/* Check for valid Amode in upgraded h/w */1475if (ee->ee_version >= AR_EEPROM_VER4_0) {1476ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A)?1:0;1477} else {1478ee->ee_Amode = (ee->ee_regCap & AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0)?1:0;1479}1480}14811482if (ee->ee_version >= AR_EEPROM_VER5_1)1483EEREAD(AR_EEPROM_CAPABILITIES_OFFSET);1484else1485eeval = 0;1486ee->ee_opCap = eeval;14871488EEREAD(AR_EEPROM_REG_DOMAIN);1489ee->ee_regdomain = eeval;14901491return AH_TRUE;1492#undef EEREAD1493}14941495/*1496* Now verify and copy EEPROM contents into the allocated space1497*/1498static HAL_BOOL1499legacyEepromReadContents(struct ath_hal *ah, HAL_EEPROM *ee)1500{1501/* Read the header information here */1502if (!readHeaderInfo(ah, ee))1503return AH_FALSE;1504#if 01505/* Require 5112 devices to have EEPROM 4.0 EEP_MAP set */1506if (IS_5112(ah) && !ee->ee_eepMap) {1507HALDEBUG(ah, HAL_DEBUG_ANY,1508"%s: 5112 devices must have EEPROM 4.0 with the "1509"EEP_MAP set\n", __func__);1510return AH_FALSE;1511}1512#endif1513/*1514* Group 1: frequency pier locations readback1515* check that the structure has been populated1516* with enough space to hold the channels1517*1518* NOTE: Group 1 contains the 5 GHz channel numbers1519* that have dBm->pcdac calibrated information.1520*/1521if (!readEepromFreqPierInfo(ah, ee))1522return AH_FALSE;15231524/*1525* Group 2: readback data for all frequency piers1526*1527* NOTE: Group 2 contains the raw power calibration1528* information for each of the channels that we1529* recorded above.1530*/1531if (!readEepromRawPowerCalInfo(ah, ee))1532return AH_FALSE;15331534/*1535* Group 5: target power values per rate1536*1537* NOTE: Group 5 contains the recorded maximum power1538* in dB that can be attained for the given rate.1539*/1540/* Read the power per rate info for test channels */1541if (!readEepromTargetPowerCalInfo(ah, ee))1542return AH_FALSE;15431544/*1545* Group 8: Conformance Test Limits information1546*1547* NOTE: Group 8 contains the values to limit the1548* maximum transmit power value based on any1549* band edge violations.1550*/1551/* Read the RD edge power limits */1552return readEepromCTLInfo(ah, ee);1553}15541555static HAL_STATUS1556legacyEepromGet(struct ath_hal *ah, int param, void *val)1557{1558HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1559uint8_t *macaddr;1560uint16_t eeval;1561uint32_t sum;1562int i;15631564switch (param) {1565case AR_EEP_OPCAP:1566*(uint16_t *) val = ee->ee_opCap;1567return HAL_OK;1568case AR_EEP_REGDMN_0:1569*(uint16_t *) val = ee->ee_regdomain;1570return HAL_OK;1571case AR_EEP_RFSILENT:1572if (!ath_hal_eepromRead(ah, AR_EEPROM_RFSILENT, &eeval))1573return HAL_EEREAD;1574*(uint16_t *) val = eeval;1575return HAL_OK;1576case AR_EEP_MACADDR:1577sum = 0;1578macaddr = val;1579for (i = 0; i < 3; i++) {1580if (!ath_hal_eepromRead(ah, AR_EEPROM_MAC(2-i), &eeval)) {1581HALDEBUG(ah, HAL_DEBUG_ANY,1582"%s: cannot read EEPROM location %u\n",1583__func__, i);1584return HAL_EEREAD;1585}1586sum += eeval;1587macaddr[2*i] = eeval >> 8;1588macaddr[2*i + 1] = eeval & 0xff;1589}1590if (sum == 0 || sum == 0xffff*3) {1591HALDEBUG(ah, HAL_DEBUG_ANY,1592"%s: mac address read failed: %s\n", __func__,1593ath_hal_ether_sprintf(macaddr));1594return HAL_EEBADMAC;1595}1596return HAL_OK;1597case AR_EEP_RFKILL:1598HALASSERT(val == AH_NULL);1599return ee->ee_rfKill ? HAL_OK : HAL_EIO;1600case AR_EEP_AMODE:1601HALASSERT(val == AH_NULL);1602return ee->ee_Amode ? HAL_OK : HAL_EIO;1603case AR_EEP_BMODE:1604HALASSERT(val == AH_NULL);1605return ee->ee_Bmode ? HAL_OK : HAL_EIO;1606case AR_EEP_GMODE:1607HALASSERT(val == AH_NULL);1608return ee->ee_Gmode ? HAL_OK : HAL_EIO;1609case AR_EEP_TURBO5DISABLE:1610HALASSERT(val == AH_NULL);1611return ee->ee_turbo5Disable ? HAL_OK : HAL_EIO;1612case AR_EEP_TURBO2DISABLE:1613HALASSERT(val == AH_NULL);1614return ee->ee_turbo2Disable ? HAL_OK : HAL_EIO;1615case AR_EEP_ISTALON: /* Talon detect */1616HALASSERT(val == AH_NULL);1617return (ee->ee_version >= AR_EEPROM_VER5_4 &&1618ath_hal_eepromRead(ah, 0x0b, &eeval) && eeval == 1) ?1619HAL_OK : HAL_EIO;1620case AR_EEP_32KHZCRYSTAL:1621HALASSERT(val == AH_NULL);1622return ee->ee_exist32kHzCrystal ? HAL_OK : HAL_EIO;1623case AR_EEP_COMPRESS:1624HALASSERT(val == AH_NULL);1625return (ee->ee_opCap & AR_EEPROM_EEPCAP_COMPRESS_DIS) == 0 ?1626HAL_OK : HAL_EIO;1627case AR_EEP_FASTFRAME:1628HALASSERT(val == AH_NULL);1629return (ee->ee_opCap & AR_EEPROM_EEPCAP_FASTFRAME_DIS) == 0 ?1630HAL_OK : HAL_EIO;1631case AR_EEP_AES:1632HALASSERT(val == AH_NULL);1633return (ee->ee_opCap & AR_EEPROM_EEPCAP_AES_DIS) == 0 ?1634HAL_OK : HAL_EIO;1635case AR_EEP_BURST:1636HALASSERT(val == AH_NULL);1637return (ee->ee_opCap & AR_EEPROM_EEPCAP_BURST_DIS) == 0 ?1638HAL_OK : HAL_EIO;1639case AR_EEP_MAXQCU:1640if (ee->ee_opCap & AR_EEPROM_EEPCAP_MAXQCU) {1641*(uint16_t *) val =1642MS(ee->ee_opCap, AR_EEPROM_EEPCAP_MAXQCU);1643return HAL_OK;1644} else1645return HAL_EIO;1646case AR_EEP_KCENTRIES:1647if (ee->ee_opCap & AR_EEPROM_EEPCAP_KC_ENTRIES) {1648*(uint16_t *) val =16491 << MS(ee->ee_opCap, AR_EEPROM_EEPCAP_KC_ENTRIES);1650return HAL_OK;1651} else1652return HAL_EIO;1653case AR_EEP_ANTGAINMAX_5:1654*(int8_t *) val = ee->ee_antennaGainMax[0];1655return HAL_OK;1656case AR_EEP_ANTGAINMAX_2:1657*(int8_t *) val = ee->ee_antennaGainMax[1];1658return HAL_OK;1659case AR_EEP_WRITEPROTECT:1660HALASSERT(val == AH_NULL);1661return (ee->ee_protect & AR_EEPROM_PROTECT_WP_128_191) ?1662HAL_OK : HAL_EIO;1663}1664return HAL_EINVAL;1665}16661667static HAL_STATUS1668legacyEepromSet(struct ath_hal *ah, int param, int v)1669{1670HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;16711672switch (param) {1673case AR_EEP_AMODE:1674ee->ee_Amode = v;1675return HAL_OK;1676case AR_EEP_BMODE:1677ee->ee_Bmode = v;1678return HAL_OK;1679case AR_EEP_GMODE:1680ee->ee_Gmode = v;1681return HAL_OK;1682case AR_EEP_TURBO5DISABLE:1683ee->ee_turbo5Disable = v;1684return HAL_OK;1685case AR_EEP_TURBO2DISABLE:1686ee->ee_turbo2Disable = v;1687return HAL_OK;1688case AR_EEP_COMPRESS:1689if (v)1690ee->ee_opCap &= ~AR_EEPROM_EEPCAP_COMPRESS_DIS;1691else1692ee->ee_opCap |= AR_EEPROM_EEPCAP_COMPRESS_DIS;1693return HAL_OK;1694case AR_EEP_FASTFRAME:1695if (v)1696ee->ee_opCap &= ~AR_EEPROM_EEPCAP_FASTFRAME_DIS;1697else1698ee->ee_opCap |= AR_EEPROM_EEPCAP_FASTFRAME_DIS;1699return HAL_OK;1700case AR_EEP_AES:1701if (v)1702ee->ee_opCap &= ~AR_EEPROM_EEPCAP_AES_DIS;1703else1704ee->ee_opCap |= AR_EEPROM_EEPCAP_AES_DIS;1705return HAL_OK;1706case AR_EEP_BURST:1707if (v)1708ee->ee_opCap &= ~AR_EEPROM_EEPCAP_BURST_DIS;1709else1710ee->ee_opCap |= AR_EEPROM_EEPCAP_BURST_DIS;1711return HAL_OK;1712}1713return HAL_EINVAL;1714}17151716static HAL_BOOL1717legacyEepromDiag(struct ath_hal *ah, int request,1718const void *args, uint32_t argsize, void **result, uint32_t *resultsize)1719{1720HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1721const EEPROM_POWER_EXPN_5112 *pe;17221723switch (request) {1724case HAL_DIAG_EEPROM:1725*result = ee;1726*resultsize = sizeof(*ee);1727return AH_TRUE;1728case HAL_DIAG_EEPROM_EXP_11A:1729case HAL_DIAG_EEPROM_EXP_11B:1730case HAL_DIAG_EEPROM_EXP_11G:1731pe = &ee->ee_modePowerArray5112[1732request - HAL_DIAG_EEPROM_EXP_11A];1733*result = pe->pChannels;1734*resultsize = (*result == AH_NULL) ? 0 :1735roundup(sizeof(uint16_t) * pe->numChannels,1736sizeof(uint32_t)) +1737sizeof(EXPN_DATA_PER_CHANNEL_5112) * pe->numChannels;1738return AH_TRUE;1739}1740return AH_FALSE;1741}17421743static uint16_t1744legacyEepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz)1745{1746HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;17471748HALASSERT(0 <= ix && ix < AR_EEPROM_MODAL_SPURS);1749return ee->ee_spurChans[ix][is2GHz];1750}17511752/*1753* Reclaim any EEPROM-related storage.1754*/1755static void1756legacyEepromDetach(struct ath_hal *ah)1757{1758HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;17591760if (ee->ee_version >= AR_EEPROM_VER4_0 && ee->ee_eepMap == 1)1761freeEepromRawPowerCalInfo5112(ah, ee);1762ath_hal_free(ee);1763AH_PRIVATE(ah)->ah_eeprom = AH_NULL;1764}17651766/*1767* These are not valid 2.4 channels, either we change 'em1768* or we need to change the coding to accept them.1769*/1770static const uint16_t channels11b[] = { 2412, 2447, 2484 };1771static const uint16_t channels11g[] = { 2312, 2412, 2484 };17721773HAL_STATUS1774ath_hal_legacyEepromAttach(struct ath_hal *ah)1775{1776HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1777uint32_t sum, eepMax;1778uint16_t eeversion, eeprotect, eeval;1779u_int i;17801781HALASSERT(ee == AH_NULL);17821783if (!ath_hal_eepromRead(ah, AR_EEPROM_VERSION, &eeversion)) {1784HALDEBUG(ah, HAL_DEBUG_ANY,1785"%s: unable to read EEPROM version\n", __func__);1786return HAL_EEREAD;1787}1788if (eeversion < AR_EEPROM_VER3) {1789HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM version "1790"%u (0x%x) found\n", __func__, eeversion, eeversion);1791return HAL_EEVERSION;1792}17931794if (!ath_hal_eepromRead(ah, AR_EEPROM_PROTECT, &eeprotect)) {1795HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cannot read EEPROM protection "1796"bits; read locked?\n", __func__);1797return HAL_EEREAD;1798}1799HALDEBUG(ah, HAL_DEBUG_ATTACH, "EEPROM protect 0x%x\n", eeprotect);1800/* XXX check proper access before continuing */18011802/*1803* Read the Atheros EEPROM entries and calculate the checksum.1804*/1805if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_UPPER, &eeval)) {1806HALDEBUG(ah, HAL_DEBUG_ANY,1807"%s: cannot read EEPROM upper size\n" , __func__);1808return HAL_EEREAD;1809}1810if (eeval != 0) {1811eepMax = (eeval & AR_EEPROM_SIZE_UPPER_MASK) <<1812AR_EEPROM_SIZE_ENDLOC_SHIFT;1813if (!ath_hal_eepromRead(ah, AR_EEPROM_SIZE_LOWER, &eeval)) {1814HALDEBUG(ah, HAL_DEBUG_ANY,1815"%s: cannot read EEPROM lower size\n" , __func__);1816return HAL_EEREAD;1817}1818eepMax = (eepMax | eeval) - AR_EEPROM_ATHEROS_BASE;1819} else1820eepMax = AR_EEPROM_ATHEROS_MAX;1821sum = 0;1822for (i = 0; i < eepMax; i++) {1823if (!ath_hal_eepromRead(ah, AR_EEPROM_ATHEROS(i), &eeval)) {1824return HAL_EEREAD;1825}1826sum ^= eeval;1827}1828if (sum != 0xffff) {1829HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad EEPROM checksum 0x%x\n",1830__func__, sum);1831return HAL_EEBADSUM;1832}18331834ee = ath_hal_malloc(sizeof(HAL_EEPROM));1835if (ee == AH_NULL) {1836/* XXX message */1837return HAL_ENOMEM;1838}18391840ee->ee_protect = eeprotect;1841ee->ee_version = eeversion;18421843ee->ee_numChannels11a = NUM_11A_EEPROM_CHANNELS;1844ee->ee_numChannels2_4 = NUM_2_4_EEPROM_CHANNELS;18451846for (i = 0; i < NUM_11A_EEPROM_CHANNELS; i ++)1847ee->ee_dataPerChannel11a[i].numPcdacValues = NUM_PCDAC_VALUES;18481849/* the channel list for 2.4 is fixed, fill this in here */1850for (i = 0; i < NUM_2_4_EEPROM_CHANNELS; i++) {1851ee->ee_channels11b[i] = channels11b[i];1852/* XXX 5211 requires a hack though we don't support 11g */1853if (ah->ah_magic == 0x19570405)1854ee->ee_channels11g[i] = channels11b[i];1855else1856ee->ee_channels11g[i] = channels11g[i];1857ee->ee_dataPerChannel11b[i].numPcdacValues = NUM_PCDAC_VALUES;1858ee->ee_dataPerChannel11g[i].numPcdacValues = NUM_PCDAC_VALUES;1859}18601861if (!legacyEepromReadContents(ah, ee)) {1862/* XXX message */1863ath_hal_free(ee);1864return HAL_EEREAD; /* XXX */1865}18661867AH_PRIVATE(ah)->ah_eeprom = ee;1868AH_PRIVATE(ah)->ah_eeversion = eeversion;1869AH_PRIVATE(ah)->ah_eepromDetach = legacyEepromDetach;1870AH_PRIVATE(ah)->ah_eepromGet = legacyEepromGet;1871AH_PRIVATE(ah)->ah_eepromSet = legacyEepromSet;1872AH_PRIVATE(ah)->ah_getSpurChan = legacyEepromGetSpurChan;1873AH_PRIVATE(ah)->ah_eepromDiag = legacyEepromDiag;1874return HAL_OK;1875}187618771878