1 /* 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $FreeBSD$ 18 */ 19 #include "opt_ah.h" 20 21 #include "ah.h" 22 #include "ah_internal.h" 23 24 #include "ah_eeprom_v3.h" 25 26 #include "ar5212/ar5212.h" 27 #include "ar5212/ar5212reg.h" 28 #include "ar5212/ar5212phy.h" 29 30 #define AH_5212_5413 31 #include "ar5212/ar5212.ini" 32 33 #define N(a) (sizeof(a)/sizeof(a[0])) 34 35 struct ar5413State { 36 RF_HAL_FUNCS base; /* public state, must be first */ 37 uint16_t pcdacTable[PWR_TABLE_SIZE_2413]; 38 39 uint32_t Bank1Data[N(ar5212Bank1_5413)]; 40 uint32_t Bank2Data[N(ar5212Bank2_5413)]; 41 uint32_t Bank3Data[N(ar5212Bank3_5413)]; 42 uint32_t Bank6Data[N(ar5212Bank6_5413)]; 43 uint32_t Bank7Data[N(ar5212Bank7_5413)]; 44 45 /* 46 * Private state for reduced stack usage. 47 */ 48 /* filled out Vpd table for all pdGains (chanL) */ 49 uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL] 50 [MAX_PWR_RANGE_IN_HALF_DB]; 51 /* filled out Vpd table for all pdGains (chanR) */ 52 uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL] 53 [MAX_PWR_RANGE_IN_HALF_DB]; 54 /* filled out Vpd table for all pdGains (interpolated) */ 55 uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL] 56 [MAX_PWR_RANGE_IN_HALF_DB]; 57 }; 58 #define AR5413(ah) ((struct ar5413State *) AH5212(ah)->ah_rfHal) 59 60 extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, 61 uint32_t numBits, uint32_t firstBit, uint32_t column); 62 63 static void 64 ar5413WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, 65 int writes) 66 { 67 HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5413, modesIndex, writes); 68 HAL_INI_WRITE_ARRAY(ah, ar5212Common_5413, 1, writes); 69 HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5413, freqIndex, writes); 70 } 71 72 /* 73 * Take the MHz channel value and set the Channel value 74 * 75 * ASSUMES: Writes enabled to analog bus 76 */ 77 static HAL_BOOL 78 ar5413SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) 79 { 80 uint16_t freq = ath_hal_gethwchannel(ah, chan); 81 uint32_t channelSel = 0; 82 uint32_t bModeSynth = 0; 83 uint32_t aModeRefSel = 0; 84 uint32_t reg32 = 0; 85 86 OS_MARK(ah, AH_MARK_SETCHANNEL, freq); 87 88 if (freq < 4800) { 89 uint32_t txctl; 90 91 if (((freq - 2192) % 5) == 0) { 92 channelSel = ((freq - 672) * 2 - 3040)/10; 93 bModeSynth = 0; 94 } else if (((freq - 2224) % 5) == 0) { 95 channelSel = ((freq - 704) * 2 - 3040) / 10; 96 bModeSynth = 1; 97 } else { 98 HALDEBUG(ah, HAL_DEBUG_ANY, 99 "%s: invalid channel %u MHz\n", 100 __func__, freq); 101 return AH_FALSE; 102 } 103 104 channelSel = (channelSel << 2) & 0xff; 105 channelSel = ath_hal_reverseBits(channelSel, 8); 106 107 txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); 108 if (freq == 2484) { 109 /* Enable channel spreading for channel 14 */ 110 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 111 txctl | AR_PHY_CCK_TX_CTRL_JAPAN); 112 } else { 113 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 114 txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); 115 } 116 } else if (((freq % 5) == 2) && (freq <= 5435)) { 117 freq = freq - 2; /* Align to even 5MHz raster */ 118 channelSel = ath_hal_reverseBits( 119 (uint32_t)(((freq - 4800)*10)/25 + 1), 8); 120 aModeRefSel = ath_hal_reverseBits(0, 2); 121 } else if ((freq % 20) == 0 && freq >= 5120) { 122 channelSel = ath_hal_reverseBits( 123 ((freq - 4800) / 20 << 2), 8); 124 aModeRefSel = ath_hal_reverseBits(1, 2); 125 } else if ((freq % 10) == 0) { 126 channelSel = ath_hal_reverseBits( 127 ((freq - 4800) / 10 << 1), 8); 128 aModeRefSel = ath_hal_reverseBits(1, 2); 129 } else if ((freq % 5) == 0) { 130 channelSel = ath_hal_reverseBits( 131 (freq - 4800) / 5, 8); 132 aModeRefSel = ath_hal_reverseBits(1, 2); 133 } else { 134 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", 135 __func__, freq); 136 return AH_FALSE; 137 } 138 139 reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | 140 (1 << 12) | 0x1; 141 OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); 142 143 reg32 >>= 8; 144 OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); 145 146 AH_PRIVATE(ah)->ah_curchan = chan; 147 return AH_TRUE; 148 } 149 150 /* 151 * Reads EEPROM header info from device structure and programs 152 * all rf registers 153 * 154 * REQUIRES: Access to the analog rf device 155 */ 156 static HAL_BOOL 157 ar5413SetRfRegs(struct ath_hal *ah, 158 const struct ieee80211_channel *chan, 159 uint16_t modesIndex, uint16_t *rfXpdGain) 160 { 161 #define RF_BANK_SETUP(_priv, _ix, _col) do { \ 162 int i; \ 163 for (i = 0; i < N(ar5212Bank##_ix##_5413); i++) \ 164 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5413[i][_col];\ 165 } while (0) 166 struct ath_hal_5212 *ahp = AH5212(ah); 167 uint16_t freq = ath_hal_gethwchannel(ah, chan); 168 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 169 uint16_t ob5GHz = 0, db5GHz = 0; 170 uint16_t ob2GHz = 0, db2GHz = 0; 171 struct ar5413State *priv = AR5413(ah); 172 int regWrites = 0; 173 174 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan %u/0x%x modesIndex %u\n", 175 __func__, chan->ic_freq, chan->ic_flags, modesIndex); 176 177 HALASSERT(priv != AH_NULL); 178 179 /* Setup rf parameters */ 180 switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) { 181 case IEEE80211_CHAN_A: 182 if (freq > 4000 && freq < 5260) { 183 ob5GHz = ee->ee_ob1; 184 db5GHz = ee->ee_db1; 185 } else if (freq >= 5260 && freq < 5500) { 186 ob5GHz = ee->ee_ob2; 187 db5GHz = ee->ee_db2; 188 } else if (freq >= 5500 && freq < 5725) { 189 ob5GHz = ee->ee_ob3; 190 db5GHz = ee->ee_db3; 191 } else if (freq >= 5725) { 192 ob5GHz = ee->ee_ob4; 193 db5GHz = ee->ee_db4; 194 } else { 195 /* XXX else */ 196 } 197 break; 198 case IEEE80211_CHAN_B: 199 ob2GHz = ee->ee_obFor24; 200 db2GHz = ee->ee_dbFor24; 201 break; 202 case IEEE80211_CHAN_G: 203 case IEEE80211_CHAN_PUREG: /* NB: really 108G */ 204 ob2GHz = ee->ee_obFor24g; 205 db2GHz = ee->ee_dbFor24g; 206 break; 207 default: 208 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", 209 __func__, chan->ic_flags); 210 return AH_FALSE; 211 } 212 213 /* Bank 1 Write */ 214 RF_BANK_SETUP(priv, 1, 1); 215 216 /* Bank 2 Write */ 217 RF_BANK_SETUP(priv, 2, modesIndex); 218 219 /* Bank 3 Write */ 220 RF_BANK_SETUP(priv, 3, modesIndex); 221 222 /* Bank 6 Write */ 223 RF_BANK_SETUP(priv, 6, modesIndex); 224 225 /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ 226 if (IEEE80211_IS_CHAN_2GHZ(chan)) { 227 ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 241, 0); 228 ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 238, 0); 229 230 /* TODO - only for Eagle 1.0 2GHz - remove for production */ 231 /* XXX: but without this bit G doesn't work. */ 232 ar5212ModifyRfBuffer(priv->Bank6Data, 1 , 1, 291, 2); 233 234 /* Optimum value for rf_pwd_iclobuf2G for PCIe chips only */ 235 if (AH_PRIVATE(ah)->ah_ispcie) { 236 ar5212ModifyRfBuffer(priv->Bank6Data, ath_hal_reverseBits(6, 3), 237 3, 131, 3); 238 } 239 } else { 240 ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 247, 0); 241 ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 244, 0); 242 243 } 244 245 /* Bank 7 Setup */ 246 RF_BANK_SETUP(priv, 7, modesIndex); 247 248 /* Write Analog registers */ 249 HAL_INI_WRITE_BANK(ah, ar5212Bank1_5413, priv->Bank1Data, regWrites); 250 HAL_INI_WRITE_BANK(ah, ar5212Bank2_5413, priv->Bank2Data, regWrites); 251 HAL_INI_WRITE_BANK(ah, ar5212Bank3_5413, priv->Bank3Data, regWrites); 252 HAL_INI_WRITE_BANK(ah, ar5212Bank6_5413, priv->Bank6Data, regWrites); 253 HAL_INI_WRITE_BANK(ah, ar5212Bank7_5413, priv->Bank7Data, regWrites); 254 255 /* Now that we have reprogrammed rfgain value, clear the flag. */ 256 ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; 257 258 return AH_TRUE; 259 #undef RF_BANK_SETUP 260 } 261 262 /* 263 * Return a reference to the requested RF Bank. 264 */ 265 static uint32_t * 266 ar5413GetRfBank(struct ath_hal *ah, int bank) 267 { 268 struct ar5413State *priv = AR5413(ah); 269 270 HALASSERT(priv != AH_NULL); 271 switch (bank) { 272 case 1: return priv->Bank1Data; 273 case 2: return priv->Bank2Data; 274 case 3: return priv->Bank3Data; 275 case 6: return priv->Bank6Data; 276 case 7: return priv->Bank7Data; 277 } 278 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", 279 __func__, bank); 280 return AH_NULL; 281 } 282 283 /* 284 * Return indices surrounding the value in sorted integer lists. 285 * 286 * NB: the input list is assumed to be sorted in ascending order 287 */ 288 static void 289 GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize, 290 uint32_t *vlo, uint32_t *vhi) 291 { 292 int16_t target = v; 293 const uint16_t *ep = lp+listSize; 294 const uint16_t *tp; 295 296 *vlo = 0; /* avoid gcc warnings */ 297 *vhi = 0; /* avoid gcc warnings */ 298 299 /* 300 * Check first and last elements for out-of-bounds conditions. 301 */ 302 if (target < lp[0]) { 303 *vlo = *vhi = 0; 304 return; 305 } 306 if (target >= ep[-1]) { 307 *vlo = *vhi = listSize - 1; 308 return; 309 } 310 311 /* look for value being near or between 2 values in list */ 312 for (tp = lp; tp < ep; tp++) { 313 /* 314 * If value is close to the current value of the list 315 * then target is not between values, it is one of the values 316 */ 317 if (*tp == target) { 318 *vlo = *vhi = tp - (const uint16_t *) lp; 319 return; 320 } 321 /* 322 * Look for value being between current value and next value 323 * if so return these 2 values 324 */ 325 if (target < tp[1]) { 326 *vlo = tp - (const uint16_t *) lp; 327 *vhi = *vlo + 1; 328 return; 329 } 330 } 331 } 332 333 /* 334 * Fill the Vpdlist for indices Pmax-Pmin 335 */ 336 static HAL_BOOL 337 ar5413FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t Pmax, 338 const int16_t *pwrList, const uint16_t *VpdList, 339 uint16_t numIntercepts, 340 uint16_t retVpdList[][64]) 341 { 342 uint16_t ii, jj, kk; 343 int16_t currPwr = (int16_t)(2*Pmin); 344 /* since Pmin is pwr*2 and pwrList is 4*pwr */ 345 uint32_t idxL, idxR; 346 347 ii = 0; 348 jj = 0; 349 350 if (numIntercepts < 2) 351 return AH_FALSE; 352 353 while (ii <= (uint16_t)(Pmax - Pmin)) { 354 GetLowerUpperIndex(currPwr, (const uint16_t *) pwrList, 355 numIntercepts, &(idxL), &(idxR)); 356 if (idxR < 1) 357 idxR = 1; /* extrapolate below */ 358 if (idxL == (uint32_t)(numIntercepts - 1)) 359 idxL = numIntercepts - 2; /* extrapolate above */ 360 if (pwrList[idxL] == pwrList[idxR]) 361 kk = VpdList[idxL]; 362 else 363 kk = (uint16_t) 364 (((currPwr - pwrList[idxL])*VpdList[idxR]+ 365 (pwrList[idxR] - currPwr)*VpdList[idxL])/ 366 (pwrList[idxR] - pwrList[idxL])); 367 retVpdList[pdGainIdx][ii] = kk; 368 ii++; 369 currPwr += 2; /* half dB steps */ 370 } 371 372 return AH_TRUE; 373 } 374 375 /* 376 * Returns interpolated or the scaled up interpolated value 377 */ 378 static int16_t 379 interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, 380 int16_t targetLeft, int16_t targetRight) 381 { 382 int16_t rv; 383 384 if (srcRight != srcLeft) { 385 rv = ((target - srcLeft)*targetRight + 386 (srcRight - target)*targetLeft) / (srcRight - srcLeft); 387 } else { 388 rv = targetLeft; 389 } 390 return rv; 391 } 392 393 /* 394 * Uses the data points read from EEPROM to reconstruct the pdadc power table 395 * Called by ar5413SetPowerTable() 396 */ 397 static int 398 ar5413getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel, 399 const RAW_DATA_STRUCT_2413 *pRawDataset, 400 uint16_t pdGainOverlap_t2, 401 int16_t *pMinCalPower, uint16_t pPdGainBoundaries[], 402 uint16_t pPdGainValues[], uint16_t pPDADCValues[]) 403 { 404 struct ar5413State *priv = AR5413(ah); 405 #define VpdTable_L priv->vpdTable_L 406 #define VpdTable_R priv->vpdTable_R 407 #define VpdTable_I priv->vpdTable_I 408 uint32_t ii, jj, kk; 409 int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */ 410 uint32_t idxL, idxR; 411 uint32_t numPdGainsUsed = 0; 412 /* 413 * If desired to support -ve power levels in future, just 414 * change pwr_I_0 to signed 5-bits. 415 */ 416 int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; 417 /* to accommodate -ve power levels later on. */ 418 int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL]; 419 /* to accommodate -ve power levels later on */ 420 uint16_t numVpd = 0; 421 uint16_t Vpd_step; 422 int16_t tmpVal ; 423 uint32_t sizeCurrVpdTable, maxIndex, tgtIndex; 424 425 /* Get upper lower index */ 426 GetLowerUpperIndex(channel, pRawDataset->pChannels, 427 pRawDataset->numChannels, &(idxL), &(idxR)); 428 429 for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { 430 jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; 431 /* work backwards 'cause highest pdGain for lowest power */ 432 numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd; 433 if (numVpd > 0) { 434 pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain; 435 Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]; 436 if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) { 437 Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]; 438 } 439 Pmin_t2[numPdGainsUsed] = (int16_t) 440 (Pmin_t2[numPdGainsUsed] / 2); 441 Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1]; 442 if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]) 443 Pmax_t2[numPdGainsUsed] = 444 pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1]; 445 Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2); 446 ar5413FillVpdTable( 447 numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], 448 &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]), 449 &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L 450 ); 451 ar5413FillVpdTable( 452 numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], 453 &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]), 454 &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R 455 ); 456 for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) { 457 VpdTable_I[numPdGainsUsed][kk] = 458 interpolate_signed( 459 channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR], 460 (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]); 461 } 462 /* fill VpdTable_I for this pdGain */ 463 numPdGainsUsed++; 464 } 465 /* if this pdGain is used */ 466 } 467 468 *pMinCalPower = Pmin_t2[0]; 469 kk = 0; /* index for the final table */ 470 for (ii = 0; ii < numPdGainsUsed; ii++) { 471 if (ii == (numPdGainsUsed - 1)) 472 pPdGainBoundaries[ii] = Pmax_t2[ii] + 473 PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB; 474 else 475 pPdGainBoundaries[ii] = (uint16_t) 476 ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 ); 477 if (pPdGainBoundaries[ii] > 63) { 478 HALDEBUG(ah, HAL_DEBUG_ANY, 479 "%s: clamp pPdGainBoundaries[%d] %d\n", 480 __func__, ii, pPdGainBoundaries[ii]);/*XXX*/ 481 pPdGainBoundaries[ii] = 63; 482 } 483 484 /* Find starting index for this pdGain */ 485 if (ii == 0) 486 ss = 0; /* for the first pdGain, start from index 0 */ 487 else 488 ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) - 489 pdGainOverlap_t2; 490 Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]); 491 Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); 492 /* 493 *-ve ss indicates need to extrapolate data below for this pdGain 494 */ 495 while (ss < 0) { 496 tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step); 497 pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal); 498 ss++; 499 } 500 501 sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii]; 502 tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii]; 503 maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; 504 505 while (ss < (int16_t)maxIndex) 506 pPDADCValues[kk++] = VpdTable_I[ii][ss++]; 507 508 Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] - 509 VpdTable_I[ii][sizeCurrVpdTable-2]); 510 Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step); 511 /* 512 * for last gain, pdGainBoundary == Pmax_t2, so will 513 * have to extrapolate 514 */ 515 if (tgtIndex > maxIndex) { /* need to extrapolate above */ 516 while(ss < (int16_t)tgtIndex) { 517 tmpVal = (uint16_t) 518 (VpdTable_I[ii][sizeCurrVpdTable-1] + 519 (ss-maxIndex)*Vpd_step); 520 pPDADCValues[kk++] = (tmpVal > 127) ? 521 127 : tmpVal; 522 ss++; 523 } 524 } /* extrapolated above */ 525 } /* for all pdGainUsed */ 526 527 while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) { 528 pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1]; 529 ii++; 530 } 531 while (kk < 128) { 532 pPDADCValues[kk] = pPDADCValues[kk-1]; 533 kk++; 534 } 535 536 return numPdGainsUsed; 537 #undef VpdTable_L 538 #undef VpdTable_R 539 #undef VpdTable_I 540 } 541 542 static HAL_BOOL 543 ar5413SetPowerTable(struct ath_hal *ah, 544 int16_t *minPower, int16_t *maxPower, 545 const struct ieee80211_channel *chan, 546 uint16_t *rfXpdGain) 547 { 548 struct ath_hal_5212 *ahp = AH5212(ah); 549 uint16_t freq = ath_hal_gethwchannel(ah, chan); 550 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 551 const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL; 552 uint16_t pdGainOverlap_t2; 553 int16_t minCalPower5413_t2; 554 uint16_t *pdadcValues = ahp->ah_pcdacTable; 555 uint16_t gainBoundaries[4]; 556 uint32_t reg32, regoffset; 557 int i, numPdGainsUsed; 558 #ifndef AH_USE_INIPDGAIN 559 uint32_t tpcrg1; 560 #endif 561 562 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n", 563 __func__, chan->ic_freq, chan->ic_flags); 564 565 if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan)) 566 pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; 567 else if (IEEE80211_IS_CHAN_B(chan)) 568 pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; 569 else { 570 HALASSERT(IEEE80211_IS_CHAN_5GHZ(chan)); 571 pRawDataset = &ee->ee_rawDataset2413[headerInfo11A]; 572 } 573 574 pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5), 575 AR_PHY_TPCRG5_PD_GAIN_OVERLAP); 576 577 numPdGainsUsed = ar5413getGainBoundariesAndPdadcsForPowers(ah, 578 freq, pRawDataset, pdGainOverlap_t2, 579 &minCalPower5413_t2,gainBoundaries, rfXpdGain, pdadcValues); 580 HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3); 581 582 #ifdef AH_USE_INIPDGAIN 583 /* 584 * Use pd_gains curve from eeprom; Atheros always uses 585 * the default curve from the ini file but some vendors 586 * (e.g. Zcomax) want to override this curve and not 587 * honoring their settings results in tx power 5dBm low. 588 */ 589 OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, 590 (pRawDataset->pDataPerChannel[0].numPdGains - 1)); 591 #else 592 tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1); 593 tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN) 594 | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN); 595 switch (numPdGainsUsed) { 596 case 3: 597 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3; 598 tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3); 599 /* fall thru... */ 600 case 2: 601 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2; 602 tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2); 603 /* fall thru... */ 604 case 1: 605 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1; 606 tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1); 607 break; 608 } 609 #ifdef AH_DEBUG 610 if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1)) 611 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default " 612 "pd_gains (default 0x%x, calculated 0x%x)\n", 613 __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1); 614 #endif 615 OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1); 616 #endif 617 618 /* 619 * Note the pdadc table may not start at 0 dBm power, could be 620 * negative or greater than 0. Need to offset the power 621 * values by the amount of minPower for griffin 622 */ 623 if (minCalPower5413_t2 != 0) 624 ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower5413_t2); 625 else 626 ahp->ah_txPowerIndexOffset = 0; 627 628 /* Finally, write the power values into the baseband power table */ 629 regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */ 630 for (i = 0; i < 32; i++) { 631 reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0) | 632 ((pdadcValues[4*i + 1] & 0xFF) << 8) | 633 ((pdadcValues[4*i + 2] & 0xFF) << 16) | 634 ((pdadcValues[4*i + 3] & 0xFF) << 24) ; 635 OS_REG_WRITE(ah, regoffset, reg32); 636 regoffset += 4; 637 } 638 639 OS_REG_WRITE(ah, AR_PHY_TPCRG5, 640 SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | 641 SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | 642 SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | 643 SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | 644 SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); 645 646 return AH_TRUE; 647 } 648 649 static int16_t 650 ar5413GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data) 651 { 652 uint32_t ii,jj; 653 uint16_t Pmin=0,numVpd; 654 655 for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { 656 jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1; 657 /* work backwards 'cause highest pdGain for lowest power */ 658 numVpd = data->pDataPerPDGain[jj].numVpd; 659 if (numVpd > 0) { 660 Pmin = data->pDataPerPDGain[jj].pwr_t4[0]; 661 return(Pmin); 662 } 663 } 664 return(Pmin); 665 } 666 667 static int16_t 668 ar5413GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data) 669 { 670 uint32_t ii; 671 uint16_t Pmax=0,numVpd; 672 673 for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) { 674 /* work forwards cuase lowest pdGain for highest power */ 675 numVpd = data->pDataPerPDGain[ii].numVpd; 676 if (numVpd > 0) { 677 Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1]; 678 return(Pmax); 679 } 680 } 681 return(Pmax); 682 } 683 684 static HAL_BOOL 685 ar5413GetChannelMaxMinPower(struct ath_hal *ah, 686 const struct ieee80211_channel *chan, 687 int16_t *maxPow, int16_t *minPow) 688 { 689 uint16_t freq = chan->ic_freq; /* NB: never mapped */ 690 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 691 const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL; 692 const RAW_DATA_PER_CHANNEL_2413 *data=AH_NULL; 693 uint16_t numChannels; 694 int totalD,totalF, totalMin,last, i; 695 696 *maxPow = 0; 697 698 if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan)) 699 pRawDataset = &ee->ee_rawDataset2413[headerInfo11G]; 700 else if (IEEE80211_IS_CHAN_B(chan)) 701 pRawDataset = &ee->ee_rawDataset2413[headerInfo11B]; 702 else { 703 HALASSERT(IEEE80211_IS_CHAN_5GHZ(chan)); 704 pRawDataset = &ee->ee_rawDataset2413[headerInfo11A]; 705 } 706 707 numChannels = pRawDataset->numChannels; 708 data = pRawDataset->pDataPerChannel; 709 710 /* Make sure the channel is in the range of the TP values 711 * (freq piers) 712 */ 713 if (numChannels < 1) 714 return(AH_FALSE); 715 716 if ((freq < data[0].channelValue) || 717 (freq > data[numChannels-1].channelValue)) { 718 if (freq < data[0].channelValue) { 719 *maxPow = ar5413GetMaxPower(ah, &data[0]); 720 *minPow = ar5413GetMinPower(ah, &data[0]); 721 return(AH_TRUE); 722 } else { 723 *maxPow = ar5413GetMaxPower(ah, &data[numChannels - 1]); 724 *minPow = ar5413GetMinPower(ah, &data[numChannels - 1]); 725 return(AH_TRUE); 726 } 727 } 728 729 /* Linearly interpolate the power value now */ 730 for (last=0,i=0; (i<numChannels) && (freq > data[i].channelValue); 731 last = i++); 732 totalD = data[i].channelValue - data[last].channelValue; 733 if (totalD > 0) { 734 totalF = ar5413GetMaxPower(ah, &data[i]) - ar5413GetMaxPower(ah, &data[last]); 735 *maxPow = (int8_t) ((totalF*(freq-data[last].channelValue) + 736 ar5413GetMaxPower(ah, &data[last])*totalD)/totalD); 737 totalMin = ar5413GetMinPower(ah, &data[i]) - ar5413GetMinPower(ah, &data[last]); 738 *minPow = (int8_t) ((totalMin*(freq-data[last].channelValue) + 739 ar5413GetMinPower(ah, &data[last])*totalD)/totalD); 740 return(AH_TRUE); 741 } else { 742 if (freq == data[i].channelValue) { 743 *maxPow = ar5413GetMaxPower(ah, &data[i]); 744 *minPow = ar5413GetMinPower(ah, &data[i]); 745 return(AH_TRUE); 746 } else 747 return(AH_FALSE); 748 } 749 } 750 751 /* 752 * Free memory for analog bank scratch buffers 753 */ 754 static void 755 ar5413RfDetach(struct ath_hal *ah) 756 { 757 struct ath_hal_5212 *ahp = AH5212(ah); 758 759 HALASSERT(ahp->ah_rfHal != AH_NULL); 760 ath_hal_free(ahp->ah_rfHal); 761 ahp->ah_rfHal = AH_NULL; 762 } 763 764 /* 765 * Allocate memory for analog bank scratch buffers 766 * Scratch Buffer will be reinitialized every reset so no need to zero now 767 */ 768 static HAL_BOOL 769 ar5413RfAttach(struct ath_hal *ah, HAL_STATUS *status) 770 { 771 struct ath_hal_5212 *ahp = AH5212(ah); 772 struct ar5413State *priv; 773 774 HALASSERT(ah->ah_magic == AR5212_MAGIC); 775 776 HALASSERT(ahp->ah_rfHal == AH_NULL); 777 priv = ath_hal_malloc(sizeof(struct ar5413State)); 778 if (priv == AH_NULL) { 779 HALDEBUG(ah, HAL_DEBUG_ANY, 780 "%s: cannot allocate private state\n", __func__); 781 *status = HAL_ENOMEM; /* XXX */ 782 return AH_FALSE; 783 } 784 priv->base.rfDetach = ar5413RfDetach; 785 priv->base.writeRegs = ar5413WriteRegs; 786 priv->base.getRfBank = ar5413GetRfBank; 787 priv->base.setChannel = ar5413SetChannel; 788 priv->base.setRfRegs = ar5413SetRfRegs; 789 priv->base.setPowerTable = ar5413SetPowerTable; 790 priv->base.getChannelMaxMinPower = ar5413GetChannelMaxMinPower; 791 priv->base.getNfAdjust = ar5212GetNfAdjust; 792 793 ahp->ah_pcdacTable = priv->pcdacTable; 794 ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); 795 ahp->ah_rfHal = &priv->base; 796 797 return AH_TRUE; 798 } 799 800 static HAL_BOOL 801 ar5413Probe(struct ath_hal *ah) 802 { 803 return IS_5413(ah); 804 } 805 AH_RF(RF5413, ar5413Probe, ar5413RfAttach); 806