1185377Ssam/* 2185377Ssam * Copyright (c) 2008 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 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 * 17185906Ssam * $FreeBSD$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam#include "ah_eeprom_v14.h" 24185377Ssam 25185377Ssamstatic HAL_STATUS 26185377Ssamv14EepromGet(struct ath_hal *ah, int param, void *val) 27185377Ssam{ 28185377Ssam#define CHAN_A_IDX 0 29185377Ssam#define CHAN_B_IDX 1 30185377Ssam#define IS_VERS(op, v) ((pBase->version & AR5416_EEP_VER_MINOR_MASK) op (v)) 31185377Ssam HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 32185377Ssam const MODAL_EEP_HEADER *pModal = ee->ee_base.modalHeader; 33185377Ssam const BASE_EEP_HEADER *pBase = &ee->ee_base.baseEepHeader; 34185377Ssam uint32_t sum; 35185377Ssam uint8_t *macaddr; 36185377Ssam int i; 37185377Ssam 38185377Ssam switch (param) { 39185377Ssam case AR_EEP_NFTHRESH_5: 40185380Ssam *(int16_t *)val = pModal[0].noiseFloorThreshCh[0]; 41185377Ssam return HAL_OK; 42185377Ssam case AR_EEP_NFTHRESH_2: 43185380Ssam *(int16_t *)val = pModal[1].noiseFloorThreshCh[0]; 44185377Ssam return HAL_OK; 45185377Ssam case AR_EEP_MACADDR: /* Get MAC Address */ 46185377Ssam sum = 0; 47185377Ssam macaddr = val; 48185377Ssam for (i = 0; i < 6; i++) { 49185377Ssam macaddr[i] = pBase->macAddr[i]; 50185377Ssam sum += pBase->macAddr[i]; 51185377Ssam } 52185377Ssam if (sum == 0 || sum == 0xffff*3) { 53185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n", 54185377Ssam __func__, ath_hal_ether_sprintf(macaddr)); 55185377Ssam return HAL_EEBADMAC; 56185377Ssam } 57185906Ssam return HAL_OK; 58185377Ssam case AR_EEP_REGDMN_0: 59185377Ssam return pBase->regDmn[0]; 60185377Ssam case AR_EEP_REGDMN_1: 61185377Ssam return pBase->regDmn[1]; 62185377Ssam case AR_EEP_OPCAP: 63185377Ssam return pBase->deviceCap; 64185377Ssam case AR_EEP_OPMODE: 65185377Ssam return pBase->opCapFlags; 66185377Ssam case AR_EEP_RFSILENT: 67185377Ssam return pBase->rfSilent; 68185377Ssam case AR_EEP_OB_5: 69185377Ssam return pModal[CHAN_A_IDX].ob; 70185377Ssam case AR_EEP_DB_5: 71185377Ssam return pModal[CHAN_A_IDX].db; 72185377Ssam case AR_EEP_OB_2: 73185377Ssam return pModal[CHAN_B_IDX].ob; 74185377Ssam case AR_EEP_DB_2: 75185377Ssam return pModal[CHAN_B_IDX].db; 76185377Ssam case AR_EEP_TXMASK: 77185377Ssam return pBase->txMask; 78185377Ssam case AR_EEP_RXMASK: 79185377Ssam return pBase->rxMask; 80185377Ssam case AR_EEP_RXGAIN_TYPE: 81185377Ssam return IS_VERS(>=, AR5416_EEP_MINOR_VER_17) ? 82185377Ssam pBase->rxGainType : AR5416_EEP_RXGAIN_ORIG; 83185377Ssam case AR_EEP_TXGAIN_TYPE: 84185377Ssam return IS_VERS(>=, AR5416_EEP_MINOR_VER_19) ? 85185377Ssam pBase->txGainType : AR5416_EEP_TXGAIN_ORIG; 86185377Ssam case AR_EEP_FSTCLK_5G: 87221897Sadrian /* 5ghz fastclock is always enabled for Merlin minor <= 16 */ 88221897Sadrian if (IS_VERS(<=, AR5416_EEP_MINOR_VER_16)) 89221897Sadrian return HAL_OK; 90221897Sadrian return pBase->fastClk5g ? HAL_OK : HAL_EIO; 91185377Ssam case AR_EEP_OL_PWRCTRL: 92185377Ssam HALASSERT(val == AH_NULL); 93185377Ssam return pBase->openLoopPwrCntl ? HAL_OK : HAL_EIO; 94217623Sadrian case AR_EEP_DAC_HPWR_5G: 95217623Sadrian if (IS_VERS(>=, AR5416_EEP_MINOR_VER_20)) { 96218419Sadrian *(uint8_t *) val = pBase->dacHiPwrMode_5G; 97217623Sadrian return HAL_OK; 98217623Sadrian } else 99217623Sadrian return HAL_EIO; 100224519Sadrian case AR_EEP_FRAC_N_5G: 101224519Sadrian if (IS_VERS(>=, AR5416_EEP_MINOR_VER_22)) { 102224519Sadrian *(uint8_t *) val = pBase->frac_n_5g; 103224519Sadrian } else 104224519Sadrian *(uint8_t *) val = 0; 105224519Sadrian return HAL_OK; 106185377Ssam case AR_EEP_AMODE: 107185377Ssam HALASSERT(val == AH_NULL); 108185377Ssam return pBase->opCapFlags & AR5416_OPFLAGS_11A ? 109185377Ssam HAL_OK : HAL_EIO; 110185377Ssam case AR_EEP_BMODE: 111185377Ssam case AR_EEP_GMODE: 112185377Ssam HALASSERT(val == AH_NULL); 113185377Ssam return pBase->opCapFlags & AR5416_OPFLAGS_11G ? 114185377Ssam HAL_OK : HAL_EIO; 115185377Ssam case AR_EEP_32KHZCRYSTAL: 116185377Ssam case AR_EEP_COMPRESS: 117185377Ssam case AR_EEP_FASTFRAME: /* XXX policy decision, h/w can do it */ 118185377Ssam case AR_EEP_WRITEPROTECT: /* NB: no write protect bit */ 119185377Ssam HALASSERT(val == AH_NULL); 120185377Ssam /* fall thru... */ 121185377Ssam case AR_EEP_MAXQCU: /* NB: not in opCapFlags */ 122185377Ssam case AR_EEP_KCENTRIES: /* NB: not in opCapFlags */ 123185377Ssam return HAL_EIO; 124185377Ssam case AR_EEP_AES: 125185377Ssam case AR_EEP_BURST: 126185377Ssam case AR_EEP_RFKILL: 127185377Ssam case AR_EEP_TURBO5DISABLE: 128185377Ssam case AR_EEP_TURBO2DISABLE: 129185377Ssam HALASSERT(val == AH_NULL); 130185377Ssam return HAL_OK; 131185377Ssam case AR_EEP_ANTGAINMAX_2: 132185377Ssam *(int8_t *) val = ee->ee_antennaGainMax[1]; 133185377Ssam return HAL_OK; 134185377Ssam case AR_EEP_ANTGAINMAX_5: 135185377Ssam *(int8_t *) val = ee->ee_antennaGainMax[0]; 136185377Ssam return HAL_OK; 137219318Sadrian case AR_EEP_PWR_TABLE_OFFSET: 138219318Sadrian if (IS_VERS(>=, AR5416_EEP_MINOR_VER_21)) 139219318Sadrian *(int8_t *) val = pBase->pwr_table_offset; 140219318Sadrian else 141219318Sadrian *(int8_t *) val = AR5416_PWR_TABLE_OFFSET_DB; 142219318Sadrian return HAL_OK; 143219441Sadrian case AR_EEP_PWDCLKIND: 144219441Sadrian if (IS_VERS(>=, AR5416_EEP_MINOR_VER_10)) { 145219441Sadrian *(uint8_t *) val = pBase->pwdclkind; 146219441Sadrian return HAL_OK; 147219441Sadrian } 148219441Sadrian return HAL_EIO; 149219318Sadrian 150185377Ssam default: 151185377Ssam HALASSERT(0); 152185377Ssam return HAL_EINVAL; 153185377Ssam } 154185377Ssam#undef IS_VERS 155185377Ssam#undef CHAN_A_IDX 156185377Ssam#undef CHAN_B_IDX 157185377Ssam} 158185377Ssam 159221896Sadrianstatic HAL_STATUS 160185377Ssamv14EepromSet(struct ath_hal *ah, int param, int v) 161185377Ssam{ 162185377Ssam HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 163185377Ssam 164185377Ssam switch (param) { 165185377Ssam case AR_EEP_ANTGAINMAX_2: 166185377Ssam ee->ee_antennaGainMax[1] = (int8_t) v; 167185377Ssam return HAL_OK; 168185377Ssam case AR_EEP_ANTGAINMAX_5: 169185377Ssam ee->ee_antennaGainMax[0] = (int8_t) v; 170185377Ssam return HAL_OK; 171185377Ssam } 172185377Ssam return HAL_EINVAL; 173185377Ssam} 174185377Ssam 175185377Ssamstatic HAL_BOOL 176185377Ssamv14EepromDiag(struct ath_hal *ah, int request, 177185377Ssam const void *args, uint32_t argsize, void **result, uint32_t *resultsize) 178185377Ssam{ 179185377Ssam HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 180185377Ssam 181185377Ssam switch (request) { 182185377Ssam case HAL_DIAG_EEPROM: 183217685Sadrian *result = ee; 184217685Sadrian *resultsize = sizeof(HAL_EEPROM_v14); 185185377Ssam return AH_TRUE; 186185377Ssam } 187185377Ssam return AH_FALSE; 188185377Ssam} 189185377Ssam 190185377Ssam/* Do structure specific swaps if Eeprom format is non native to host */ 191185377Ssamstatic void 192185377SsameepromSwap(struct ar5416eeprom *ee) 193185377Ssam{ 194185377Ssam uint32_t integer, i, j; 195185377Ssam uint16_t word; 196185377Ssam MODAL_EEP_HEADER *pModal; 197185377Ssam 198185377Ssam /* convert Base Eep header */ 199185377Ssam word = __bswap16(ee->baseEepHeader.length); 200185377Ssam ee->baseEepHeader.length = word; 201185377Ssam 202185377Ssam word = __bswap16(ee->baseEepHeader.checksum); 203185377Ssam ee->baseEepHeader.checksum = word; 204185377Ssam 205185377Ssam word = __bswap16(ee->baseEepHeader.version); 206185377Ssam ee->baseEepHeader.version = word; 207185377Ssam 208185377Ssam word = __bswap16(ee->baseEepHeader.regDmn[0]); 209185377Ssam ee->baseEepHeader.regDmn[0] = word; 210185377Ssam 211185377Ssam word = __bswap16(ee->baseEepHeader.regDmn[1]); 212185377Ssam ee->baseEepHeader.regDmn[1] = word; 213185377Ssam 214185377Ssam word = __bswap16(ee->baseEepHeader.rfSilent); 215185377Ssam ee->baseEepHeader.rfSilent = word; 216185377Ssam 217185377Ssam word = __bswap16(ee->baseEepHeader.blueToothOptions); 218185377Ssam ee->baseEepHeader.blueToothOptions = word; 219185377Ssam 220185377Ssam word = __bswap16(ee->baseEepHeader.deviceCap); 221185377Ssam ee->baseEepHeader.deviceCap = word; 222185377Ssam 223185377Ssam /* convert Modal Eep header */ 224185377Ssam for (j = 0; j < 2; j++) { 225185377Ssam pModal = &ee->modalHeader[j]; 226185377Ssam 227185377Ssam /* XXX linux/ah_osdep.h only defines __bswap32 for BE */ 228185377Ssam integer = __bswap32(pModal->antCtrlCommon); 229185377Ssam pModal->antCtrlCommon = integer; 230185377Ssam 231185377Ssam for (i = 0; i < AR5416_MAX_CHAINS; i++) { 232185377Ssam integer = __bswap32(pModal->antCtrlChain[i]); 233185377Ssam pModal->antCtrlChain[i] = integer; 234185377Ssam } 235220360Sadrian for (i = 0; i < 3; i++) { 236220360Sadrian word = __bswap16(pModal->xpaBiasLvlFreq[i]); 237220360Sadrian pModal->xpaBiasLvlFreq[i] = word; 238220360Sadrian } 239185377Ssam for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { 240185377Ssam word = __bswap16(pModal->spurChans[i].spurChan); 241185377Ssam pModal->spurChans[i].spurChan = word; 242185377Ssam } 243185377Ssam } 244185377Ssam} 245185377Ssam 246185377Ssamstatic uint16_t 247185377Ssamv14EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz) 248185377Ssam{ 249185377Ssam HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 250185377Ssam 251185377Ssam HALASSERT(0 <= ix && ix < AR5416_EEPROM_MODAL_SPURS); 252185377Ssam return ee->ee_base.modalHeader[is2GHz].spurChans[ix].spurChan; 253185377Ssam} 254185377Ssam 255185377Ssam/************************************************************************** 256185377Ssam * fbin2freq 257185377Ssam * 258185377Ssam * Get channel value from binary representation held in eeprom 259185377Ssam * RETURNS: the frequency in MHz 260185377Ssam */ 261185377Ssamstatic uint16_t 262185377Ssamfbin2freq(uint8_t fbin, HAL_BOOL is2GHz) 263185377Ssam{ 264185377Ssam /* 265185377Ssam * Reserved value 0xFF provides an empty definition both as 266185377Ssam * an fbin and as a frequency - do not convert 267185377Ssam */ 268185377Ssam if (fbin == AR5416_BCHAN_UNUSED) 269185377Ssam return fbin; 270185377Ssam return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); 271185377Ssam} 272185377Ssam 273185377Ssam/* 274185377Ssam * Copy EEPROM Conformance Testing Limits contents 275185377Ssam * into the allocated space 276185377Ssam */ 277185377Ssam/* USE CTLS from chain zero */ 278185377Ssam#define CTL_CHAIN 0 279185377Ssam 280185377Ssamstatic void 281185377Ssamv14EepromReadCTLInfo(struct ath_hal *ah, HAL_EEPROM_v14 *ee) 282185377Ssam{ 283185377Ssam RD_EDGES_POWER *rep = ee->ee_rdEdgesPower; 284185377Ssam int i, j; 285185377Ssam 286185377Ssam HALASSERT(AR5416_NUM_CTLS <= sizeof(ee->ee_rdEdgesPower)/NUM_EDGES); 287185377Ssam 288185377Ssam for (i = 0; ee->ee_base.ctlIndex[i] != 0 && i < AR5416_NUM_CTLS; i++) { 289185377Ssam for (j = 0; j < NUM_EDGES; j ++) { 290185377Ssam /* XXX Confirm this is the right thing to do when an invalid channel is stored */ 291185377Ssam if (ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel == AR5416_BCHAN_UNUSED) { 292185377Ssam rep[j].rdEdge = 0; 293185377Ssam rep[j].twice_rdEdgePower = 0; 294185377Ssam rep[j].flag = 0; 295185377Ssam } else { 296185377Ssam rep[j].rdEdge = fbin2freq( 297185377Ssam ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel, 298185377Ssam (ee->ee_base.ctlIndex[i] & CTL_MODE_M) != CTL_11A); 299185377Ssam rep[j].twice_rdEdgePower = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_POWER); 300185377Ssam rep[j].flag = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_FLAG) != 0; 301185377Ssam } 302185377Ssam } 303185377Ssam rep += NUM_EDGES; 304185377Ssam } 305185377Ssam ee->ee_numCtls = i; 306185377Ssam HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, 307185377Ssam "%s Numctls = %u\n",__func__,i); 308185377Ssam} 309185377Ssam 310185377Ssam/* 311185377Ssam * Reclaim any EEPROM-related storage. 312185377Ssam */ 313185377Ssamstatic void 314185377Ssamv14EepromDetach(struct ath_hal *ah) 315185377Ssam{ 316185377Ssam HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 317185377Ssam 318185377Ssam ath_hal_free(ee); 319185377Ssam AH_PRIVATE(ah)->ah_eeprom = AH_NULL; 320185377Ssam} 321185377Ssam 322185377Ssam#define owl_get_eep_ver(_ee) \ 323185377Ssam (((_ee)->ee_base.baseEepHeader.version >> 12) & 0xF) 324185377Ssam#define owl_get_eep_rev(_ee) \ 325185377Ssam (((_ee)->ee_base.baseEepHeader.version) & 0xFFF) 326185377Ssam 327221163Sadrian/* 328221163Sadrian * Howl is (hopefully) a special case where the endian-ness of the EEPROM 329221163Sadrian * matches the native endian-ness; and that supplied EEPROMs don't have 330221163Sadrian * a magic value to check. 331221163Sadrian */ 332185377SsamHAL_STATUS 333185377Ssamath_hal_v14EepromAttach(struct ath_hal *ah) 334185377Ssam{ 335185377Ssam#define NW(a) (sizeof(a) / sizeof(uint16_t)) 336185377Ssam HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 337185377Ssam uint16_t *eep_data, magic; 338185377Ssam HAL_BOOL need_swap; 339185377Ssam u_int w, off, len; 340185377Ssam uint32_t sum; 341185377Ssam 342185377Ssam HALASSERT(ee == AH_NULL); 343185377Ssam 344221163Sadrian /* 345221163Sadrian * Don't check magic if we're supplied with an EEPROM block, 346221163Sadrian * typically this is from Howl but it may also be from later 347221163Sadrian * boards w/ an embedded Merlin. 348221163Sadrian */ 349221163Sadrian if (ah->ah_eepromdata == NULL) { 350221163Sadrian if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { 351221163Sadrian HALDEBUG(ah, HAL_DEBUG_ANY, 352221163Sadrian "%s Error reading Eeprom MAGIC\n", __func__); 353221163Sadrian return HAL_EEREAD; 354221163Sadrian } 355221163Sadrian HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n", 356221163Sadrian __func__, magic); 357221163Sadrian if (magic != AR5416_EEPROM_MAGIC) { 358221163Sadrian HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n"); 359221163Sadrian return HAL_EEMAGIC; 360221163Sadrian } 361185377Ssam } 362185377Ssam 363185377Ssam ee = ath_hal_malloc(sizeof(HAL_EEPROM_v14)); 364185377Ssam if (ee == AH_NULL) { 365185377Ssam /* XXX message */ 366185377Ssam return HAL_ENOMEM; 367185377Ssam } 368185377Ssam 369185377Ssam eep_data = (uint16_t *)&ee->ee_base; 370185377Ssam for (w = 0; w < NW(struct ar5416eeprom); w++) { 371185377Ssam off = owl_eep_start_loc + w; /* NB: AP71 starts at 0 */ 372185377Ssam if (!ath_hal_eepromRead(ah, off, &eep_data[w])) { 373185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 374185377Ssam "%s eeprom read error at offset 0x%x\n", 375185377Ssam __func__, off); 376185377Ssam return HAL_EEREAD; 377185377Ssam } 378185377Ssam } 379185377Ssam /* Convert to eeprom native eeprom endian format */ 380221163Sadrian /* XXX this is likely incorrect but will do for now to get howl/ap83 working. */ 381221163Sadrian if (ah->ah_eepromdata == NULL && isBigEndian()) { 382185377Ssam for (w = 0; w < NW(struct ar5416eeprom); w++) 383185377Ssam eep_data[w] = __bswap16(eep_data[w]); 384185377Ssam } 385185377Ssam 386185377Ssam /* 387185377Ssam * At this point, we're in the native eeprom endian format 388185377Ssam * Now, determine the eeprom endian by looking at byte 26?? 389185377Ssam */ 390185377Ssam need_swap = ((ee->ee_base.baseEepHeader.eepMisc & AR5416_EEPMISC_BIG_ENDIAN) != 0) ^ isBigEndian(); 391185377Ssam if (need_swap) { 392185377Ssam HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, 393185377Ssam "Byte swap EEPROM contents.\n"); 394185377Ssam len = __bswap16(ee->ee_base.baseEepHeader.length); 395185377Ssam } else { 396185377Ssam len = ee->ee_base.baseEepHeader.length; 397185377Ssam } 398185377Ssam len = AH_MIN(len, sizeof(struct ar5416eeprom)) / sizeof(uint16_t); 399185377Ssam 400185377Ssam /* Apply the checksum, done in native eeprom format */ 401185377Ssam /* XXX - Need to check to make sure checksum calculation is done 402185377Ssam * in the correct endian format. Right now, it seems it would 403185377Ssam * cast the raw data to host format and do the calculation, which may 404185377Ssam * not be correct as the calculation may need to be done in the native 405185377Ssam * eeprom format 406185377Ssam */ 407185377Ssam sum = 0; 408185377Ssam for (w = 0; w < len; w++) 409185377Ssam sum ^= eep_data[w]; 410185377Ssam /* Check CRC - Attach should fail on a bad checksum */ 411185377Ssam if (sum != 0xffff) { 412185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 413185377Ssam "Bad EEPROM checksum 0x%x (Len=%u)\n", sum, len); 414185377Ssam return HAL_EEBADSUM; 415185377Ssam } 416185377Ssam 417185377Ssam if (need_swap) 418185377Ssam eepromSwap(&ee->ee_base); /* byte swap multi-byte data */ 419185377Ssam 420185377Ssam /* swap words 0+2 so version is at the front */ 421185377Ssam magic = eep_data[0]; 422185377Ssam eep_data[0] = eep_data[2]; 423185377Ssam eep_data[2] = magic; 424185377Ssam 425185377Ssam HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, 426185377Ssam "%s Eeprom Version %u.%u\n", __func__, 427185377Ssam owl_get_eep_ver(ee), owl_get_eep_rev(ee)); 428185377Ssam 429185377Ssam /* NB: must be after all byte swapping */ 430185377Ssam if (owl_get_eep_ver(ee) != AR5416_EEP_VER) { 431185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 432185377Ssam "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee)); 433185377Ssam return HAL_EEBADSUM; 434185377Ssam } 435185377Ssam 436185377Ssam v14EepromReadCTLInfo(ah, ee); /* Get CTLs */ 437185377Ssam 438185377Ssam AH_PRIVATE(ah)->ah_eeprom = ee; 439185377Ssam AH_PRIVATE(ah)->ah_eeversion = ee->ee_base.baseEepHeader.version; 440185377Ssam AH_PRIVATE(ah)->ah_eepromDetach = v14EepromDetach; 441185377Ssam AH_PRIVATE(ah)->ah_eepromGet = v14EepromGet; 442185377Ssam AH_PRIVATE(ah)->ah_eepromSet = v14EepromSet; 443185377Ssam AH_PRIVATE(ah)->ah_getSpurChan = v14EepromGetSpurChan; 444185377Ssam AH_PRIVATE(ah)->ah_eepromDiag = v14EepromDiag; 445185377Ssam return HAL_OK; 446185377Ssam#undef NW 447185377Ssam} 448