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 HAL_INI_WRITE_BANK(ah, ar5212Bank7_5111, rfReg, regWrites); 342 343 /* Now that we have reprogrammed rfgain value, clear the flag. */ 344 ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; 345 346 return AH_TRUE; 347 } 348 349 /* 350 * Returns interpolated or the scaled up interpolated value 351 */ 352 static uint16_t 353 interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, 354 uint16_t targetLeft, uint16_t targetRight) 355 { 356 uint16_t rv; 357 int16_t lRatio; 358 359 /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */ 360 if ((targetLeft * targetRight) == 0) 361 return 0; 362 363 if (srcRight != srcLeft) { 364 /* 365 * Note the ratio always need to be scaled, 366 * since it will be a fraction. 367 */ 368 lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft); 369 if (lRatio < 0) { 370 /* Return as Left target if value would be negative */ 371 rv = targetLeft; 372 } else if (lRatio > EEP_SCALE) { 373 /* Return as Right target if Ratio is greater than 100% (SCALE) */ 374 rv = targetRight; 375 } else { 376 rv = (lRatio * targetRight + (EEP_SCALE - lRatio) * 377 targetLeft) / EEP_SCALE; 378 } 379 } else { 380 rv = targetLeft; 381 } 382 return rv; 383 } 384 385 /* 386 * Read the transmit power levels from the structures taken from EEPROM 387 * Interpolate read transmit power values for this channel 388 * Organize the transmit power values into a table for writing into the hardware 389 */ 390 static HAL_BOOL 391 ar5111SetPowerTable(struct ath_hal *ah, 392 int16_t *pMinPower, int16_t *pMaxPower, 393 const struct ieee80211_channel *chan, 394 uint16_t *rfXpdGain) 395 { 396 uint16_t freq = ath_hal_gethwchannel(ah, chan); 397 struct ath_hal_5212 *ahp = AH5212(ah); 398 const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; 399 FULL_PCDAC_STRUCT pcdacStruct; 400 int i, j; 401 402 uint16_t *pPcdacValues; 403 int16_t *pScaledUpDbm; 404 int16_t minScaledPwr; 405 int16_t maxScaledPwr; 406 int16_t pwr; 407 uint16_t pcdacMin = 0; 408 uint16_t pcdacMax = PCDAC_STOP; 409 uint16_t pcdacTableIndex; 410 uint16_t scaledPcdac; 411 PCDACS_EEPROM *pSrcStruct; 412 PCDACS_EEPROM eepromPcdacs; 413 414 /* setup the pcdac struct to point to the correct info, based on mode */ 415 switch (chan->ic_flags & IEEE80211_CHAN_ALLTURBOFULL) { 416 case IEEE80211_CHAN_A: 417 case IEEE80211_CHAN_ST: 418 eepromPcdacs.numChannels = ee->ee_numChannels11a; 419 eepromPcdacs.pChannelList = ee->ee_channels11a; 420 eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11a; 421 break; 422 case IEEE80211_CHAN_B: 423 eepromPcdacs.numChannels = ee->ee_numChannels2_4; 424 eepromPcdacs.pChannelList = ee->ee_channels11b; 425 eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11b; 426 break; 427 case IEEE80211_CHAN_G: 428 case IEEE80211_CHAN_108G: 429 eepromPcdacs.numChannels = ee->ee_numChannels2_4; 430 eepromPcdacs.pChannelList = ee->ee_channels11g; 431 eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11g; 432 break; 433 default: 434 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", 435 __func__, chan->ic_flags); 436 return AH_FALSE; 437 } 438 439 pSrcStruct = &eepromPcdacs; 440 441 OS_MEMZERO(&pcdacStruct, sizeof(pcdacStruct)); 442 pPcdacValues = pcdacStruct.PcdacValues; 443 pScaledUpDbm = pcdacStruct.PwrValues; 444 445 /* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */ 446 for (i = PCDAC_START, j = 0; i <= PCDAC_STOP; i+= PCDAC_STEP, j++) 447 pPcdacValues[j] = i; 448 449 pcdacStruct.numPcdacValues = j; 450 pcdacStruct.pcdacMin = PCDAC_START; 451 pcdacStruct.pcdacMax = PCDAC_STOP; 452 453 /* Fill out the power values for this channel */ 454 for (j = 0; j < pcdacStruct.numPcdacValues; j++ ) 455 pScaledUpDbm[j] = ar5212GetScaledPower(freq, 456 pPcdacValues[j], pSrcStruct); 457 458 /* Now scale the pcdac values to fit in the 64 entry power table */ 459 minScaledPwr = pScaledUpDbm[0]; 460 maxScaledPwr = pScaledUpDbm[pcdacStruct.numPcdacValues - 1]; 461 462 /* find minimum and make monotonic */ 463 for (j = 0; j < pcdacStruct.numPcdacValues; j++) { 464 if (minScaledPwr >= pScaledUpDbm[j]) { 465 minScaledPwr = pScaledUpDbm[j]; 466 pcdacMin = j; 467 } 468 /* 469 * Make the full_hsh monotonically increasing otherwise 470 * interpolation algorithm will get fooled gotta start 471 * working from the top, hence i = 63 - j. 472 */ 473 i = (uint16_t)(pcdacStruct.numPcdacValues - 1 - j); 474 if (i == 0) 475 break; 476 if (pScaledUpDbm[i-1] > pScaledUpDbm[i]) { 477 /* 478 * It could be a glitch, so make the power for 479 * this pcdac the same as the power from the 480 * next highest pcdac. 481 */ 482 pScaledUpDbm[i - 1] = pScaledUpDbm[i]; 483 } 484 } 485 486 for (j = 0; j < pcdacStruct.numPcdacValues; j++) 487 if (maxScaledPwr < pScaledUpDbm[j]) { 488 maxScaledPwr = pScaledUpDbm[j]; 489 pcdacMax = j; 490 } 491 492 /* Find the first power level with a pcdac */ 493 pwr = (uint16_t)(PWR_STEP * 494 ((minScaledPwr - PWR_MIN + PWR_STEP / 2) / PWR_STEP) + PWR_MIN); 495 496 /* Write all the first pcdac entries based off the pcdacMin */ 497 pcdacTableIndex = 0; 498 for (i = 0; i < (2 * (pwr - PWR_MIN) / EEP_SCALE + 1); i++) { 499 HALASSERT(pcdacTableIndex < PWR_TABLE_SIZE); 500 ahp->ah_pcdacTable[pcdacTableIndex++] = pcdacMin; 501 } 502 503 i = 0; 504 while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && 505 pcdacTableIndex < PWR_TABLE_SIZE) { 506 pwr += PWR_STEP; 507 /* stop if dbM > max_power_possible */ 508 while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && 509 (pwr - pScaledUpDbm[i])*(pwr - pScaledUpDbm[i+1]) > 0) 510 i++; 511 /* scale by 2 and add 1 to enable round up or down as needed */ 512 scaledPcdac = (uint16_t)(interpolate(pwr, 513 pScaledUpDbm[i], pScaledUpDbm[i + 1], 514 (uint16_t)(pPcdacValues[i] * 2), 515 (uint16_t)(pPcdacValues[i + 1] * 2)) + 1); 516 517 HALASSERT(pcdacTableIndex < PWR_TABLE_SIZE); 518 ahp->ah_pcdacTable[pcdacTableIndex] = scaledPcdac / 2; 519 if (ahp->ah_pcdacTable[pcdacTableIndex] > pcdacMax) 520 ahp->ah_pcdacTable[pcdacTableIndex] = pcdacMax; 521 pcdacTableIndex++; 522 } 523 524 /* Write all the last pcdac entries based off the last valid pcdac */ 525 while (pcdacTableIndex < PWR_TABLE_SIZE) { 526 ahp->ah_pcdacTable[pcdacTableIndex] = 527 ahp->ah_pcdacTable[pcdacTableIndex - 1]; 528 pcdacTableIndex++; 529 } 530 531 /* No power table adjustment for 5111 */ 532 ahp->ah_txPowerIndexOffset = 0; 533 534 return AH_TRUE; 535 } 536 537 /* 538 * Get or interpolate the pcdac value from the calibrated data. 539 */ 540 static uint16_t 541 ar5212GetScaledPower(uint16_t channel, uint16_t pcdacValue, 542 const PCDACS_EEPROM *pSrcStruct) 543 { 544 uint16_t powerValue; 545 uint16_t lFreq, rFreq; /* left and right frequency values */ 546 uint16_t llPcdac, ulPcdac; /* lower and upper left pcdac values */ 547 uint16_t lrPcdac, urPcdac; /* lower and upper right pcdac values */ 548 uint16_t lPwr, uPwr; /* lower and upper temp pwr values */ 549 uint16_t lScaledPwr, rScaledPwr; /* left and right scaled power */ 550 551 if (ar5212FindValueInList(channel, pcdacValue, pSrcStruct, &powerValue)) { 552 /* value was copied from srcStruct */ 553 return powerValue; 554 } 555 556 ar5212GetLowerUpperValues(channel, 557 pSrcStruct->pChannelList, pSrcStruct->numChannels, 558 &lFreq, &rFreq); 559 ar5212GetLowerUpperPcdacs(pcdacValue, 560 lFreq, pSrcStruct, &llPcdac, &ulPcdac); 561 ar5212GetLowerUpperPcdacs(pcdacValue, 562 rFreq, pSrcStruct, &lrPcdac, &urPcdac); 563 564 /* get the power index for the pcdac value */ 565 ar5212FindValueInList(lFreq, llPcdac, pSrcStruct, &lPwr); 566 ar5212FindValueInList(lFreq, ulPcdac, pSrcStruct, &uPwr); 567 lScaledPwr = interpolate(pcdacValue, llPcdac, ulPcdac, lPwr, uPwr); 568 569 ar5212FindValueInList(rFreq, lrPcdac, pSrcStruct, &lPwr); 570 ar5212FindValueInList(rFreq, urPcdac, pSrcStruct, &uPwr); 571 rScaledPwr = interpolate(pcdacValue, lrPcdac, urPcdac, lPwr, uPwr); 572 573 return interpolate(channel, lFreq, rFreq, lScaledPwr, rScaledPwr); 574 } 575 576 /* 577 * Find the value from the calibrated source data struct 578 */ 579 static HAL_BOOL 580 ar5212FindValueInList(uint16_t channel, uint16_t pcdacValue, 581 const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue) 582 { 583 const DATA_PER_CHANNEL *pChannelData = pSrcStruct->pDataPerChannel; 584 int i; 585 586 for (i = 0; i < pSrcStruct->numChannels; i++ ) { 587 if (pChannelData->channelValue == channel) { 588 const uint16_t* pPcdac = pChannelData->PcdacValues; 589 int j; 590 591 for (j = 0; j < pChannelData->numPcdacValues; j++ ) { 592 if (*pPcdac == pcdacValue) { 593 *powerValue = pChannelData->PwrValues[j]; 594 return AH_TRUE; 595 } 596 pPcdac++; 597 } 598 } 599 pChannelData++; 600 } 601 return AH_FALSE; 602 } 603 604 /* 605 * Get the upper and lower pcdac given the channel and the pcdac 606 * used in the search 607 */ 608 static void 609 ar5212GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel, 610 const PCDACS_EEPROM *pSrcStruct, 611 uint16_t *pLowerPcdac, uint16_t *pUpperPcdac) 612 { 613 const DATA_PER_CHANNEL *pChannelData = pSrcStruct->pDataPerChannel; 614 int i; 615 616 /* Find the channel information */ 617 for (i = 0; i < pSrcStruct->numChannels; i++) { 618 if (pChannelData->channelValue == channel) 619 break; 620 pChannelData++; 621 } 622 ar5212GetLowerUpperValues(pcdac, pChannelData->PcdacValues, 623 pChannelData->numPcdacValues, 624 pLowerPcdac, pUpperPcdac); 625 } 626 627 static HAL_BOOL 628 ar5111GetChannelMaxMinPower(struct ath_hal *ah, 629 const struct ieee80211_channel *chan, 630 int16_t *maxPow, int16_t *minPow) 631 { 632 /* XXX - Get 5111 power limits! */ 633 /* NB: caller will cope */ 634 return AH_FALSE; 635 } 636 637 /* 638 * Adjust NF based on statistical values for 5GHz frequencies. 639 */ 640 static int16_t 641 ar5111GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 642 { 643 static const struct { 644 uint16_t freqLow; 645 int16_t adjust; 646 } adjust5111[] = { 647 { 5790, 6 }, /* NB: ordered high -> low */ 648 { 5730, 4 }, 649 { 5690, 3 }, 650 { 5660, 2 }, 651 { 5610, 1 }, 652 { 5530, 0 }, 653 { 5450, 0 }, 654 { 5379, 1 }, 655 { 5209, 3 }, 656 { 3000, 5 }, 657 { 0, 0 }, 658 }; 659 int i; 660 661 for (i = 0; c->channel <= adjust5111[i].freqLow; i++) 662 ; 663 return adjust5111[i].adjust; 664 } 665 666 /* 667 * Free memory for analog bank scratch buffers 668 */ 669 static void 670 ar5111RfDetach(struct ath_hal *ah) 671 { 672 struct ath_hal_5212 *ahp = AH5212(ah); 673 674 HALASSERT(ahp->ah_rfHal != AH_NULL); 675 ath_hal_free(ahp->ah_rfHal); 676 ahp->ah_rfHal = AH_NULL; 677 } 678 679 /* 680 * Allocate memory for analog bank scratch buffers 681 * Scratch Buffer will be reinitialized every reset so no need to zero now 682 */ 683 static HAL_BOOL 684 ar5111RfAttach(struct ath_hal *ah, HAL_STATUS *status) 685 { 686 struct ath_hal_5212 *ahp = AH5212(ah); 687 struct ar5111State *priv; 688 689 HALASSERT(ah->ah_magic == AR5212_MAGIC); 690 691 HALASSERT(ahp->ah_rfHal == AH_NULL); 692 priv = ath_hal_malloc(sizeof(struct ar5111State)); 693 if (priv == AH_NULL) { 694 HALDEBUG(ah, HAL_DEBUG_ANY, 695 "%s: cannot allocate private state\n", __func__); 696 *status = HAL_ENOMEM; /* XXX */ 697 return AH_FALSE; 698 } 699 priv->base.rfDetach = ar5111RfDetach; 700 priv->base.writeRegs = ar5111WriteRegs; 701 priv->base.getRfBank = ar5111GetRfBank; 702 priv->base.setChannel = ar5111SetChannel; 703 priv->base.setRfRegs = ar5111SetRfRegs; 704 priv->base.setPowerTable = ar5111SetPowerTable; 705 priv->base.getChannelMaxMinPower = ar5111GetChannelMaxMinPower; 706 priv->base.getNfAdjust = ar5111GetNfAdjust; 707 708 ahp->ah_pcdacTable = priv->pcdacTable; 709 ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); 710 ahp->ah_rfHal = &priv->base; 711 712 return AH_TRUE; 713 } 714 715 static HAL_BOOL 716 ar5111Probe(struct ath_hal *ah) 717 { 718 return IS_RAD5111(ah); 719 } 720 AH_RF(RF5111, ar5111Probe, ar5111RfAttach); 721