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