ar5112.c revision 185377
190075Sobrien/* 2132718Skan * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 390075Sobrien * Copyright (c) 2002-2008 Atheros Communications, Inc. 490075Sobrien * 590075Sobrien * Permission to use, copy, modify, and/or distribute this software for any 690075Sobrien * purpose with or without fee is hereby granted, provided that the above 790075Sobrien * copyright notice and this permission notice appear in all copies. 890075Sobrien * 990075Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1090075Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1190075Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1290075Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1390075Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1490075Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1590075Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1690075Sobrien * 1790075Sobrien * $Id: ar5112.c,v 1.7 2008/11/10 04:08:03 sam Exp $ 1890075Sobrien */ 1990075Sobrien#include "opt_ah.h" 2090075Sobrien 2190075Sobrien#ifdef AH_SUPPORT_5112 2290075Sobrien 2390075Sobrien#include "ah.h" 2490075Sobrien#include "ah_internal.h" 2590075Sobrien 2690075Sobrien#include "ah_eeprom_v3.h" 2790075Sobrien 2890075Sobrien#include "ar5212/ar5212.h" 2990075Sobrien#include "ar5212/ar5212reg.h" 3090075Sobrien#include "ar5212/ar5212phy.h" 31132718Skan 32132718Skan#define AH_5212_5112 3390075Sobrien#include "ar5212/ar5212.ini" 3490075Sobrien 3590075Sobrien#define N(a) (sizeof(a)/sizeof(a[0])) 3690075Sobrien 3790075Sobrienstruct ar5112State { 3890075Sobrien RF_HAL_FUNCS base; /* public state, must be first */ 3990075Sobrien uint16_t pcdacTable[PWR_TABLE_SIZE]; 4090075Sobrien 4190075Sobrien uint32_t Bank1Data[N(ar5212Bank1_5112)]; 4290075Sobrien uint32_t Bank2Data[N(ar5212Bank2_5112)]; 4390075Sobrien uint32_t Bank3Data[N(ar5212Bank3_5112)]; 4490075Sobrien uint32_t Bank6Data[N(ar5212Bank6_5112)]; 4590075Sobrien uint32_t Bank7Data[N(ar5212Bank7_5112)]; 4690075Sobrien}; 4790075Sobrien#define AR5112(ah) ((struct ar5112State *) AH5212(ah)->ah_rfHal) 4890075Sobrien 4990075Sobrienstatic void ar5212GetLowerUpperIndex(uint16_t v, 5090075Sobrien uint16_t *lp, uint16_t listSize, 5190075Sobrien uint32_t *vlo, uint32_t *vhi); 5290075Sobrienstatic HAL_BOOL getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs, 5390075Sobrien int16_t *power, int16_t maxPower, int16_t *retVals); 5490075Sobrienstatic int16_t getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4, 5590075Sobrien uint16_t retVals[]); 5690075Sobrienstatic int16_t getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4, 5790075Sobrien int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid); 5890075Sobrienstatic int16_t interpolate_signed(uint16_t target, 5990075Sobrien uint16_t srcLeft, uint16_t srcRight, 60117395Skan int16_t targetLeft, int16_t targetRight); 6190075Sobrien 6290075Sobrienextern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, 6390075Sobrien uint32_t numBits, uint32_t firstBit, uint32_t column); 6490075Sobrien 6590075Sobrienstatic void 6690075Sobrienar5112WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, 6790075Sobrien int writes) 6890075Sobrien{ 6990075Sobrien HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5112, modesIndex, writes); 7090075Sobrien HAL_INI_WRITE_ARRAY(ah, ar5212Common_5112, 1, writes); 7190075Sobrien HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5112, freqIndex, writes); 7290075Sobrien} 7390075Sobrien 7490075Sobrien/* 7590075Sobrien * Take the MHz channel value and set the Channel value 7690075Sobrien * 7790075Sobrien * ASSUMES: Writes enabled to analog bus 7890075Sobrien */ 79132718Skanstatic HAL_BOOL 8090075Sobrienar5112SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) 8190075Sobrien{ 8290075Sobrien uint32_t channelSel = 0; 8390075Sobrien uint32_t bModeSynth = 0; 8490075Sobrien uint32_t aModeRefSel = 0; 85132718Skan uint32_t reg32 = 0; 86 uint16_t freq; 87 88 OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); 89 90 if (chan->channel < 4800) { 91 uint32_t txctl; 92 93 if (((chan->channel - 2192) % 5) == 0) { 94 channelSel = ((chan->channel - 672) * 2 - 3040)/10; 95 bModeSynth = 0; 96 } else if (((chan->channel - 2224) % 5) == 0) { 97 channelSel = ((chan->channel - 704) * 2 - 3040) / 10; 98 bModeSynth = 1; 99 } else { 100 HALDEBUG(ah, HAL_DEBUG_ANY, 101 "%s: invalid channel %u MHz\n", 102 __func__, chan->channel); 103 return AH_FALSE; 104 } 105 106 channelSel = (channelSel << 2) & 0xff; 107 channelSel = ath_hal_reverseBits(channelSel, 8); 108 109 txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); 110 if (chan->channel == 2484) { 111 /* Enable channel spreading for channel 14 */ 112 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 113 txctl | AR_PHY_CCK_TX_CTRL_JAPAN); 114 } else { 115 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 116 txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); 117 } 118 } else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) { 119 freq = chan->channel - 2; /* Align to even 5MHz raster */ 120 channelSel = ath_hal_reverseBits( 121 (uint32_t)(((freq - 4800)*10)/25 + 1), 8); 122 aModeRefSel = ath_hal_reverseBits(0, 2); 123 } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) { 124 channelSel = ath_hal_reverseBits( 125 ((chan->channel - 4800) / 20 << 2), 8); 126 aModeRefSel = ath_hal_reverseBits(3, 2); 127 } else if ((chan->channel % 10) == 0) { 128 channelSel = ath_hal_reverseBits( 129 ((chan->channel - 4800) / 10 << 1), 8); 130 aModeRefSel = ath_hal_reverseBits(2, 2); 131 } else if ((chan->channel % 5) == 0) { 132 channelSel = ath_hal_reverseBits( 133 (chan->channel - 4800) / 5, 8); 134 aModeRefSel = ath_hal_reverseBits(1, 2); 135 } else { 136 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", 137 __func__, chan->channel); 138 return AH_FALSE; 139 } 140 141 reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | 142 (1 << 12) | 0x1; 143 OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); 144 145 reg32 >>= 8; 146 OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); 147 148 AH_PRIVATE(ah)->ah_curchan = chan; 149 return AH_TRUE; 150} 151 152/* 153 * Return a reference to the requested RF Bank. 154 */ 155static uint32_t * 156ar5112GetRfBank(struct ath_hal *ah, int bank) 157{ 158 struct ar5112State *priv = AR5112(ah); 159 160 HALASSERT(priv != AH_NULL); 161 switch (bank) { 162 case 1: return priv->Bank1Data; 163 case 2: return priv->Bank2Data; 164 case 3: return priv->Bank3Data; 165 case 6: return priv->Bank6Data; 166 case 7: return priv->Bank7Data; 167 } 168 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", 169 __func__, bank); 170 return AH_NULL; 171} 172 173/* 174 * Reads EEPROM header info from device structure and programs 175 * all rf registers 176 * 177 * REQUIRES: Access to the analog rf device 178 */ 179static HAL_BOOL 180ar5112SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, 181 uint16_t modesIndex, uint16_t *rfXpdGain) 182{ 183#define RF_BANK_SETUP(_priv, _ix, _col) do { \ 184 int i; \ 185 for (i = 0; i < N(ar5212Bank##_ix##_5112); i++) \ 186 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5112[i][_col];\ 187} while (0) 188 struct ath_hal_5212 *ahp = AH5212(ah); 189 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 190 uint16_t rfXpdSel, gainI; 191 uint16_t ob5GHz = 0, db5GHz = 0; 192 uint16_t ob2GHz = 0, db2GHz = 0; 193 struct ar5112State *priv = AR5112(ah); 194 GAIN_VALUES *gv = &ahp->ah_gainValues; 195 int regWrites = 0; 196 197 HALASSERT(priv); 198 199 /* Setup rf parameters */ 200 switch (chan->channelFlags & CHANNEL_ALL) { 201 case CHANNEL_A: 202 case CHANNEL_T: 203 if (chan->channel > 4000 && chan->channel < 5260) { 204 ob5GHz = ee->ee_ob1; 205 db5GHz = ee->ee_db1; 206 } else if (chan->channel >= 5260 && chan->channel < 5500) { 207 ob5GHz = ee->ee_ob2; 208 db5GHz = ee->ee_db2; 209 } else if (chan->channel >= 5500 && chan->channel < 5725) { 210 ob5GHz = ee->ee_ob3; 211 db5GHz = ee->ee_db3; 212 } else if (chan->channel >= 5725) { 213 ob5GHz = ee->ee_ob4; 214 db5GHz = ee->ee_db4; 215 } else { 216 /* XXX else */ 217 } 218 rfXpdSel = ee->ee_xpd[headerInfo11A]; 219 gainI = ee->ee_gainI[headerInfo11A]; 220 break; 221 case CHANNEL_B: 222 ob2GHz = ee->ee_ob2GHz[0]; 223 db2GHz = ee->ee_db2GHz[0]; 224 rfXpdSel = ee->ee_xpd[headerInfo11B]; 225 gainI = ee->ee_gainI[headerInfo11B]; 226 break; 227 case CHANNEL_G: 228 case CHANNEL_108G: 229 ob2GHz = ee->ee_ob2GHz[1]; 230 db2GHz = ee->ee_ob2GHz[1]; 231 rfXpdSel = ee->ee_xpd[headerInfo11G]; 232 gainI = ee->ee_gainI[headerInfo11G]; 233 break; 234 default: 235 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", 236 __func__, chan->channelFlags); 237 return AH_FALSE; 238 } 239 240 /* Setup Bank 1 Write */ 241 RF_BANK_SETUP(priv, 1, 1); 242 243 /* Setup Bank 2 Write */ 244 RF_BANK_SETUP(priv, 2, modesIndex); 245 246 /* Setup Bank 3 Write */ 247 RF_BANK_SETUP(priv, 3, modesIndex); 248 249 /* Setup Bank 6 Write */ 250 RF_BANK_SETUP(priv, 6, modesIndex); 251 252 ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdSel, 1, 302, 0); 253 254 ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[0], 2, 270, 0); 255 ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[1], 2, 257, 0); 256 257 if (IS_CHAN_OFDM(chan)) { 258 ar5212ModifyRfBuffer(priv->Bank6Data, 259 gv->currStep->paramVal[GP_PWD_138], 1, 168, 3); 260 ar5212ModifyRfBuffer(priv->Bank6Data, 261 gv->currStep->paramVal[GP_PWD_137], 1, 169, 3); 262 ar5212ModifyRfBuffer(priv->Bank6Data, 263 gv->currStep->paramVal[GP_PWD_136], 1, 170, 3); 264 ar5212ModifyRfBuffer(priv->Bank6Data, 265 gv->currStep->paramVal[GP_PWD_132], 1, 174, 3); 266 ar5212ModifyRfBuffer(priv->Bank6Data, 267 gv->currStep->paramVal[GP_PWD_131], 1, 175, 3); 268 ar5212ModifyRfBuffer(priv->Bank6Data, 269 gv->currStep->paramVal[GP_PWD_130], 1, 176, 3); 270 } 271 272 /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ 273 if (IS_CHAN_2GHZ(chan)) { 274 ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 287, 0); 275 ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 290, 0); 276 } else { 277 ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 279, 0); 278 ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 282, 0); 279 } 280 281 /* Lower synth voltage for X112 Rev 2.0 only */ 282 if (IS_RADX112_REV2(ah)) { 283 /* Non-Reversed analyg registers - so values are pre-reversed */ 284 ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 90, 2); 285 ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 92, 2); 286 ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 94, 2); 287 ar5212ModifyRfBuffer(priv->Bank6Data, 2, 1, 254, 2); 288 } 289 290 /* Decrease Power Consumption for 5312/5213 and up */ 291 if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { 292 ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 281, 1); 293 ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 1, 3); 294 ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 3, 3); 295 ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 139, 3); 296 ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 140, 3); 297 } 298 299 /* Setup Bank 7 Setup */ 300 RF_BANK_SETUP(priv, 7, modesIndex); 301 if (IS_CHAN_OFDM(chan)) 302 ar5212ModifyRfBuffer(priv->Bank7Data, 303 gv->currStep->paramVal[GP_MIXGAIN_OVR], 2, 37, 0); 304 305 ar5212ModifyRfBuffer(priv->Bank7Data, gainI, 6, 14, 0); 306 307 /* Adjust params for Derby TX power control */ 308 if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) { 309 uint32_t rfDelay, rfPeriod; 310 311 rfDelay = 0xf; 312 rfPeriod = (IS_CHAN_HALF_RATE(chan)) ? 0x8 : 0xf; 313 ar5212ModifyRfBuffer(priv->Bank7Data, rfDelay, 4, 58, 0); 314 ar5212ModifyRfBuffer(priv->Bank7Data, rfPeriod, 4, 70, 0); 315 } 316 317#ifdef notyet 318 /* Analog registers are setup - EAR can modify */ 319 if (ar5212IsEarEngaged(pDev, chan)) 320 uint32_t modifier; 321 ar5212EarModify(pDev, EAR_LC_RF_WRITE, chan, &modifier); 322#endif 323 /* Write Analog registers */ 324 HAL_INI_WRITE_BANK(ah, ar5212Bank1_5112, priv->Bank1Data, regWrites); 325 HAL_INI_WRITE_BANK(ah, ar5212Bank2_5112, priv->Bank2Data, regWrites); 326 HAL_INI_WRITE_BANK(ah, ar5212Bank3_5112, priv->Bank3Data, regWrites); 327 HAL_INI_WRITE_BANK(ah, ar5212Bank6_5112, priv->Bank6Data, regWrites); 328 HAL_INI_WRITE_BANK(ah, ar5212Bank7_5112, priv->Bank7Data, regWrites); 329 330 /* Now that we have reprogrammed rfgain value, clear the flag. */ 331 ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; 332 return AH_TRUE; 333#undef RF_BANK_SETUP 334} 335 336/* 337 * Read the transmit power levels from the structures taken from EEPROM 338 * Interpolate read transmit power values for this channel 339 * Organize the transmit power values into a table for writing into the hardware 340 */ 341static HAL_BOOL 342ar5112SetPowerTable(struct ath_hal *ah, 343 int16_t *pPowerMin, int16_t *pPowerMax, HAL_CHANNEL_INTERNAL *chan, 344 uint16_t *rfXpdGain) 345{ 346 struct ath_hal_5212 *ahp = AH5212(ah); 347 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 348 uint32_t numXpdGain = IS_RADX112_REV2(ah) ? 2 : 1; 349 uint32_t xpdGainMask = 0; 350 int16_t powerMid, *pPowerMid = &powerMid; 351 352 const EXPN_DATA_PER_CHANNEL_5112 *pRawCh; 353 const EEPROM_POWER_EXPN_5112 *pPowerExpn = AH_NULL; 354 355 uint32_t ii, jj, kk; 356 int16_t minPwr_t4, maxPwr_t4, Pmin, Pmid; 357 358 uint32_t chan_idx_L = 0, chan_idx_R = 0; 359 uint16_t chan_L, chan_R; 360 361 int16_t pwr_table0[64]; 362 int16_t pwr_table1[64]; 363 uint16_t pcdacs[10]; 364 int16_t powers[10]; 365 uint16_t numPcd; 366 int16_t powTableLXPD[2][64]; 367 int16_t powTableHXPD[2][64]; 368 int16_t tmpPowerTable[64]; 369 uint16_t xgainList[2]; 370 uint16_t xpdMask; 371 372 switch (chan->channelFlags & CHANNEL_ALL) { 373 case CHANNEL_A: 374 case CHANNEL_T: 375 pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11A]; 376 xpdGainMask = ee->ee_xgain[headerInfo11A]; 377 break; 378 case CHANNEL_B: 379 pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11B]; 380 xpdGainMask = ee->ee_xgain[headerInfo11B]; 381 break; 382 case CHANNEL_G: 383 case CHANNEL_108G: 384 pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11G]; 385 xpdGainMask = ee->ee_xgain[headerInfo11G]; 386 break; 387 default: 388 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown channel flags 0x%x\n", 389 __func__, chan->channelFlags & CHANNEL_ALL); 390 return AH_FALSE; 391 } 392 393 if ((xpdGainMask & pPowerExpn->xpdMask) < 1) { 394 HALDEBUG(ah, HAL_DEBUG_ANY, 395 "%s: desired xpdGainMask 0x%x not supported by " 396 "calibrated xpdMask 0x%x\n", __func__, 397 xpdGainMask, pPowerExpn->xpdMask); 398 return AH_FALSE; 399 } 400 401 maxPwr_t4 = (int16_t)(2*(*pPowerMax)); /* pwr_t2 -> pwr_t4 */ 402 minPwr_t4 = (int16_t)(2*(*pPowerMin)); /* pwr_t2 -> pwr_t4 */ 403 404 xgainList[0] = 0xDEAD; 405 xgainList[1] = 0xDEAD; 406 407 kk = 0; 408 xpdMask = pPowerExpn->xpdMask; 409 for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) { 410 if (((xpdMask >> jj) & 1) > 0) { 411 if (kk > 1) { 412 HALDEBUG(ah, HAL_DEBUG_ANY, 413 "A maximum of 2 xpdGains supported" 414 "in pExpnPower data\n"); 415 return AH_FALSE; 416 } 417 xgainList[kk++] = (uint16_t)jj; 418 } 419 } 420 421 ar5212GetLowerUpperIndex(chan->channel, &pPowerExpn->pChannels[0], 422 pPowerExpn->numChannels, &chan_idx_L, &chan_idx_R); 423 424 kk = 0; 425 for (ii = chan_idx_L; ii <= chan_idx_R; ii++) { 426 pRawCh = &(pPowerExpn->pDataPerChannel[ii]); 427 if (xgainList[1] == 0xDEAD) { 428 jj = xgainList[0]; 429 numPcd = pRawCh->pDataPerXPD[jj].numPcdacs; 430 OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0], 431 numPcd * sizeof(uint16_t)); 432 OS_MEMCPY(&powers[0], &pRawCh->pDataPerXPD[jj].pwr_t4[0], 433 numPcd * sizeof(int16_t)); 434 if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0], 435 pRawCh->maxPower_t4, &tmpPowerTable[0])) { 436 return AH_FALSE; 437 } 438 OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0], 439 64*sizeof(int16_t)); 440 } else { 441 jj = xgainList[0]; 442 numPcd = pRawCh->pDataPerXPD[jj].numPcdacs; 443 OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0], 444 numPcd*sizeof(uint16_t)); 445 OS_MEMCPY(&powers[0], 446 &pRawCh->pDataPerXPD[jj].pwr_t4[0], 447 numPcd*sizeof(int16_t)); 448 if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0], 449 pRawCh->maxPower_t4, &tmpPowerTable[0])) { 450 return AH_FALSE; 451 } 452 OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0], 453 64 * sizeof(int16_t)); 454 455 jj = xgainList[1]; 456 numPcd = pRawCh->pDataPerXPD[jj].numPcdacs; 457 OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0], 458 numPcd * sizeof(uint16_t)); 459 OS_MEMCPY(&powers[0], 460 &pRawCh->pDataPerXPD[jj].pwr_t4[0], 461 numPcd * sizeof(int16_t)); 462 if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0], 463 pRawCh->maxPower_t4, &tmpPowerTable[0])) { 464 return AH_FALSE; 465 } 466 OS_MEMCPY(&powTableHXPD[kk][0], &tmpPowerTable[0], 467 64 * sizeof(int16_t)); 468 } 469 kk++; 470 } 471 472 chan_L = pPowerExpn->pChannels[chan_idx_L]; 473 chan_R = pPowerExpn->pChannels[chan_idx_R]; 474 kk = chan_idx_R - chan_idx_L; 475 476 if (xgainList[1] == 0xDEAD) { 477 for (jj = 0; jj < 64; jj++) { 478 pwr_table0[jj] = interpolate_signed( 479 chan->channel, chan_L, chan_R, 480 powTableLXPD[0][jj], powTableLXPD[kk][jj]); 481 } 482 Pmin = getPminAndPcdacTableFromPowerTable(&pwr_table0[0], 483 ahp->ah_pcdacTable); 484 *pPowerMin = (int16_t) (Pmin / 2); 485 *pPowerMid = (int16_t) (pwr_table0[63] / 2); 486 *pPowerMax = (int16_t) (pwr_table0[63] / 2); 487 rfXpdGain[0] = xgainList[0]; 488 rfXpdGain[1] = rfXpdGain[0]; 489 } else { 490 for (jj = 0; jj < 64; jj++) { 491 pwr_table0[jj] = interpolate_signed( 492 chan->channel, chan_L, chan_R, 493 powTableLXPD[0][jj], powTableLXPD[kk][jj]); 494 pwr_table1[jj] = interpolate_signed( 495 chan->channel, chan_L, chan_R, 496 powTableHXPD[0][jj], powTableHXPD[kk][jj]); 497 } 498 if (numXpdGain == 2) { 499 Pmin = getPminAndPcdacTableFromTwoPowerTables( 500 &pwr_table0[0], &pwr_table1[0], 501 ahp->ah_pcdacTable, &Pmid); 502 *pPowerMin = (int16_t) (Pmin / 2); 503 *pPowerMid = (int16_t) (Pmid / 2); 504 *pPowerMax = (int16_t) (pwr_table0[63] / 2); 505 rfXpdGain[0] = xgainList[0]; 506 rfXpdGain[1] = xgainList[1]; 507 } else if (minPwr_t4 <= pwr_table1[63] && 508 maxPwr_t4 <= pwr_table1[63]) { 509 Pmin = getPminAndPcdacTableFromPowerTable( 510 &pwr_table1[0], ahp->ah_pcdacTable); 511 rfXpdGain[0] = xgainList[1]; 512 rfXpdGain[1] = rfXpdGain[0]; 513 *pPowerMin = (int16_t) (Pmin / 2); 514 *pPowerMid = (int16_t) (pwr_table1[63] / 2); 515 *pPowerMax = (int16_t) (pwr_table1[63] / 2); 516 } else { 517 Pmin = getPminAndPcdacTableFromPowerTable( 518 &pwr_table0[0], ahp->ah_pcdacTable); 519 rfXpdGain[0] = xgainList[0]; 520 rfXpdGain[1] = rfXpdGain[0]; 521 *pPowerMin = (int16_t) (Pmin/2); 522 *pPowerMid = (int16_t) (pwr_table0[63] / 2); 523 *pPowerMax = (int16_t) (pwr_table0[63] / 2); 524 } 525 } 526 527 /* 528 * Move 5112 rates to match power tables where the max 529 * power table entry corresponds with maxPower. 530 */ 531 HALASSERT(*pPowerMax <= PCDAC_STOP); 532 ahp->ah_txPowerIndexOffset = PCDAC_STOP - *pPowerMax; 533 534 return AH_TRUE; 535} 536 537/* 538 * Returns interpolated or the scaled up interpolated value 539 */ 540static int16_t 541interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, 542 int16_t targetLeft, int16_t targetRight) 543{ 544 int16_t rv; 545 546 if (srcRight != srcLeft) { 547 rv = ((target - srcLeft)*targetRight + 548 (srcRight - target)*targetLeft) / (srcRight - srcLeft); 549 } else { 550 rv = targetLeft; 551 } 552 return rv; 553} 554 555/* 556 * Return indices surrounding the value in sorted integer lists. 557 * 558 * NB: the input list is assumed to be sorted in ascending order 559 */ 560static void 561ar5212GetLowerUpperIndex(uint16_t v, uint16_t *lp, uint16_t listSize, 562 uint32_t *vlo, uint32_t *vhi) 563{ 564 uint32_t target = v; 565 uint16_t *ep = lp+listSize; 566 uint16_t *tp; 567 568 /* 569 * Check first and last elements for out-of-bounds conditions. 570 */ 571 if (target < lp[0]) { 572 *vlo = *vhi = 0; 573 return; 574 } 575 if (target >= ep[-1]) { 576 *vlo = *vhi = listSize - 1; 577 return; 578 } 579 580 /* look for value being near or between 2 values in list */ 581 for (tp = lp; tp < ep; tp++) { 582 /* 583 * If value is close to the current value of the list 584 * then target is not between values, it is one of the values 585 */ 586 if (*tp == target) { 587 *vlo = *vhi = tp - lp; 588 return; 589 } 590 /* 591 * Look for value being between current value and next value 592 * if so return these 2 values 593 */ 594 if (target < tp[1]) { 595 *vlo = tp - lp; 596 *vhi = *vlo + 1; 597 return; 598 } 599 } 600} 601 602static HAL_BOOL 603getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs, int16_t *power, int16_t maxPower, int16_t *retVals) 604{ 605 uint16_t ii; 606 uint16_t idxL = 0; 607 uint16_t idxR = 1; 608 609 if (numPcdacs < 2) { 610 HALDEBUG(AH_NULL, HAL_DEBUG_ANY, 611 "%s: at least 2 pcdac values needed [%d]\n", 612 __func__, numPcdacs); 613 return AH_FALSE; 614 } 615 for (ii = 0; ii < 64; ii++) { 616 if (ii>pcdacs[idxR] && idxR < numPcdacs-1) { 617 idxL++; 618 idxR++; 619 } 620 retVals[ii] = interpolate_signed(ii, 621 pcdacs[idxL], pcdacs[idxR], power[idxL], power[idxR]); 622 if (retVals[ii] >= maxPower) { 623 while (ii < 64) 624 retVals[ii++] = maxPower; 625 } 626 } 627 return AH_TRUE; 628} 629 630/* 631 * Takes a single calibration curve and creates a power table. 632 * Adjusts the new power table so the max power is relative 633 * to the maximum index in the power table. 634 * 635 * WARNING: rates must be adjusted for this relative power table 636 */ 637static int16_t 638getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4, uint16_t retVals[]) 639{ 640 int16_t ii, jj, jjMax; 641 int16_t pMin, currPower, pMax; 642 643 /* If the spread is > 31.5dB, keep the upper 31.5dB range */ 644 if ((pwrTableT4[63] - pwrTableT4[0]) > 126) { 645 pMin = pwrTableT4[63] - 126; 646 } else { 647 pMin = pwrTableT4[0]; 648 } 649 650 pMax = pwrTableT4[63]; 651 jjMax = 63; 652 653 /* Search for highest pcdac 0.25dB below maxPower */ 654 while ((pwrTableT4[jjMax] > (pMax - 1) ) && (jjMax >= 0)) { 655 jjMax--; 656 } 657 658 jj = jjMax; 659 currPower = pMax; 660 for (ii = 63; ii >= 0; ii--) { 661 while ((jj < 64) && (jj > 0) && (pwrTableT4[jj] >= currPower)) { 662 jj--; 663 } 664 if (jj == 0) { 665 while (ii >= 0) { 666 retVals[ii] = retVals[ii + 1]; 667 ii--; 668 } 669 break; 670 } 671 retVals[ii] = jj; 672 currPower -= 2; // corresponds to a 0.5dB step 673 } 674 return pMin; 675} 676 677/* 678 * Combines the XPD curves from two calibration sets into a single 679 * power table and adjusts the power table so the max power is relative 680 * to the maximum index in the power table 681 * 682 * WARNING: rates must be adjusted for this relative power table 683 */ 684static int16_t 685getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4, 686 int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid) 687{ 688 int16_t ii, jj, jjMax; 689 int16_t pMin, pMax, currPower; 690 int16_t *pwrTableT4; 691 uint16_t msbFlag = 0x40; // turns on the 7th bit of the pcdac 692 693 /* If the spread is > 31.5dB, keep the upper 31.5dB range */ 694 if ((pwrTableLXpdT4[63] - pwrTableHXpdT4[0]) > 126) { 695 pMin = pwrTableLXpdT4[63] - 126; 696 } else { 697 pMin = pwrTableHXpdT4[0]; 698 } 699 700 pMax = pwrTableLXpdT4[63]; 701 jjMax = 63; 702 /* Search for highest pcdac 0.25dB below maxPower */ 703 while ((pwrTableLXpdT4[jjMax] > (pMax - 1) ) && (jjMax >= 0)){ 704 jjMax--; 705 } 706 707 *pMid = pwrTableHXpdT4[63]; 708 jj = jjMax; 709 ii = 63; 710 currPower = pMax; 711 pwrTableT4 = &(pwrTableLXpdT4[0]); 712 while (ii >= 0) { 713 if ((currPower <= *pMid) || ( (jj == 0) && (msbFlag == 0x40))){ 714 msbFlag = 0x00; 715 pwrTableT4 = &(pwrTableHXpdT4[0]); 716 jj = 63; 717 } 718 while ((jj > 0) && (pwrTableT4[jj] >= currPower)) { 719 jj--; 720 } 721 if ((jj == 0) && (msbFlag == 0x00)) { 722 while (ii >= 0) { 723 retVals[ii] = retVals[ii+1]; 724 ii--; 725 } 726 break; 727 } 728 retVals[ii] = jj | msbFlag; 729 currPower -= 2; // corresponds to a 0.5dB step 730 ii--; 731 } 732 return pMin; 733} 734 735static int16_t 736ar5112GetMinPower(struct ath_hal *ah, const EXPN_DATA_PER_CHANNEL_5112 *data) 737{ 738 int i, minIndex; 739 int16_t minGain,minPwr,minPcdac,retVal; 740 741 /* Assume NUM_POINTS_XPD0 > 0 */ 742 minGain = data->pDataPerXPD[0].xpd_gain; 743 for (minIndex=0,i=1; i<NUM_XPD_PER_CHANNEL; i++) { 744 if (data->pDataPerXPD[i].xpd_gain < minGain) { 745 minIndex = i; 746 minGain = data->pDataPerXPD[i].xpd_gain; 747 } 748 } 749 minPwr = data->pDataPerXPD[minIndex].pwr_t4[0]; 750 minPcdac = data->pDataPerXPD[minIndex].pcdac[0]; 751 for (i=1; i<NUM_POINTS_XPD0; i++) { 752 if (data->pDataPerXPD[minIndex].pwr_t4[i] < minPwr) { 753 minPwr = data->pDataPerXPD[minIndex].pwr_t4[i]; 754 minPcdac = data->pDataPerXPD[minIndex].pcdac[i]; 755 } 756 } 757 retVal = minPwr - (minPcdac*2); 758 return(retVal); 759} 760 761static HAL_BOOL 762ar5112GetChannelMaxMinPower(struct ath_hal *ah, HAL_CHANNEL *chan, 763 int16_t *maxPow, int16_t *minPow) 764{ 765 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 766 int numChannels=0,i,last; 767 int totalD, totalF,totalMin; 768 const EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL; 769 const EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL; 770 771 *maxPow = 0; 772 if (IS_CHAN_A(chan)) { 773 powerArray = ee->ee_modePowerArray5112; 774 data = powerArray[headerInfo11A].pDataPerChannel; 775 numChannels = powerArray[headerInfo11A].numChannels; 776 } else if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) { 777 /* XXX - is this correct? Should we also use the same power for turbo G? */ 778 powerArray = ee->ee_modePowerArray5112; 779 data = powerArray[headerInfo11G].pDataPerChannel; 780 numChannels = powerArray[headerInfo11G].numChannels; 781 } else if (IS_CHAN_B(chan)) { 782 powerArray = ee->ee_modePowerArray5112; 783 data = powerArray[headerInfo11B].pDataPerChannel; 784 numChannels = powerArray[headerInfo11B].numChannels; 785 } else { 786 return (AH_TRUE); 787 } 788 /* Make sure the channel is in the range of the TP values 789 * (freq piers) 790 */ 791 if (numChannels < 1) 792 return(AH_FALSE); 793 794 if ((chan->channel < data[0].channelValue) || 795 (chan->channel > data[numChannels-1].channelValue)) { 796 if (chan->channel < data[0].channelValue) { 797 *maxPow = data[0].maxPower_t4; 798 *minPow = ar5112GetMinPower(ah, &data[0]); 799 return(AH_TRUE); 800 } else { 801 *maxPow = data[numChannels - 1].maxPower_t4; 802 *minPow = ar5112GetMinPower(ah, &data[numChannels - 1]); 803 return(AH_TRUE); 804 } 805 } 806 807 /* Linearly interpolate the power value now */ 808 for (last=0,i=0; 809 (i<numChannels) && (chan->channel > data[i].channelValue); 810 last=i++); 811 totalD = data[i].channelValue - data[last].channelValue; 812 if (totalD > 0) { 813 totalF = data[i].maxPower_t4 - data[last].maxPower_t4; 814 *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + data[last].maxPower_t4*totalD)/totalD); 815 816 totalMin = ar5112GetMinPower(ah,&data[i]) - ar5112GetMinPower(ah, &data[last]); 817 *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + ar5112GetMinPower(ah, &data[last])*totalD)/totalD); 818 return (AH_TRUE); 819 } else { 820 if (chan->channel == data[i].channelValue) { 821 *maxPow = data[i].maxPower_t4; 822 *minPow = ar5112GetMinPower(ah, &data[i]); 823 return(AH_TRUE); 824 } else 825 return(AH_FALSE); 826 } 827} 828 829/* 830 * Free memory for analog bank scratch buffers 831 */ 832static void 833ar5112RfDetach(struct ath_hal *ah) 834{ 835 struct ath_hal_5212 *ahp = AH5212(ah); 836 837 HALASSERT(ahp->ah_rfHal != AH_NULL); 838 ath_hal_free(ahp->ah_rfHal); 839 ahp->ah_rfHal = AH_NULL; 840} 841 842/* 843 * Allocate memory for analog bank scratch buffers 844 * Scratch Buffer will be reinitialized every reset so no need to zero now 845 */ 846HAL_BOOL 847ar5112RfAttach(struct ath_hal *ah, HAL_STATUS *status) 848{ 849 struct ath_hal_5212 *ahp = AH5212(ah); 850 struct ar5112State *priv; 851 852 HALASSERT(ah->ah_magic == AR5212_MAGIC); 853 854 HALASSERT(ahp->ah_rfHal == AH_NULL); 855 priv = ath_hal_malloc(sizeof(struct ar5112State)); 856 if (priv == AH_NULL) { 857 HALDEBUG(ah, HAL_DEBUG_ANY, 858 "%s: cannot allocate private state\n", __func__); 859 *status = HAL_ENOMEM; /* XXX */ 860 return AH_FALSE; 861 } 862 priv->base.rfDetach = ar5112RfDetach; 863 priv->base.writeRegs = ar5112WriteRegs; 864 priv->base.getRfBank = ar5112GetRfBank; 865 priv->base.setChannel = ar5112SetChannel; 866 priv->base.setRfRegs = ar5112SetRfRegs; 867 priv->base.setPowerTable = ar5112SetPowerTable; 868 priv->base.getChannelMaxMinPower = ar5112GetChannelMaxMinPower; 869 priv->base.getNfAdjust = ar5212GetNfAdjust; 870 871 ahp->ah_pcdacTable = priv->pcdacTable; 872 ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); 873 ahp->ah_rfHal = &priv->base; 874 875 return AH_TRUE; 876} 877#endif /* AH_SUPPORT_5112 */ 878