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