1 /*- 2 * SPDX-License-Identifier: ISC 3 * 4 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 5 * Copyright (c) 2002-2008 Atheros Communications, Inc. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 * 19 * $FreeBSD$ 20 */ 21 #include "opt_ah.h" 22 23 #include "ah.h" 24 #include "ah_internal.h" 25 26 #include "ah_eeprom_v3.h" 27 28 #include "ar5212/ar5212.h" 29 #include "ar5212/ar5212reg.h" 30 #include "ar5212/ar5212phy.h" 31 32 #define AH_5212_5111 33 #include "ar5212/ar5212.ini" 34 35 #define N(a) (sizeof(a)/sizeof(a[0])) 36 37 struct ar5111State { 38 RF_HAL_FUNCS base; /* public state, must be first */ 39 uint16_t pcdacTable[PWR_TABLE_SIZE]; 40 41 uint32_t Bank0Data[N(ar5212Bank0_5111)]; 42 uint32_t Bank1Data[N(ar5212Bank1_5111)]; 43 uint32_t Bank2Data[N(ar5212Bank2_5111)]; 44 uint32_t Bank3Data[N(ar5212Bank3_5111)]; 45 uint32_t Bank6Data[N(ar5212Bank6_5111)]; 46 uint32_t Bank7Data[N(ar5212Bank7_5111)]; 47 }; 48 #define AR5111(ah) ((struct ar5111State *) AH5212(ah)->ah_rfHal) 49 50 static uint16_t ar5212GetScaledPower(uint16_t channel, uint16_t pcdacValue, 51 const PCDACS_EEPROM *pSrcStruct); 52 static HAL_BOOL ar5212FindValueInList(uint16_t channel, uint16_t pcdacValue, 53 const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue); 54 static void ar5212GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel, 55 const PCDACS_EEPROM *pSrcStruct, 56 uint16_t *pLowerPcdac, uint16_t *pUpperPcdac); 57 58 extern void ar5212GetLowerUpperValues(uint16_t value, 59 const uint16_t *pList, uint16_t listSize, 60 uint16_t *pLowerValue, uint16_t *pUpperValue); 61 extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, 62 uint32_t numBits, uint32_t firstBit, uint32_t column); 63 64 static void 65 ar5111WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, 66 int writes) 67 { 68 HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5111, modesIndex, writes); 69 HAL_INI_WRITE_ARRAY(ah, ar5212Common_5111, 1, writes); 70 HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5111, freqIndex, writes); 71 } 72 73 /* 74 * Take the MHz channel value and set the Channel value 75 * 76 * ASSUMES: Writes enabled to analog bus 77 */ 78 static HAL_BOOL 79 ar5111SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) 80 { 81 #define CI_2GHZ_INDEX_CORRECTION 19 82 uint16_t freq = ath_hal_gethwchannel(ah, chan); 83 uint32_t refClk, reg32, data2111; 84 int16_t chan5111, chanIEEE; 85 86 /* 87 * Structure to hold 11b tuning information for 5111/2111 88 * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12 89 */ 90 typedef struct { 91 uint32_t refClkSel; /* reference clock, 1 for 16 MHz */ 92 uint32_t channelSelect; /* P[7:4]S[3:0] bits */ 93 uint16_t channel5111; /* 11a channel for 5111 */ 94 } CHAN_INFO_2GHZ; 95 96 static const CHAN_INFO_2GHZ chan2GHzData[] = { 97 { 1, 0x46, 96 }, /* 2312 -19 */ 98 { 1, 0x46, 97 }, /* 2317 -18 */ 99 { 1, 0x46, 98 }, /* 2322 -17 */ 100 { 1, 0x46, 99 }, /* 2327 -16 */ 101 { 1, 0x46, 100 }, /* 2332 -15 */ 102 { 1, 0x46, 101 }, /* 2337 -14 */ 103 { 1, 0x46, 102 }, /* 2342 -13 */ 104 { 1, 0x46, 103 }, /* 2347 -12 */ 105 { 1, 0x46, 104 }, /* 2352 -11 */ 106 { 1, 0x46, 105 }, /* 2357 -10 */ 107 { 1, 0x46, 106 }, /* 2362 -9 */ 108 { 1, 0x46, 107 }, /* 2367 -8 */ 109 { 1, 0x46, 108 }, /* 2372 -7 */ 110 /* index -6 to 0 are pad to make this a nolookup table */ 111 { 1, 0x46, 116 }, /* -6 */ 112 { 1, 0x46, 116 }, /* -5 */ 113 { 1, 0x46, 116 }, /* -4 */ 114 { 1, 0x46, 116 }, /* -3 */ 115 { 1, 0x46, 116 }, /* -2 */ 116 { 1, 0x46, 116 }, /* -1 */ 117 { 1, 0x46, 116 }, /* 0 */ 118 { 1, 0x46, 116 }, /* 2412 1 */ 119 { 1, 0x46, 117 }, /* 2417 2 */ 120 { 1, 0x46, 118 }, /* 2422 3 */ 121 { 1, 0x46, 119 }, /* 2427 4 */ 122 { 1, 0x46, 120 }, /* 2432 5 */ 123 { 1, 0x46, 121 }, /* 2437 6 */ 124 { 1, 0x46, 122 }, /* 2442 7 */ 125 { 1, 0x46, 123 }, /* 2447 8 */ 126 { 1, 0x46, 124 }, /* 2452 9 */ 127 { 1, 0x46, 125 }, /* 2457 10 */ 128 { 1, 0x46, 126 }, /* 2462 11 */ 129 { 1, 0x46, 127 }, /* 2467 12 */ 130 { 1, 0x46, 128 }, /* 2472 13 */ 131 { 1, 0x44, 124 }, /* 2484 14 */ 132 { 1, 0x46, 136 }, /* 2512 15 */ 133 { 1, 0x46, 140 }, /* 2532 16 */ 134 { 1, 0x46, 144 }, /* 2552 17 */ 135 { 1, 0x46, 148 }, /* 2572 18 */ 136 { 1, 0x46, 152 }, /* 2592 19 */ 137 { 1, 0x46, 156 }, /* 2612 20 */ 138 { 1, 0x46, 160 }, /* 2632 21 */ 139 { 1, 0x46, 164 }, /* 2652 22 */ 140 { 1, 0x46, 168 }, /* 2672 23 */ 141 { 1, 0x46, 172 }, /* 2692 24 */ 142 { 1, 0x46, 176 }, /* 2712 25 */ 143 { 1, 0x46, 180 } /* 2732 26 */ 144 }; 145 146 OS_MARK(ah, AH_MARK_SETCHANNEL, freq); 147 148 chanIEEE = chan->ic_ieee; 149 if (IEEE80211_IS_CHAN_2GHZ(chan)) { 150 const CHAN_INFO_2GHZ* ci = 151 &chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION]; 152 uint32_t txctl; 153 154 data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff) 155 << 5) 156 | (ci->refClkSel << 4); 157 chan5111 = ci->channel5111; 158 txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); 159 if (freq == 2484) { 160 /* Enable channel spreading for channel 14 */ 161 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 162 txctl | AR_PHY_CCK_TX_CTRL_JAPAN); 163 } else { 164 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 165 txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); 166 } 167 } else { 168 chan5111 = chanIEEE; /* no conversion needed */ 169 data2111 = 0; 170 } 171 172 /* Rest of the code is common for 5 GHz and 2.4 GHz. */ 173 if (chan5111 >= 145 || (chan5111 & 0x1)) { 174 reg32 = ath_hal_reverseBits(chan5111 - 24, 8) & 0xff; 175 refClk = 1; 176 } else { 177 reg32 = ath_hal_reverseBits(((chan5111 - 24)/2), 8) & 0xff; 178 refClk = 0; 179 } 180 181 reg32 = (reg32 << 2) | (refClk << 1) | (1 << 10) | 0x1; 182 OS_REG_WRITE(ah, AR_PHY(0x27), ((data2111 & 0xff) << 8) | (reg32 & 0xff)); 183 reg32 >>= 8; 184 OS_REG_WRITE(ah, AR_PHY(0x34), (data2111 & 0xff00) | (reg32 & 0xff)); 185 186 AH_PRIVATE(ah)->ah_curchan = chan; 187 return AH_TRUE; 188 #undef CI_2GHZ_INDEX_CORRECTION 189 } 190 191 /* 192 * Return a reference to the requested RF Bank. 193 */ 194 static uint32_t * 195 ar5111GetRfBank(struct ath_hal *ah, int bank) 196 { 197 struct ar5111State *priv = AR5111(ah); 198 199 HALASSERT(priv != AH_NULL); 200 switch (bank) { 201 case 0: return priv->Bank0Data; 202 case 1: return priv->Bank1Data; 203 case 2: return priv->Bank2Data; 204 case 3: return priv->Bank3Data; 205 case 6: return priv->Bank6Data; 206 case 7: return priv->Bank7Data; 207 } 208 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", 209 __func__, bank); 210 return AH_NULL; 211 } 212 213 /* 214 * Reads EEPROM header info from device structure and programs 215 * all rf registers 216 * 217 * REQUIRES: Access to the analog rf device 218 */ 219 static HAL_BOOL 220 ar5111SetRfRegs(struct ath_hal *ah, const struct ieee80211_channel *chan, 221 uint16_t modesIndex, uint16_t *rfXpdGain) 222 { 223 uint16_t freq = ath_hal_gethwchannel(ah, chan); 224 struct ath_hal_5212 *ahp = AH5212(ah); 225 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 226 uint16_t rfXpdGainFixed, rfPloSel, rfPwdXpd, gainI; 227 uint16_t tempOB, tempDB; 228 uint32_t ob2GHz, db2GHz, rfReg[N(ar5212Bank6_5111)]; 229 int i, regWrites = 0; 230 231 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan %u/0x%x modesIndex %u\n", 232 __func__, chan->ic_freq, chan->ic_flags, modesIndex); 233 234 /* Setup rf parameters */ 235 switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) { 236 case IEEE80211_CHAN_A: 237 if (4000 < freq && freq < 5260) { 238 tempOB = ee->ee_ob1; 239 tempDB = ee->ee_db1; 240 } else if (5260 <= freq && freq < 5500) { 241 tempOB = ee->ee_ob2; 242 tempDB = ee->ee_db2; 243 } else if (5500 <= freq && freq < 5725) { 244 tempOB = ee->ee_ob3; 245 tempDB = ee->ee_db3; 246 } else if (freq >= 5725) { 247 tempOB = ee->ee_ob4; 248 tempDB = ee->ee_db4; 249 } else { 250 /* XXX when does this happen??? */ 251 tempOB = tempDB = 0; 252 } 253 ob2GHz = db2GHz = 0; 254 255 rfXpdGainFixed = ee->ee_xgain[headerInfo11A]; 256 rfPloSel = ee->ee_xpd[headerInfo11A]; 257 rfPwdXpd = !ee->ee_xpd[headerInfo11A]; 258 gainI = ee->ee_gainI[headerInfo11A]; 259 break; 260 case IEEE80211_CHAN_B: 261 tempOB = ee->ee_obFor24; 262 tempDB = ee->ee_dbFor24; 263 ob2GHz = ee->ee_ob2GHz[0]; 264 db2GHz = ee->ee_db2GHz[0]; 265 266 rfXpdGainFixed = ee->ee_xgain[headerInfo11B]; 267 rfPloSel = ee->ee_xpd[headerInfo11B]; 268 rfPwdXpd = !ee->ee_xpd[headerInfo11B]; 269 gainI = ee->ee_gainI[headerInfo11B]; 270 break; 271 case IEEE80211_CHAN_G: 272 case IEEE80211_CHAN_PUREG: /* NB: really 108G */ 273 tempOB = ee->ee_obFor24g; 274 tempDB = ee->ee_dbFor24g; 275 ob2GHz = ee->ee_ob2GHz[1]; 276 db2GHz = ee->ee_db2GHz[1]; 277 278 rfXpdGainFixed = ee->ee_xgain[headerInfo11G]; 279 rfPloSel = ee->ee_xpd[headerInfo11G]; 280 rfPwdXpd = !ee->ee_xpd[headerInfo11G]; 281 gainI = ee->ee_gainI[headerInfo11G]; 282 break; 283 default: 284 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", 285 __func__, chan->ic_flags); 286 return AH_FALSE; 287 } 288 289 HALASSERT(1 <= tempOB && tempOB <= 5); 290 HALASSERT(1 <= tempDB && tempDB <= 5); 291 292 /* Bank 0 Write */ 293 for (i = 0; i < N(ar5212Bank0_5111); i++) 294 rfReg[i] = ar5212Bank0_5111[i][modesIndex]; 295 if (IEEE80211_IS_CHAN_2GHZ(chan)) { 296 ar5212ModifyRfBuffer(rfReg, ob2GHz, 3, 119, 0); 297 ar5212ModifyRfBuffer(rfReg, db2GHz, 3, 122, 0); 298 } 299 HAL_INI_WRITE_BANK(ah, ar5212Bank0_5111, rfReg, regWrites); 300 301 /* Bank 1 Write */ 302 HAL_INI_WRITE_ARRAY(ah, ar5212Bank1_5111, 1, regWrites); 303 304 /* Bank 2 Write */ 305 HAL_INI_WRITE_ARRAY(ah, ar5212Bank2_5111, modesIndex, regWrites); 306 307 /* Bank 3 Write */ 308 HAL_INI_WRITE_ARRAY(ah, ar5212Bank3_5111, modesIndex, regWrites); 309 310 /* Bank 6 Write */ 311 for (i = 0; i < N(ar5212Bank6_5111); i++) 312 rfReg[i] = ar5212Bank6_5111[i][modesIndex]; 313 if (IEEE80211_IS_CHAN_A(chan)) { /* NB: CHANNEL_A | CHANNEL_T */ 314 ar5212ModifyRfBuffer(rfReg, ee->ee_cornerCal.pd84, 1, 51, 3); 315 ar5212ModifyRfBuffer(rfReg, ee->ee_cornerCal.pd90, 1, 45, 3); 316 } 317 ar5212ModifyRfBuffer(rfReg, rfPwdXpd, 1, 95, 0); 318 ar5212ModifyRfBuffer(rfReg, rfXpdGainFixed, 4, 96, 0); 319 /* Set 5212 OB & DB */ 320 ar5212ModifyRfBuffer(rfReg, tempOB, 3, 104, 0); 321 ar5212ModifyRfBuffer(rfReg, tempDB, 3, 107, 0); 322 HAL_INI_WRITE_BANK(ah, ar5212Bank6_5111, rfReg, regWrites); 323 324 /* Bank 7 Write */ 325 for (i = 0; i < N(ar5212Bank7_5111); i++) 326 rfReg[i] = ar5212Bank7_5111[i][modesIndex]; 327 ar5212ModifyRfBuffer(rfReg, gainI, 6, 29, 0); 328 ar5212ModifyRfBuffer(rfReg, rfPloSel, 1, 4, 0); 329 330 if (IEEE80211_IS_CHAN_QUARTER(chan) || IEEE80211_IS_CHAN_HALF(chan)) { 331 uint32_t rfWaitI, rfWaitS, rfMaxTime; 332 333 rfWaitS = 0x1f; 334 rfWaitI = (IEEE80211_IS_CHAN_HALF(chan)) ? 0x10 : 0x1f; 335 rfMaxTime = 3; 336 ar5212ModifyRfBuffer(rfReg, rfWaitS, 5, 19, 0); 337 ar5212ModifyRfBuffer(rfReg, rfWaitI, 5, 24, 0); 338 ar5212ModifyRfBuffer(rfReg, rfMaxTime, 2, 49, 0); 339 340 } 341 342 HAL_INI_WRITE_BANK(ah, ar5212Bank7_5111, rfReg, regWrites); 343 344 /* Now that we have reprogrammed rfgain value, clear the flag. */ 345 ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; 346 347 return AH_TRUE; 348 } 349 350 /* 351 * Returns interpolated or the scaled up interpolated value 352 */ 353 static uint16_t 354 interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, 355 uint16_t targetLeft, uint16_t targetRight) 356 { 357 uint16_t rv; 358 int16_t lRatio; 359 360 /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */ 361 if ((targetLeft * targetRight) == 0) 362 return 0; 363 364 if (srcRight != srcLeft) { 365 /* 366 * Note the ratio always need to be scaled, 367 * since it will be a fraction. 368 */ 369 lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft); 370 if (lRatio < 0) { 371 /* Return as Left target if value would be negative */ 372 rv = targetLeft; 373 } else if (lRatio > EEP_SCALE) { 374 /* Return as Right target if Ratio is greater than 100% (SCALE) */ 375 rv = targetRight; 376 } else { 377 rv = (lRatio * targetRight + (EEP_SCALE - lRatio) * 378 targetLeft) / EEP_SCALE; 379 } 380 } else { 381 rv = targetLeft; 382 } 383 return rv; 384 } 385 386 /* 387 * Read the transmit power levels from the structures taken from EEPROM 388 * Interpolate read transmit power values for this channel 389 * Organize the transmit power values into a table for writing into the hardware 390 */ 391 static HAL_BOOL 392 ar5111SetPowerTable(struct ath_hal *ah, 393 int16_t *pMinPower, int16_t *pMaxPower, 394 const struct ieee80211_channel *chan, 395 uint16_t *rfXpdGain) 396 { 397 uint16_t freq = ath_hal_gethwchannel(ah, chan); 398 struct ath_hal_5212 *ahp = AH5212(ah); 399 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 400 FULL_PCDAC_STRUCT pcdacStruct; 401 int i, j; 402 403 uint16_t *pPcdacValues; 404 int16_t *pScaledUpDbm; 405 int16_t minScaledPwr; 406 int16_t maxScaledPwr; 407 int16_t pwr; 408 uint16_t pcdacMin = 0; 409 uint16_t pcdacMax = PCDAC_STOP; 410 uint16_t pcdacTableIndex; 411 uint16_t scaledPcdac; 412 PCDACS_EEPROM *pSrcStruct; 413 PCDACS_EEPROM eepromPcdacs; 414 415 /* setup the pcdac struct to point to the correct info, based on mode */ 416 switch (chan->ic_flags & IEEE80211_CHAN_ALLTURBOFULL) { 417 case IEEE80211_CHAN_A: 418 case IEEE80211_CHAN_ST: 419 eepromPcdacs.numChannels = ee->ee_numChannels11a; 420 eepromPcdacs.pChannelList = ee->ee_channels11a; 421 eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11a; 422 break; 423 case IEEE80211_CHAN_B: 424 eepromPcdacs.numChannels = ee->ee_numChannels2_4; 425 eepromPcdacs.pChannelList = ee->ee_channels11b; 426 eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11b; 427 break; 428 case IEEE80211_CHAN_G: 429 case IEEE80211_CHAN_108G: 430 eepromPcdacs.numChannels = ee->ee_numChannels2_4; 431 eepromPcdacs.pChannelList = ee->ee_channels11g; 432 eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11g; 433 break; 434 default: 435 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", 436 __func__, chan->ic_flags); 437 return AH_FALSE; 438 } 439 440 pSrcStruct = &eepromPcdacs; 441 442 OS_MEMZERO(&pcdacStruct, sizeof(pcdacStruct)); 443 pPcdacValues = pcdacStruct.PcdacValues; 444 pScaledUpDbm = pcdacStruct.PwrValues; 445 446 /* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */ 447 for (i = PCDAC_START, j = 0; i <= PCDAC_STOP; i+= PCDAC_STEP, j++) 448 pPcdacValues[j] = i; 449 450 pcdacStruct.numPcdacValues = j; 451 pcdacStruct.pcdacMin = PCDAC_START; 452 pcdacStruct.pcdacMax = PCDAC_STOP; 453 454 /* Fill out the power values for this channel */ 455 for (j = 0; j < pcdacStruct.numPcdacValues; j++ ) 456 pScaledUpDbm[j] = ar5212GetScaledPower(freq, 457 pPcdacValues[j], pSrcStruct); 458 459 /* Now scale the pcdac values to fit in the 64 entry power table */ 460 minScaledPwr = pScaledUpDbm[0]; 461 maxScaledPwr = pScaledUpDbm[pcdacStruct.numPcdacValues - 1]; 462 463 /* find minimum and make monotonic */ 464 for (j = 0; j < pcdacStruct.numPcdacValues; j++) { 465 if (minScaledPwr >= pScaledUpDbm[j]) { 466 minScaledPwr = pScaledUpDbm[j]; 467 pcdacMin = j; 468 } 469 /* 470 * Make the full_hsh monotonically increasing otherwise 471 * interpolation algorithm will get fooled gotta start 472 * working from the top, hence i = 63 - j. 473 */ 474 i = (uint16_t)(pcdacStruct.numPcdacValues - 1 - j); 475 if (i == 0) 476 break; 477 if (pScaledUpDbm[i-1] > pScaledUpDbm[i]) { 478 /* 479 * It could be a glitch, so make the power for 480 * this pcdac the same as the power from the 481 * next highest pcdac. 482 */ 483 pScaledUpDbm[i - 1] = pScaledUpDbm[i]; 484 } 485 } 486 487 for (j = 0; j < pcdacStruct.numPcdacValues; j++) 488 if (maxScaledPwr < pScaledUpDbm[j]) { 489 maxScaledPwr = pScaledUpDbm[j]; 490 pcdacMax = j; 491 } 492 493 /* Find the first power level with a pcdac */ 494 pwr = (uint16_t)(PWR_STEP * 495 ((minScaledPwr - PWR_MIN + PWR_STEP / 2) / PWR_STEP) + PWR_MIN); 496 497 /* Write all the first pcdac entries based off the pcdacMin */ 498 pcdacTableIndex = 0; 499 for (i = 0; i < (2 * (pwr - PWR_MIN) / EEP_SCALE + 1); i++) { 500 HALASSERT(pcdacTableIndex < PWR_TABLE_SIZE); 501 ahp->ah_pcdacTable[pcdacTableIndex++] = pcdacMin; 502 } 503 504 i = 0; 505 while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && 506 pcdacTableIndex < PWR_TABLE_SIZE) { 507 pwr += PWR_STEP; 508 /* stop if dbM > max_power_possible */ 509 while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && 510 (pwr - pScaledUpDbm[i])*(pwr - pScaledUpDbm[i+1]) > 0) 511 i++; 512 /* scale by 2 and add 1 to enable round up or down as needed */ 513 scaledPcdac = (uint16_t)(interpolate(pwr, 514 pScaledUpDbm[i], pScaledUpDbm[i + 1], 515 (uint16_t)(pPcdacValues[i] * 2), 516 (uint16_t)(pPcdacValues[i + 1] * 2)) + 1); 517 518 HALASSERT(pcdacTableIndex < PWR_TABLE_SIZE); 519 ahp->ah_pcdacTable[pcdacTableIndex] = scaledPcdac / 2; 520 if (ahp->ah_pcdacTable[pcdacTableIndex] > pcdacMax) 521 ahp->ah_pcdacTable[pcdacTableIndex] = pcdacMax; 522 pcdacTableIndex++; 523 } 524 525 /* Write all the last pcdac entries based off the last valid pcdac */ 526 while (pcdacTableIndex < PWR_TABLE_SIZE) { 527 ahp->ah_pcdacTable[pcdacTableIndex] = 528 ahp->ah_pcdacTable[pcdacTableIndex - 1]; 529 pcdacTableIndex++; 530 } 531 532 /* No power table adjustment for 5111 */ 533 ahp->ah_txPowerIndexOffset = 0; 534 535 return AH_TRUE; 536 } 537 538 /* 539 * Get or interpolate the pcdac value from the calibrated data. 540 */ 541 static uint16_t 542 ar5212GetScaledPower(uint16_t channel, uint16_t pcdacValue, 543 const PCDACS_EEPROM *pSrcStruct) 544 { 545 uint16_t powerValue; 546 uint16_t lFreq, rFreq; /* left and right frequency values */ 547 uint16_t llPcdac, ulPcdac; /* lower and upper left pcdac values */ 548 uint16_t lrPcdac, urPcdac; /* lower and upper right pcdac values */ 549 uint16_t lPwr, uPwr; /* lower and upper temp pwr values */ 550 uint16_t lScaledPwr, rScaledPwr; /* left and right scaled power */ 551 552 if (ar5212FindValueInList(channel, pcdacValue, pSrcStruct, &powerValue)) { 553 /* value was copied from srcStruct */ 554 return powerValue; 555 } 556 557 ar5212GetLowerUpperValues(channel, 558 pSrcStruct->pChannelList, pSrcStruct->numChannels, 559 &lFreq, &rFreq); 560 ar5212GetLowerUpperPcdacs(pcdacValue, 561 lFreq, pSrcStruct, &llPcdac, &ulPcdac); 562 ar5212GetLowerUpperPcdacs(pcdacValue, 563 rFreq, pSrcStruct, &lrPcdac, &urPcdac); 564 565 /* get the power index for the pcdac value */ 566 ar5212FindValueInList(lFreq, llPcdac, pSrcStruct, &lPwr); 567 ar5212FindValueInList(lFreq, ulPcdac, pSrcStruct, &uPwr); 568 lScaledPwr = interpolate(pcdacValue, llPcdac, ulPcdac, lPwr, uPwr); 569 570 ar5212FindValueInList(rFreq, lrPcdac, pSrcStruct, &lPwr); 571 ar5212FindValueInList(rFreq, urPcdac, pSrcStruct, &uPwr); 572 rScaledPwr = interpolate(pcdacValue, lrPcdac, urPcdac, lPwr, uPwr); 573 574 return interpolate(channel, lFreq, rFreq, lScaledPwr, rScaledPwr); 575 } 576 577 /* 578 * Find the value from the calibrated source data struct 579 */ 580 static HAL_BOOL 581 ar5212FindValueInList(uint16_t channel, uint16_t pcdacValue, 582 const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue) 583 { 584 const DATA_PER_CHANNEL *pChannelData = pSrcStruct->pDataPerChannel; 585 int i; 586 587 for (i = 0; i < pSrcStruct->numChannels; i++ ) { 588 if (pChannelData->channelValue == channel) { 589 const uint16_t* pPcdac = pChannelData->PcdacValues; 590 int j; 591 592 for (j = 0; j < pChannelData->numPcdacValues; j++ ) { 593 if (*pPcdac == pcdacValue) { 594 *powerValue = pChannelData->PwrValues[j]; 595 return AH_TRUE; 596 } 597 pPcdac++; 598 } 599 } 600 pChannelData++; 601 } 602 return AH_FALSE; 603 } 604 605 /* 606 * Get the upper and lower pcdac given the channel and the pcdac 607 * used in the search 608 */ 609 static void 610 ar5212GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel, 611 const PCDACS_EEPROM *pSrcStruct, 612 uint16_t *pLowerPcdac, uint16_t *pUpperPcdac) 613 { 614 const DATA_PER_CHANNEL *pChannelData = pSrcStruct->pDataPerChannel; 615 int i; 616 617 /* Find the channel information */ 618 for (i = 0; i < pSrcStruct->numChannels; i++) { 619 if (pChannelData->channelValue == channel) 620 break; 621 pChannelData++; 622 } 623 ar5212GetLowerUpperValues(pcdac, pChannelData->PcdacValues, 624 pChannelData->numPcdacValues, 625 pLowerPcdac, pUpperPcdac); 626 } 627 628 static HAL_BOOL 629 ar5111GetChannelMaxMinPower(struct ath_hal *ah, 630 const struct ieee80211_channel *chan, 631 int16_t *maxPow, int16_t *minPow) 632 { 633 /* XXX - Get 5111 power limits! */ 634 /* NB: caller will cope */ 635 return AH_FALSE; 636 } 637 638 /* 639 * Adjust NF based on statistical values for 5GHz frequencies. 640 */ 641 static int16_t 642 ar5111GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 643 { 644 static const struct { 645 uint16_t freqLow; 646 int16_t adjust; 647 } adjust5111[] = { 648 { 5790, 6 }, /* NB: ordered high -> low */ 649 { 5730, 4 }, 650 { 5690, 3 }, 651 { 5660, 2 }, 652 { 5610, 1 }, 653 { 5530, 0 }, 654 { 5450, 0 }, 655 { 5379, 1 }, 656 { 5209, 3 }, 657 { 3000, 5 }, 658 { 0, 0 }, 659 }; 660 int i; 661 662 for (i = 0; c->channel <= adjust5111[i].freqLow; i++) 663 ; 664 return adjust5111[i].adjust; 665 } 666 667 /* 668 * Free memory for analog bank scratch buffers 669 */ 670 static void 671 ar5111RfDetach(struct ath_hal *ah) 672 { 673 struct ath_hal_5212 *ahp = AH5212(ah); 674 675 HALASSERT(ahp->ah_rfHal != AH_NULL); 676 ath_hal_free(ahp->ah_rfHal); 677 ahp->ah_rfHal = AH_NULL; 678 } 679 680 /* 681 * Allocate memory for analog bank scratch buffers 682 * Scratch Buffer will be reinitialized every reset so no need to zero now 683 */ 684 static HAL_BOOL 685 ar5111RfAttach(struct ath_hal *ah, HAL_STATUS *status) 686 { 687 struct ath_hal_5212 *ahp = AH5212(ah); 688 struct ar5111State *priv; 689 690 HALASSERT(ah->ah_magic == AR5212_MAGIC); 691 692 HALASSERT(ahp->ah_rfHal == AH_NULL); 693 priv = ath_hal_malloc(sizeof(struct ar5111State)); 694 if (priv == AH_NULL) { 695 HALDEBUG(ah, HAL_DEBUG_ANY, 696 "%s: cannot allocate private state\n", __func__); 697 *status = HAL_ENOMEM; /* XXX */ 698 return AH_FALSE; 699 } 700 priv->base.rfDetach = ar5111RfDetach; 701 priv->base.writeRegs = ar5111WriteRegs; 702 priv->base.getRfBank = ar5111GetRfBank; 703 priv->base.setChannel = ar5111SetChannel; 704 priv->base.setRfRegs = ar5111SetRfRegs; 705 priv->base.setPowerTable = ar5111SetPowerTable; 706 priv->base.getChannelMaxMinPower = ar5111GetChannelMaxMinPower; 707 priv->base.getNfAdjust = ar5111GetNfAdjust; 708 709 ahp->ah_pcdacTable = priv->pcdacTable; 710 ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); 711 ahp->ah_rfHal = &priv->base; 712 713 return AH_TRUE; 714 } 715 716 static HAL_BOOL 717 ar5111Probe(struct ath_hal *ah) 718 { 719 return IS_RAD5111(ah); 720 } 721 AH_RF(RF5111, ar5111Probe, ar5111RfAttach); 722