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