1/* 2 * Copyright (c) 2008-2011 Atheros Communications Inc. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include "hw.h" 18 19void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) 20{ 21 REG_WRITE(ah, reg, val); 22 23 if (ah->config.analog_shiftreg) 24 udelay(100); 25} 26 27void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, 28 u32 shift, u32 val) 29{ 30 REG_RMW(ah, reg, ((val << shift) & mask), mask); 31 32 if (ah->config.analog_shiftreg) 33 udelay(100); 34} 35 36int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, 37 int16_t targetLeft, int16_t targetRight) 38{ 39 int16_t rv; 40 41 if (srcRight == srcLeft) { 42 rv = targetLeft; 43 } else { 44 rv = (int16_t) (((target - srcLeft) * targetRight + 45 (srcRight - target) * targetLeft) / 46 (srcRight - srcLeft)); 47 } 48 return rv; 49} 50 51bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, 52 u16 *indexL, u16 *indexR) 53{ 54 u16 i; 55 56 if (target <= pList[0]) { 57 *indexL = *indexR = 0; 58 return true; 59 } 60 if (target >= pList[listSize - 1]) { 61 *indexL = *indexR = (u16) (listSize - 1); 62 return true; 63 } 64 65 for (i = 0; i < listSize - 1; i++) { 66 if (pList[i] == target) { 67 *indexL = *indexR = i; 68 return true; 69 } 70 if (target < pList[i + 1]) { 71 *indexL = i; 72 *indexR = (u16) (i + 1); 73 return false; 74 } 75 } 76 return false; 77} 78 79void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, 80 int eep_start_loc, int size) 81{ 82 int i = 0, j, addr; 83 u32 addrdata[8]; 84 u32 data[8]; 85 86 for (addr = 0; addr < size; addr++) { 87 addrdata[i] = AR5416_EEPROM_OFFSET + 88 ((addr + eep_start_loc) << AR5416_EEPROM_S); 89 i++; 90 if (i == 8) { 91 REG_READ_MULTI(ah, addrdata, data, i); 92 93 for (j = 0; j < i; j++) { 94 *eep_data = data[j]; 95 eep_data++; 96 } 97 i = 0; 98 } 99 } 100 101 if (i != 0) { 102 REG_READ_MULTI(ah, addrdata, data, i); 103 104 for (j = 0; j < i; j++) { 105 *eep_data = data[j]; 106 eep_data++; 107 } 108 } 109} 110 111static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off, 112 u16 *data) 113{ 114 u16 *blob_data; 115 116 if (off * sizeof(u16) > ah->eeprom_blob->size) 117 return false; 118 119 blob_data = (u16 *)ah->eeprom_blob->data; 120 *data = blob_data[off]; 121 return true; 122} 123 124bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) 125{ 126 struct ath_common *common = ath9k_hw_common(ah); 127 bool ret; 128 129 if (ah->eeprom_blob) 130 ret = ath9k_hw_nvram_read_blob(ah, off, data); 131 else 132 ret = common->bus_ops->eeprom_read(common, off, data); 133 134 if (!ret) 135 ath_dbg(common, EEPROM, 136 "unable to read eeprom region at offset %u\n", off); 137 138 return ret; 139} 140 141void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, 142 u8 *pVpdList, u16 numIntercepts, 143 u8 *pRetVpdList) 144{ 145 u16 i, k; 146 u8 currPwr = pwrMin; 147 u16 idxL = 0, idxR = 0; 148 149 for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { 150 ath9k_hw_get_lower_upper_index(currPwr, pPwrList, 151 numIntercepts, &(idxL), 152 &(idxR)); 153 if (idxR < 1) 154 idxR = 1; 155 if (idxL == numIntercepts - 1) 156 idxL = (u16) (numIntercepts - 2); 157 if (pPwrList[idxL] == pPwrList[idxR]) 158 k = pVpdList[idxL]; 159 else 160 k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + 161 (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / 162 (pPwrList[idxR] - pPwrList[idxL])); 163 pRetVpdList[i] = (u8) k; 164 currPwr += 2; 165 } 166} 167 168void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, 169 struct ath9k_channel *chan, 170 struct cal_target_power_leg *powInfo, 171 u16 numChannels, 172 struct cal_target_power_leg *pNewPower, 173 u16 numRates, bool isExtTarget) 174{ 175 struct chan_centers centers; 176 u16 clo, chi; 177 int i; 178 int matchIndex = -1, lowIndex = -1; 179 u16 freq; 180 181 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 182 freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; 183 184 if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, 185 IS_CHAN_2GHZ(chan))) { 186 matchIndex = 0; 187 } else { 188 for (i = 0; (i < numChannels) && 189 (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 190 if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, 191 IS_CHAN_2GHZ(chan))) { 192 matchIndex = i; 193 break; 194 } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, 195 IS_CHAN_2GHZ(chan)) && i > 0 && 196 freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, 197 IS_CHAN_2GHZ(chan))) { 198 lowIndex = i - 1; 199 break; 200 } 201 } 202 if ((matchIndex == -1) && (lowIndex == -1)) 203 matchIndex = i - 1; 204 } 205 206 if (matchIndex != -1) { 207 *pNewPower = powInfo[matchIndex]; 208 } else { 209 clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, 210 IS_CHAN_2GHZ(chan)); 211 chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, 212 IS_CHAN_2GHZ(chan)); 213 214 for (i = 0; i < numRates; i++) { 215 pNewPower->tPow2x[i] = 216 (u8)ath9k_hw_interpolate(freq, clo, chi, 217 powInfo[lowIndex].tPow2x[i], 218 powInfo[lowIndex + 1].tPow2x[i]); 219 } 220 } 221} 222 223void ath9k_hw_get_target_powers(struct ath_hw *ah, 224 struct ath9k_channel *chan, 225 struct cal_target_power_ht *powInfo, 226 u16 numChannels, 227 struct cal_target_power_ht *pNewPower, 228 u16 numRates, bool isHt40Target) 229{ 230 struct chan_centers centers; 231 u16 clo, chi; 232 int i; 233 int matchIndex = -1, lowIndex = -1; 234 u16 freq; 235 236 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 237 freq = isHt40Target ? centers.synth_center : centers.ctl_center; 238 239 if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { 240 matchIndex = 0; 241 } else { 242 for (i = 0; (i < numChannels) && 243 (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 244 if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, 245 IS_CHAN_2GHZ(chan))) { 246 matchIndex = i; 247 break; 248 } else 249 if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, 250 IS_CHAN_2GHZ(chan)) && i > 0 && 251 freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, 252 IS_CHAN_2GHZ(chan))) { 253 lowIndex = i - 1; 254 break; 255 } 256 } 257 if ((matchIndex == -1) && (lowIndex == -1)) 258 matchIndex = i - 1; 259 } 260 261 if (matchIndex != -1) { 262 *pNewPower = powInfo[matchIndex]; 263 } else { 264 clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, 265 IS_CHAN_2GHZ(chan)); 266 chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, 267 IS_CHAN_2GHZ(chan)); 268 269 for (i = 0; i < numRates; i++) { 270 pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, 271 clo, chi, 272 powInfo[lowIndex].tPow2x[i], 273 powInfo[lowIndex + 1].tPow2x[i]); 274 } 275 } 276} 277 278u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, 279 bool is2GHz, int num_band_edges) 280{ 281 u16 twiceMaxEdgePower = MAX_RATE_POWER; 282 int i; 283 284 for (i = 0; (i < num_band_edges) && 285 (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 286 if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { 287 twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl); 288 break; 289 } else if ((i > 0) && 290 (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, 291 is2GHz))) { 292 if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, 293 is2GHz) < freq && 294 CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) { 295 twiceMaxEdgePower = 296 CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl); 297 } 298 break; 299 } 300 } 301 302 return twiceMaxEdgePower; 303} 304 305u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit, 306 u8 antenna_reduction) 307{ 308 u16 reduction = antenna_reduction; 309 310 /* 311 * Reduce scaled Power by number of chains active 312 * to get the per chain tx power level. 313 */ 314 switch (ar5416_get_ntxchains(ah->txchainmask)) { 315 case 1: 316 break; 317 case 2: 318 reduction += POWER_CORRECTION_FOR_TWO_CHAIN; 319 break; 320 case 3: 321 reduction += POWER_CORRECTION_FOR_THREE_CHAIN; 322 break; 323 } 324 325 if (power_limit > reduction) 326 power_limit -= reduction; 327 else 328 power_limit = 0; 329 330 return power_limit; 331} 332 333void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah) 334{ 335 struct ath_common *common = ath9k_hw_common(ah); 336 struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); 337 338 switch (ar5416_get_ntxchains(ah->txchainmask)) { 339 case 1: 340 break; 341 case 2: 342 regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN; 343 break; 344 case 3: 345 regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN; 346 break; 347 default: 348 ath_dbg(common, EEPROM, "Invalid chainmask configuration\n"); 349 break; 350 } 351} 352 353void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, 354 struct ath9k_channel *chan, 355 void *pRawDataSet, 356 u8 *bChans, u16 availPiers, 357 u16 tPdGainOverlap, 358 u16 *pPdGainBoundaries, u8 *pPDADCValues, 359 u16 numXpdGains) 360{ 361 int i, j, k; 362 int16_t ss; 363 u16 idxL = 0, idxR = 0, numPiers; 364 static u8 vpdTableL[AR5416_NUM_PD_GAINS] 365 [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 366 static u8 vpdTableR[AR5416_NUM_PD_GAINS] 367 [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 368 static u8 vpdTableI[AR5416_NUM_PD_GAINS] 369 [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 370 371 u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; 372 u8 minPwrT4[AR5416_NUM_PD_GAINS]; 373 u8 maxPwrT4[AR5416_NUM_PD_GAINS]; 374 int16_t vpdStep; 375 int16_t tmpVal; 376 u16 sizeCurrVpdTable, maxIndex, tgtIndex; 377 bool match; 378 int16_t minDelta = 0; 379 struct chan_centers centers; 380 int pdgain_boundary_default; 381 struct cal_data_per_freq *data_def = pRawDataSet; 382 struct cal_data_per_freq_4k *data_4k = pRawDataSet; 383 struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet; 384 bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah); 385 int intercepts; 386 387 if (AR_SREV_9287(ah)) 388 intercepts = AR9287_PD_GAIN_ICEPTS; 389 else 390 intercepts = AR5416_PD_GAIN_ICEPTS; 391 392 memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS); 393 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 394 395 for (numPiers = 0; numPiers < availPiers; numPiers++) { 396 if (bChans[numPiers] == AR5416_BCHAN_UNUSED) 397 break; 398 } 399 400 match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, 401 IS_CHAN_2GHZ(chan)), 402 bChans, numPiers, &idxL, &idxR); 403 404 if (match) { 405 if (AR_SREV_9287(ah)) { 406 /* FIXME: array overrun? */ 407 for (i = 0; i < numXpdGains; i++) { 408 minPwrT4[i] = data_9287[idxL].pwrPdg[i][0]; 409 maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4]; 410 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 411 data_9287[idxL].pwrPdg[i], 412 data_9287[idxL].vpdPdg[i], 413 intercepts, 414 vpdTableI[i]); 415 } 416 } else if (eeprom_4k) { 417 for (i = 0; i < numXpdGains; i++) { 418 minPwrT4[i] = data_4k[idxL].pwrPdg[i][0]; 419 maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4]; 420 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 421 data_4k[idxL].pwrPdg[i], 422 data_4k[idxL].vpdPdg[i], 423 intercepts, 424 vpdTableI[i]); 425 } 426 } else { 427 for (i = 0; i < numXpdGains; i++) { 428 minPwrT4[i] = data_def[idxL].pwrPdg[i][0]; 429 maxPwrT4[i] = data_def[idxL].pwrPdg[i][4]; 430 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 431 data_def[idxL].pwrPdg[i], 432 data_def[idxL].vpdPdg[i], 433 intercepts, 434 vpdTableI[i]); 435 } 436 } 437 } else { 438 for (i = 0; i < numXpdGains; i++) { 439 if (AR_SREV_9287(ah)) { 440 pVpdL = data_9287[idxL].vpdPdg[i]; 441 pPwrL = data_9287[idxL].pwrPdg[i]; 442 pVpdR = data_9287[idxR].vpdPdg[i]; 443 pPwrR = data_9287[idxR].pwrPdg[i]; 444 } else if (eeprom_4k) { 445 pVpdL = data_4k[idxL].vpdPdg[i]; 446 pPwrL = data_4k[idxL].pwrPdg[i]; 447 pVpdR = data_4k[idxR].vpdPdg[i]; 448 pPwrR = data_4k[idxR].pwrPdg[i]; 449 } else { 450 pVpdL = data_def[idxL].vpdPdg[i]; 451 pPwrL = data_def[idxL].pwrPdg[i]; 452 pVpdR = data_def[idxR].vpdPdg[i]; 453 pPwrR = data_def[idxR].pwrPdg[i]; 454 } 455 456 minPwrT4[i] = max(pPwrL[0], pPwrR[0]); 457 458 maxPwrT4[i] = 459 min(pPwrL[intercepts - 1], 460 pPwrR[intercepts - 1]); 461 462 463 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 464 pPwrL, pVpdL, 465 intercepts, 466 vpdTableL[i]); 467 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 468 pPwrR, pVpdR, 469 intercepts, 470 vpdTableR[i]); 471 472 for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { 473 vpdTableI[i][j] = 474 (u8)(ath9k_hw_interpolate((u16) 475 FREQ2FBIN(centers. 476 synth_center, 477 IS_CHAN_2GHZ 478 (chan)), 479 bChans[idxL], bChans[idxR], 480 vpdTableL[i][j], vpdTableR[i][j])); 481 } 482 } 483 } 484 485 k = 0; 486 487 for (i = 0; i < numXpdGains; i++) { 488 if (i == (numXpdGains - 1)) 489 pPdGainBoundaries[i] = 490 (u16)(maxPwrT4[i] / 2); 491 else 492 pPdGainBoundaries[i] = 493 (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); 494 495 pPdGainBoundaries[i] = 496 min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]); 497 498 minDelta = 0; 499 500 if (i == 0) { 501 if (AR_SREV_9280_20_OR_LATER(ah)) 502 ss = (int16_t)(0 - (minPwrT4[i] / 2)); 503 else 504 ss = 0; 505 } else { 506 ss = (int16_t)((pPdGainBoundaries[i - 1] - 507 (minPwrT4[i] / 2)) - 508 tPdGainOverlap + 1 + minDelta); 509 } 510 vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); 511 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 512 513 while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 514 tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); 515 pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); 516 ss++; 517 } 518 519 sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); 520 tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - 521 (minPwrT4[i] / 2)); 522 maxIndex = (tgtIndex < sizeCurrVpdTable) ? 523 tgtIndex : sizeCurrVpdTable; 524 525 while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 526 pPDADCValues[k++] = vpdTableI[i][ss++]; 527 } 528 529 vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - 530 vpdTableI[i][sizeCurrVpdTable - 2]); 531 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 532 533 if (tgtIndex >= maxIndex) { 534 while ((ss <= tgtIndex) && 535 (k < (AR5416_NUM_PDADC_VALUES - 1))) { 536 tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + 537 (ss - maxIndex + 1) * vpdStep)); 538 pPDADCValues[k++] = (u8)((tmpVal > 255) ? 539 255 : tmpVal); 540 ss++; 541 } 542 } 543 } 544 545 if (eeprom_4k) 546 pdgain_boundary_default = 58; 547 else 548 pdgain_boundary_default = pPdGainBoundaries[i - 1]; 549 550 while (i < AR5416_PD_GAINS_IN_MASK) { 551 pPdGainBoundaries[i] = pdgain_boundary_default; 552 i++; 553 } 554 555 while (k < AR5416_NUM_PDADC_VALUES) { 556 pPDADCValues[k] = pPDADCValues[k - 1]; 557 k++; 558 } 559} 560 561int ath9k_hw_eeprom_init(struct ath_hw *ah) 562{ 563 int status; 564 565 if (AR_SREV_9300_20_OR_LATER(ah)) 566 ah->eep_ops = &eep_ar9300_ops; 567 else if (AR_SREV_9287(ah)) { 568 ah->eep_ops = &eep_ar9287_ops; 569 } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { 570 ah->eep_ops = &eep_4k_ops; 571 } else { 572 ah->eep_ops = &eep_def_ops; 573 } 574 575 if (!ah->eep_ops->fill_eeprom(ah)) 576 return -EIO; 577 578 status = ah->eep_ops->check_eeprom(ah); 579 580 return status; 581} 582