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