1 1.1 alc /* 2 1.1 alc * Copyright (c) 2008 Sam Leffler, Errno Consulting 3 1.1 alc * Copyright (c) 2008 Atheros Communications, Inc. 4 1.1 alc * 5 1.1 alc * Permission to use, copy, modify, and/or distribute this software for any 6 1.1 alc * purpose with or without fee is hereby granted, provided that the above 7 1.1 alc * copyright notice and this permission notice appear in all copies. 8 1.1 alc * 9 1.1 alc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 1.1 alc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 1.1 alc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 1.1 alc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 1.1 alc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 1.1 alc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 1.1 alc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 1.1 alc * 17 1.7 mrg * $Id: ah_eeprom_v14.c,v 1.7 2021/04/13 03:27:13 mrg Exp $ 18 1.1 alc */ 19 1.1 alc #include "opt_ah.h" 20 1.1 alc 21 1.1 alc #include "ah.h" 22 1.1 alc #include "ah_internal.h" 23 1.1 alc #include "ah_eeprom_v14.h" 24 1.1 alc 25 1.1 alc static HAL_STATUS 26 1.1 alc v14EepromGet(struct ath_hal *ah, int param, void *val) 27 1.1 alc { 28 1.1 alc #define CHAN_A_IDX 0 29 1.1 alc #define CHAN_B_IDX 1 30 1.1 alc #define IS_VERS(op, v) ((pBase->version & AR5416_EEP_VER_MINOR_MASK) op (v)) 31 1.1 alc HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 32 1.1 alc const MODAL_EEP_HEADER *pModal = ee->ee_base.modalHeader; 33 1.1 alc const BASE_EEP_HEADER *pBase = &ee->ee_base.baseEepHeader; 34 1.1 alc uint32_t sum; 35 1.1 alc uint8_t *macaddr; 36 1.1 alc int i; 37 1.1 alc 38 1.1 alc switch (param) { 39 1.1 alc case AR_EEP_NFTHRESH_5: 40 1.1 alc *(int16_t *)val = pModal[0].noiseFloorThreshCh[0]; 41 1.1 alc return HAL_OK; 42 1.1 alc case AR_EEP_NFTHRESH_2: 43 1.1 alc *(int16_t *)val = pModal[1].noiseFloorThreshCh[0]; 44 1.1 alc return HAL_OK; 45 1.1 alc case AR_EEP_MACADDR: /* Get MAC Address */ 46 1.1 alc sum = 0; 47 1.1 alc macaddr = val; 48 1.1 alc for (i = 0; i < 6; i++) { 49 1.1 alc macaddr[i] = pBase->macAddr[i]; 50 1.1 alc sum += pBase->macAddr[i]; 51 1.1 alc } 52 1.1 alc if (sum == 0 || sum == 0xffff*3) { 53 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad mac address %s\n", 54 1.1 alc __func__, ath_hal_ether_sprintf(macaddr)); 55 1.1 alc return HAL_EEBADMAC; 56 1.5 cegger } 57 1.5 cegger return HAL_OK; 58 1.1 alc case AR_EEP_REGDMN_0: 59 1.1 alc return pBase->regDmn[0]; 60 1.1 alc case AR_EEP_REGDMN_1: 61 1.1 alc return pBase->regDmn[1]; 62 1.1 alc case AR_EEP_OPCAP: 63 1.1 alc return pBase->deviceCap; 64 1.1 alc case AR_EEP_OPMODE: 65 1.1 alc return pBase->opCapFlags; 66 1.1 alc case AR_EEP_RFSILENT: 67 1.1 alc return pBase->rfSilent; 68 1.1 alc case AR_EEP_OB_5: 69 1.1 alc return pModal[CHAN_A_IDX].ob; 70 1.1 alc case AR_EEP_DB_5: 71 1.1 alc return pModal[CHAN_A_IDX].db; 72 1.1 alc case AR_EEP_OB_2: 73 1.1 alc return pModal[CHAN_B_IDX].ob; 74 1.1 alc case AR_EEP_DB_2: 75 1.1 alc return pModal[CHAN_B_IDX].db; 76 1.1 alc case AR_EEP_TXMASK: 77 1.1 alc return pBase->txMask; 78 1.1 alc case AR_EEP_RXMASK: 79 1.1 alc return pBase->rxMask; 80 1.1 alc case AR_EEP_RXGAIN_TYPE: 81 1.1 alc return IS_VERS(>=, AR5416_EEP_MINOR_VER_17) ? 82 1.1 alc pBase->rxGainType : AR5416_EEP_RXGAIN_ORIG; 83 1.1 alc case AR_EEP_TXGAIN_TYPE: 84 1.1 alc return IS_VERS(>=, AR5416_EEP_MINOR_VER_19) ? 85 1.1 alc pBase->txGainType : AR5416_EEP_TXGAIN_ORIG; 86 1.1 alc case AR_EEP_FSTCLK_5G: 87 1.1 alc return IS_VERS(>, AR5416_EEP_MINOR_VER_16) ? 88 1.1 alc pBase->fastClk5g : AH_TRUE; 89 1.1 alc case AR_EEP_OL_PWRCTRL: 90 1.1 alc HALASSERT(val == AH_NULL); 91 1.1 alc return pBase->openLoopPwrCntl ? HAL_OK : HAL_EIO; 92 1.1 alc case AR_EEP_AMODE: 93 1.1 alc HALASSERT(val == AH_NULL); 94 1.1 alc return pBase->opCapFlags & AR5416_OPFLAGS_11A ? 95 1.1 alc HAL_OK : HAL_EIO; 96 1.1 alc case AR_EEP_BMODE: 97 1.1 alc case AR_EEP_GMODE: 98 1.1 alc HALASSERT(val == AH_NULL); 99 1.1 alc return pBase->opCapFlags & AR5416_OPFLAGS_11G ? 100 1.1 alc HAL_OK : HAL_EIO; 101 1.1 alc case AR_EEP_32KHZCRYSTAL: 102 1.1 alc case AR_EEP_COMPRESS: 103 1.1 alc case AR_EEP_FASTFRAME: /* XXX policy decision, h/w can do it */ 104 1.1 alc case AR_EEP_WRITEPROTECT: /* NB: no write protect bit */ 105 1.1 alc HALASSERT(val == AH_NULL); 106 1.1 alc /* fall thru... */ 107 1.1 alc case AR_EEP_MAXQCU: /* NB: not in opCapFlags */ 108 1.1 alc case AR_EEP_KCENTRIES: /* NB: not in opCapFlags */ 109 1.1 alc return HAL_EIO; 110 1.1 alc case AR_EEP_AES: 111 1.1 alc case AR_EEP_BURST: 112 1.1 alc case AR_EEP_RFKILL: 113 1.1 alc case AR_EEP_TURBO5DISABLE: 114 1.1 alc case AR_EEP_TURBO2DISABLE: 115 1.1 alc HALASSERT(val == AH_NULL); 116 1.1 alc return HAL_OK; 117 1.1 alc case AR_EEP_ANTGAINMAX_2: 118 1.1 alc *(int8_t *) val = ee->ee_antennaGainMax[1]; 119 1.1 alc return HAL_OK; 120 1.1 alc case AR_EEP_ANTGAINMAX_5: 121 1.1 alc *(int8_t *) val = ee->ee_antennaGainMax[0]; 122 1.1 alc return HAL_OK; 123 1.1 alc default: 124 1.1 alc HALASSERT(0); 125 1.1 alc return HAL_EINVAL; 126 1.1 alc } 127 1.1 alc #undef IS_VERS 128 1.1 alc #undef CHAN_A_IDX 129 1.1 alc #undef CHAN_B_IDX 130 1.1 alc } 131 1.1 alc 132 1.1 alc static HAL_BOOL 133 1.1 alc v14EepromSet(struct ath_hal *ah, int param, int v) 134 1.1 alc { 135 1.1 alc HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 136 1.1 alc 137 1.1 alc switch (param) { 138 1.1 alc case AR_EEP_ANTGAINMAX_2: 139 1.1 alc ee->ee_antennaGainMax[1] = (int8_t) v; 140 1.7 mrg return AH_TRUE; 141 1.1 alc case AR_EEP_ANTGAINMAX_5: 142 1.1 alc ee->ee_antennaGainMax[0] = (int8_t) v; 143 1.7 mrg return AH_TRUE; 144 1.1 alc } 145 1.7 mrg return AH_FALSE; 146 1.1 alc } 147 1.1 alc 148 1.1 alc static HAL_BOOL 149 1.1 alc v14EepromDiag(struct ath_hal *ah, int request, 150 1.1 alc const void *args, uint32_t argsize, void **result, uint32_t *resultsize) 151 1.1 alc { 152 1.1 alc HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 153 1.1 alc 154 1.1 alc switch (request) { 155 1.1 alc case HAL_DIAG_EEPROM: 156 1.1 alc *result = &ee->ee_base; 157 1.1 alc *resultsize = sizeof(ee->ee_base); 158 1.1 alc return AH_TRUE; 159 1.1 alc } 160 1.1 alc return AH_FALSE; 161 1.1 alc } 162 1.1 alc 163 1.1 alc /* Do structure specific swaps if Eeprom format is non native to host */ 164 1.1 alc static void 165 1.1 alc eepromSwap(struct ar5416eeprom *ee) 166 1.1 alc { 167 1.1 alc uint32_t integer, i, j; 168 1.1 alc uint16_t word; 169 1.1 alc MODAL_EEP_HEADER *pModal; 170 1.1 alc 171 1.1 alc /* convert Base Eep header */ 172 1.1 alc word = __bswap16(ee->baseEepHeader.length); 173 1.1 alc ee->baseEepHeader.length = word; 174 1.1 alc 175 1.1 alc word = __bswap16(ee->baseEepHeader.checksum); 176 1.1 alc ee->baseEepHeader.checksum = word; 177 1.1 alc 178 1.1 alc word = __bswap16(ee->baseEepHeader.version); 179 1.1 alc ee->baseEepHeader.version = word; 180 1.1 alc 181 1.1 alc word = __bswap16(ee->baseEepHeader.regDmn[0]); 182 1.1 alc ee->baseEepHeader.regDmn[0] = word; 183 1.1 alc 184 1.1 alc word = __bswap16(ee->baseEepHeader.regDmn[1]); 185 1.1 alc ee->baseEepHeader.regDmn[1] = word; 186 1.1 alc 187 1.1 alc word = __bswap16(ee->baseEepHeader.rfSilent); 188 1.1 alc ee->baseEepHeader.rfSilent = word; 189 1.1 alc 190 1.1 alc word = __bswap16(ee->baseEepHeader.blueToothOptions); 191 1.1 alc ee->baseEepHeader.blueToothOptions = word; 192 1.1 alc 193 1.1 alc word = __bswap16(ee->baseEepHeader.deviceCap); 194 1.1 alc ee->baseEepHeader.deviceCap = word; 195 1.1 alc 196 1.1 alc /* convert Modal Eep header */ 197 1.1 alc for (j = 0; j < 2; j++) { 198 1.1 alc pModal = &ee->modalHeader[j]; 199 1.1 alc 200 1.1 alc /* XXX linux/ah_osdep.h only defines __bswap32 for BE */ 201 1.1 alc integer = __bswap32(pModal->antCtrlCommon); 202 1.1 alc pModal->antCtrlCommon = integer; 203 1.1 alc 204 1.1 alc for (i = 0; i < AR5416_MAX_CHAINS; i++) { 205 1.1 alc integer = __bswap32(pModal->antCtrlChain[i]); 206 1.1 alc pModal->antCtrlChain[i] = integer; 207 1.1 alc } 208 1.1 alc 209 1.1 alc for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { 210 1.1 alc word = __bswap16(pModal->spurChans[i].spurChan); 211 1.1 alc pModal->spurChans[i].spurChan = word; 212 1.1 alc } 213 1.1 alc } 214 1.1 alc } 215 1.1 alc 216 1.1 alc static uint16_t 217 1.1 alc v14EepromGetSpurChan(struct ath_hal *ah, int ix, HAL_BOOL is2GHz) 218 1.1 alc { 219 1.1 alc HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 220 1.1 alc 221 1.1 alc HALASSERT(0 <= ix && ix < AR5416_EEPROM_MODAL_SPURS); 222 1.1 alc return ee->ee_base.modalHeader[is2GHz].spurChans[ix].spurChan; 223 1.1 alc } 224 1.1 alc 225 1.1 alc /************************************************************************** 226 1.1 alc * fbin2freq 227 1.1 alc * 228 1.1 alc * Get channel value from binary representation held in eeprom 229 1.1 alc * RETURNS: the frequency in MHz 230 1.1 alc */ 231 1.1 alc static uint16_t 232 1.1 alc fbin2freq(uint8_t fbin, HAL_BOOL is2GHz) 233 1.1 alc { 234 1.1 alc /* 235 1.1 alc * Reserved value 0xFF provides an empty definition both as 236 1.1 alc * an fbin and as a frequency - do not convert 237 1.1 alc */ 238 1.1 alc if (fbin == AR5416_BCHAN_UNUSED) 239 1.1 alc return fbin; 240 1.1 alc return (uint16_t)((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); 241 1.1 alc } 242 1.1 alc 243 1.1 alc /* 244 1.1 alc * Copy EEPROM Conformance Testing Limits contents 245 1.1 alc * into the allocated space 246 1.1 alc */ 247 1.1 alc /* USE CTLS from chain zero */ 248 1.1 alc #define CTL_CHAIN 0 249 1.1 alc 250 1.1 alc static void 251 1.1 alc v14EepromReadCTLInfo(struct ath_hal *ah, HAL_EEPROM_v14 *ee) 252 1.1 alc { 253 1.1 alc RD_EDGES_POWER *rep = ee->ee_rdEdgesPower; 254 1.1 alc int i, j; 255 1.1 alc 256 1.1 alc HALASSERT(AR5416_NUM_CTLS <= sizeof(ee->ee_rdEdgesPower)/NUM_EDGES); 257 1.1 alc 258 1.6 msaitoh for (i = 0; i < AR5416_NUM_CTLS && ee->ee_base.ctlIndex[i] != 0; i++) { 259 1.1 alc for (j = 0; j < NUM_EDGES; j ++) { 260 1.1 alc /* XXX Confirm this is the right thing to do when an invalid channel is stored */ 261 1.1 alc if (ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel == AR5416_BCHAN_UNUSED) { 262 1.1 alc rep[j].rdEdge = 0; 263 1.1 alc rep[j].twice_rdEdgePower = 0; 264 1.1 alc rep[j].flag = 0; 265 1.1 alc } else { 266 1.1 alc rep[j].rdEdge = fbin2freq( 267 1.1 alc ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].bChannel, 268 1.1 alc (ee->ee_base.ctlIndex[i] & CTL_MODE_M) != CTL_11A); 269 1.1 alc rep[j].twice_rdEdgePower = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_POWER); 270 1.1 alc rep[j].flag = MS(ee->ee_base.ctlData[i].ctlEdges[CTL_CHAIN][j].tPowerFlag, CAL_CTL_EDGES_FLAG) != 0; 271 1.1 alc } 272 1.1 alc } 273 1.1 alc rep += NUM_EDGES; 274 1.1 alc } 275 1.1 alc ee->ee_numCtls = i; 276 1.1 alc HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, 277 1.1 alc "%s Numctls = %u\n",__func__,i); 278 1.1 alc } 279 1.1 alc 280 1.1 alc /* 281 1.1 alc * Reclaim any EEPROM-related storage. 282 1.1 alc */ 283 1.1 alc static void 284 1.1 alc v14EepromDetach(struct ath_hal *ah) 285 1.1 alc { 286 1.1 alc HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 287 1.1 alc 288 1.1 alc ath_hal_free(ee); 289 1.1 alc AH_PRIVATE(ah)->ah_eeprom = AH_NULL; 290 1.1 alc } 291 1.1 alc 292 1.1 alc #define owl_get_eep_ver(_ee) \ 293 1.1 alc (((_ee)->ee_base.baseEepHeader.version >> 12) & 0xF) 294 1.1 alc #define owl_get_eep_rev(_ee) \ 295 1.1 alc (((_ee)->ee_base.baseEepHeader.version) & 0xFFF) 296 1.1 alc 297 1.1 alc HAL_STATUS 298 1.1 alc ath_hal_v14EepromAttach(struct ath_hal *ah) 299 1.1 alc { 300 1.1 alc #define NW(a) (sizeof(a) / sizeof(uint16_t)) 301 1.1 alc HAL_EEPROM_v14 *ee = AH_PRIVATE(ah)->ah_eeprom; 302 1.1 alc uint16_t *eep_data, magic; 303 1.1 alc HAL_BOOL need_swap; 304 1.1 alc u_int w, off, len; 305 1.1 alc uint32_t sum; 306 1.1 alc 307 1.1 alc HALASSERT(ee == AH_NULL); 308 1.1 alc 309 1.1 alc if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { 310 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 311 1.1 alc "%s Error reading Eeprom MAGIC\n", __func__); 312 1.1 alc return HAL_EEREAD; 313 1.1 alc } 314 1.1 alc HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n", 315 1.1 alc __func__, magic); 316 1.1 alc if (magic != AR5416_EEPROM_MAGIC) { 317 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n"); 318 1.1 alc return HAL_EEMAGIC; 319 1.1 alc } 320 1.1 alc 321 1.1 alc ee = ath_hal_malloc(sizeof(HAL_EEPROM_v14)); 322 1.1 alc if (ee == AH_NULL) { 323 1.1 alc /* XXX message */ 324 1.1 alc return HAL_ENOMEM; 325 1.1 alc } 326 1.1 alc 327 1.1 alc eep_data = (uint16_t *)&ee->ee_base; 328 1.1 alc for (w = 0; w < NW(struct ar5416eeprom); w++) { 329 1.1 alc off = owl_eep_start_loc + w; /* NB: AP71 starts at 0 */ 330 1.1 alc if (!ath_hal_eepromRead(ah, off, &eep_data[w])) { 331 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 332 1.1 alc "%s eeprom read error at offset 0x%x\n", 333 1.1 alc __func__, off); 334 1.1 alc return HAL_EEREAD; 335 1.1 alc } 336 1.1 alc } 337 1.1 alc /* Convert to eeprom native eeprom endian format */ 338 1.1 alc if (isBigEndian()) { 339 1.1 alc for (w = 0; w < NW(struct ar5416eeprom); w++) 340 1.1 alc eep_data[w] = __bswap16(eep_data[w]); 341 1.1 alc } 342 1.1 alc 343 1.1 alc /* 344 1.1 alc * At this point, we're in the native eeprom endian format 345 1.1 alc * Now, determine the eeprom endian by looking at byte 26?? 346 1.1 alc */ 347 1.1 alc need_swap = ((ee->ee_base.baseEepHeader.eepMisc & AR5416_EEPMISC_BIG_ENDIAN) != 0) ^ isBigEndian(); 348 1.1 alc if (need_swap) { 349 1.1 alc HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, 350 1.1 alc "Byte swap EEPROM contents.\n"); 351 1.1 alc len = __bswap16(ee->ee_base.baseEepHeader.length); 352 1.1 alc } else { 353 1.1 alc len = ee->ee_base.baseEepHeader.length; 354 1.1 alc } 355 1.1 alc len = AH_MIN(len, sizeof(struct ar5416eeprom)) / sizeof(uint16_t); 356 1.1 alc 357 1.1 alc /* Apply the checksum, done in native eeprom format */ 358 1.1 alc /* XXX - Need to check to make sure checksum calculation is done 359 1.1 alc * in the correct endian format. Right now, it seems it would 360 1.1 alc * cast the raw data to host format and do the calculation, which may 361 1.1 alc * not be correct as the calculation may need to be done in the native 362 1.1 alc * eeprom format 363 1.1 alc */ 364 1.1 alc sum = 0; 365 1.1 alc for (w = 0; w < len; w++) 366 1.1 alc sum ^= eep_data[w]; 367 1.1 alc /* Check CRC - Attach should fail on a bad checksum */ 368 1.1 alc if (sum != 0xffff) { 369 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 370 1.1 alc "Bad EEPROM checksum 0x%x (Len=%u)\n", sum, len); 371 1.1 alc return HAL_EEBADSUM; 372 1.1 alc } 373 1.1 alc 374 1.1 alc if (need_swap) 375 1.1 alc eepromSwap(&ee->ee_base); /* byte swap multi-byte data */ 376 1.1 alc 377 1.1 alc /* swap words 0+2 so version is at the front */ 378 1.1 alc magic = eep_data[0]; 379 1.1 alc eep_data[0] = eep_data[2]; 380 1.1 alc eep_data[2] = magic; 381 1.1 alc 382 1.1 alc HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM, 383 1.1 alc "%s Eeprom Version %u.%u\n", __func__, 384 1.1 alc owl_get_eep_ver(ee), owl_get_eep_rev(ee)); 385 1.1 alc 386 1.1 alc /* NB: must be after all byte swapping */ 387 1.1 alc if (owl_get_eep_ver(ee) != AR5416_EEP_VER) { 388 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 389 1.1 alc "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee)); 390 1.1 alc return HAL_EEBADSUM; 391 1.1 alc } 392 1.1 alc 393 1.1 alc v14EepromReadCTLInfo(ah, ee); /* Get CTLs */ 394 1.1 alc 395 1.1 alc AH_PRIVATE(ah)->ah_eeprom = ee; 396 1.1 alc AH_PRIVATE(ah)->ah_eeversion = ee->ee_base.baseEepHeader.version; 397 1.1 alc AH_PRIVATE(ah)->ah_eepromDetach = v14EepromDetach; 398 1.1 alc AH_PRIVATE(ah)->ah_eepromGet = v14EepromGet; 399 1.1 alc AH_PRIVATE(ah)->ah_eepromSet = v14EepromSet; 400 1.1 alc AH_PRIVATE(ah)->ah_getSpurChan = v14EepromGetSpurChan; 401 1.1 alc AH_PRIVATE(ah)->ah_eepromDiag = v14EepromDiag; 402 1.1 alc return HAL_OK; 403 1.1 alc #undef NW 404 1.1 alc } 405