1185377Ssam/* 2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17187831Ssam * $FreeBSD$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam 24185377Ssam#include "ah_eeprom_v14.h" 25185377Ssam 26185377Ssam#include "ar5416/ar5416.h" 27185377Ssam#include "ar5416/ar5416reg.h" 28185377Ssam#include "ar5416/ar5416phy.h" 29185377Ssam 30185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 31185377Ssam 32185377Ssamstruct ar2133State { 33185377Ssam RF_HAL_FUNCS base; /* public state, must be first */ 34185377Ssam uint16_t pcdacTable[1]; 35185377Ssam 36185377Ssam uint32_t *Bank0Data; 37185377Ssam uint32_t *Bank1Data; 38185377Ssam uint32_t *Bank2Data; 39185377Ssam uint32_t *Bank3Data; 40185377Ssam uint32_t *Bank6Data; 41185377Ssam uint32_t *Bank7Data; 42185377Ssam 43185377Ssam /* NB: Bank*Data storage follows */ 44185377Ssam}; 45185377Ssam#define AR2133(ah) ((struct ar2133State *) AH5212(ah)->ah_rfHal) 46185377Ssam 47185377Ssam#define ar5416ModifyRfBuffer ar5212ModifyRfBuffer /*XXX*/ 48185377Ssam 49187831Ssamvoid ar5416ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, 50187831Ssam uint32_t numBits, uint32_t firstBit, uint32_t column); 51185377Ssam 52185377Ssamstatic void 53185377Ssamar2133WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, 54185377Ssam int writes) 55185377Ssam{ 56185377Ssam (void) ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_bb_rfgain, 57185377Ssam freqIndex, writes); 58185377Ssam} 59185377Ssam 60185377Ssam/* 61217881Sadrian * Fix on 2.4 GHz band for orientation sensitivity issue by increasing 62217881Sadrian * rf_pwd_icsyndiv. 63217881Sadrian * 64217881Sadrian * Theoretical Rules: 65217881Sadrian * if 2 GHz band 66217881Sadrian * if forceBiasAuto 67217881Sadrian * if synth_freq < 2412 68217881Sadrian * bias = 0 69217881Sadrian * else if 2412 <= synth_freq <= 2422 70217881Sadrian * bias = 1 71217881Sadrian * else // synth_freq > 2422 72217881Sadrian * bias = 2 73217881Sadrian * else if forceBias > 0 74217881Sadrian * bias = forceBias & 7 75217881Sadrian * else 76217881Sadrian * no change, use value from ini file 77217881Sadrian * else 78217881Sadrian * no change, invalid band 79217881Sadrian * 80217881Sadrian * 1st Mod: 81217881Sadrian * 2422 also uses value of 2 82217881Sadrian * <approved> 83217881Sadrian * 84217881Sadrian * 2nd Mod: 85217881Sadrian * Less than 2412 uses value of 0, 2412 and above uses value of 2 86217881Sadrian */ 87217881Sadrianstatic void 88217881Sadrianar2133ForceBias(struct ath_hal *ah, uint16_t synth_freq) 89217881Sadrian{ 90217881Sadrian uint32_t tmp_reg; 91217881Sadrian int reg_writes = 0; 92217881Sadrian uint32_t new_bias = 0; 93217881Sadrian struct ar2133State *priv = AR2133(ah); 94217881Sadrian 95217881Sadrian /* XXX this is a bit of a silly check for 2.4ghz channels -adrian */ 96217881Sadrian if (synth_freq >= 3000) 97217881Sadrian return; 98217881Sadrian 99217881Sadrian if (synth_freq < 2412) 100217881Sadrian new_bias = 0; 101217881Sadrian else if (synth_freq < 2422) 102217881Sadrian new_bias = 1; 103217881Sadrian else 104217881Sadrian new_bias = 2; 105217881Sadrian 106217881Sadrian /* pre-reverse this field */ 107217881Sadrian tmp_reg = ath_hal_reverseBits(new_bias, 3); 108217881Sadrian 109217881Sadrian HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Force rf_pwd_icsyndiv to %1d on %4d\n", 110217881Sadrian __func__, new_bias, synth_freq); 111217881Sadrian 112217881Sadrian /* swizzle rf_pwd_icsyndiv */ 113217881Sadrian ar5416ModifyRfBuffer(priv->Bank6Data, tmp_reg, 3, 181, 3); 114217881Sadrian 115217881Sadrian /* write Bank 6 with new params */ 116217881Sadrian ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank6, priv->Bank6Data, reg_writes); 117217881Sadrian} 118217881Sadrian 119217881Sadrian/* 120185377Ssam * Take the MHz channel value and set the Channel value 121185377Ssam * 122185377Ssam * ASSUMES: Writes enabled to analog bus 123185377Ssam */ 124185377Ssamstatic HAL_BOOL 125187831Ssamar2133SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) 126185377Ssam{ 127185377Ssam uint32_t channelSel = 0; 128185377Ssam uint32_t bModeSynth = 0; 129185377Ssam uint32_t aModeRefSel = 0; 130185377Ssam uint32_t reg32 = 0; 131185377Ssam uint16_t freq; 132185377Ssam CHAN_CENTERS centers; 133185377Ssam 134187831Ssam OS_MARK(ah, AH_MARK_SETCHANNEL, chan->ic_freq); 135185377Ssam 136187831Ssam ar5416GetChannelCenters(ah, chan, ¢ers); 137185377Ssam freq = centers.synth_center; 138185377Ssam 139185377Ssam if (freq < 4800) { 140185377Ssam uint32_t txctl; 141185377Ssam 142185377Ssam if (((freq - 2192) % 5) == 0) { 143185377Ssam channelSel = ((freq - 672) * 2 - 3040)/10; 144185377Ssam bModeSynth = 0; 145185377Ssam } else if (((freq - 2224) % 5) == 0) { 146185377Ssam channelSel = ((freq - 704) * 2 - 3040) / 10; 147185377Ssam bModeSynth = 1; 148185377Ssam } else { 149185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 150185377Ssam "%s: invalid channel %u MHz\n", __func__, freq); 151185377Ssam return AH_FALSE; 152185377Ssam } 153185377Ssam 154185377Ssam channelSel = (channelSel << 2) & 0xff; 155185377Ssam channelSel = ath_hal_reverseBits(channelSel, 8); 156185377Ssam 157185377Ssam txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); 158185377Ssam if (freq == 2484) { 159185377Ssam /* Enable channel spreading for channel 14 */ 160185377Ssam OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 161185377Ssam txctl | AR_PHY_CCK_TX_CTRL_JAPAN); 162185377Ssam } else { 163185377Ssam OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 164185377Ssam txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); 165185377Ssam } 166241195Sadrian /* 167241195Sadrian * Handle programming the RF synth for odd frequencies in the 168241195Sadrian * 4.9->5GHz range. This matches the programming from the 169241195Sadrian * later model 802.11abg RF synths. 170241195Sadrian * 171241195Sadrian * This interoperates on the quarter rate channels with the 172241195Sadrian * AR5112 and later RF synths. Please note that the synthesiser 173241195Sadrian * isn't able to completely accurately represent these frequencies 174241195Sadrian * (as the resolution in this reference is 2.5MHz) and thus it will 175241195Sadrian * be slightly "off centre." This matches the same slightly 176241195Sadrian * incorrect * centre frequency behaviour that the AR5112 and later 177241195Sadrian * channel selection code has. 178241195Sadrian * 179241195Sadrian * This is disabled because it hasn't been tested for regulatory 180241195Sadrian * compliance and neither have the NICs which would use it. 181241195Sadrian * So if you enable this code, you must first ensure that you've 182241195Sadrian * re-certified the NICs in question beforehand or you will be 183241195Sadrian * violating your local regulatory rules and breaking the law. 184241195Sadrian */ 185241195Sadrian#if 0 186241195Sadrian } else if (((freq % 5) == 2) && (freq <= 5435)) { 187241195Sadrian freq = freq - 2; 188241195Sadrian channelSel = ath_hal_reverseBits( 189241195Sadrian (uint32_t) (((freq - 4800) * 10) / 25 + 1), 8); 190241195Sadrian /* XXX what about for Howl/Sowl? */ 191241195Sadrian aModeRefSel = ath_hal_reverseBits(0, 2); 192241195Sadrian#endif 193185377Ssam } else if ((freq % 20) == 0 && freq >= 5120) { 194185377Ssam channelSel = ath_hal_reverseBits(((freq - 4800) / 20 << 2), 8); 195221483Sadrian if (AR_SREV_HOWL(ah) || AR_SREV_SOWL_10_OR_LATER(ah)) 196185377Ssam aModeRefSel = ath_hal_reverseBits(3, 2); 197185377Ssam else 198185377Ssam aModeRefSel = ath_hal_reverseBits(1, 2); 199185377Ssam } else if ((freq % 10) == 0) { 200185377Ssam channelSel = ath_hal_reverseBits(((freq - 4800) / 10 << 1), 8); 201221163Sadrian if (AR_SREV_HOWL(ah) || AR_SREV_SOWL_10_OR_LATER(ah)) 202185377Ssam aModeRefSel = ath_hal_reverseBits(2, 2); 203185377Ssam else 204185377Ssam aModeRefSel = ath_hal_reverseBits(1, 2); 205185377Ssam } else if ((freq % 5) == 0) { 206185377Ssam channelSel = ath_hal_reverseBits((freq - 4800) / 5, 8); 207185377Ssam aModeRefSel = ath_hal_reverseBits(1, 2); 208185377Ssam } else { 209241195Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 210241195Sadrian "%s: invalid channel %u MHz\n", 211185377Ssam __func__, freq); 212185377Ssam return AH_FALSE; 213185377Ssam } 214185377Ssam 215217881Sadrian /* Workaround for hw bug - AR5416 specific */ 216223459Sadrian if (AR_SREV_OWL(ah) && ah->ah_config.ah_ar5416_biasadj) 217217881Sadrian ar2133ForceBias(ah, freq); 218217881Sadrian 219185377Ssam reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | 220185377Ssam (1 << 5) | 0x1; 221185377Ssam 222185377Ssam OS_REG_WRITE(ah, AR_PHY(0x37), reg32); 223185377Ssam 224185377Ssam AH_PRIVATE(ah)->ah_curchan = chan; 225185377Ssam return AH_TRUE; 226185377Ssam 227185377Ssam} 228185377Ssam 229185377Ssam/* 230185377Ssam * Return a reference to the requested RF Bank. 231185377Ssam */ 232185377Ssamstatic uint32_t * 233185377Ssamar2133GetRfBank(struct ath_hal *ah, int bank) 234185377Ssam{ 235185377Ssam struct ar2133State *priv = AR2133(ah); 236185377Ssam 237185377Ssam HALASSERT(priv != AH_NULL); 238185377Ssam switch (bank) { 239185377Ssam case 1: return priv->Bank1Data; 240185377Ssam case 2: return priv->Bank2Data; 241185377Ssam case 3: return priv->Bank3Data; 242185377Ssam case 6: return priv->Bank6Data; 243185377Ssam case 7: return priv->Bank7Data; 244185377Ssam } 245185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", 246185377Ssam __func__, bank); 247185377Ssam return AH_NULL; 248185377Ssam} 249185377Ssam 250185377Ssam/* 251185377Ssam * Reads EEPROM header info from device structure and programs 252185377Ssam * all rf registers 253185377Ssam * 254185377Ssam * REQUIRES: Access to the analog rf device 255185377Ssam */ 256185377Ssamstatic HAL_BOOL 257187831Ssamar2133SetRfRegs(struct ath_hal *ah, const struct ieee80211_channel *chan, 258185377Ssam uint16_t modesIndex, uint16_t *rfXpdGain) 259185377Ssam{ 260185377Ssam struct ar2133State *priv = AR2133(ah); 261185377Ssam int writes; 262185377Ssam 263185377Ssam HALASSERT(priv); 264185377Ssam 265185377Ssam /* Setup Bank 0 Write */ 266185377Ssam ath_hal_ini_bank_setup(priv->Bank0Data, &AH5416(ah)->ah_ini_bank0, 1); 267185377Ssam 268185377Ssam /* Setup Bank 1 Write */ 269185377Ssam ath_hal_ini_bank_setup(priv->Bank1Data, &AH5416(ah)->ah_ini_bank1, 1); 270185377Ssam 271185377Ssam /* Setup Bank 2 Write */ 272185377Ssam ath_hal_ini_bank_setup(priv->Bank2Data, &AH5416(ah)->ah_ini_bank2, 1); 273185377Ssam 274185377Ssam /* Setup Bank 3 Write */ 275185377Ssam ath_hal_ini_bank_setup(priv->Bank3Data, &AH5416(ah)->ah_ini_bank3, modesIndex); 276185377Ssam 277185377Ssam /* Setup Bank 6 Write */ 278185377Ssam ath_hal_ini_bank_setup(priv->Bank6Data, &AH5416(ah)->ah_ini_bank6, modesIndex); 279185377Ssam 280185377Ssam /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ 281187831Ssam if (IEEE80211_IS_CHAN_2GHZ(chan)) { 282220258Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: 2ghz: OB_2:%d, DB_2:%d\n", 283220258Sadrian __func__, 284220258Sadrian ath_hal_eepromGet(ah, AR_EEP_OB_2, AH_NULL), 285220258Sadrian ath_hal_eepromGet(ah, AR_EEP_DB_2, AH_NULL)); 286185377Ssam ar5416ModifyRfBuffer(priv->Bank6Data, 287185377Ssam ath_hal_eepromGet(ah, AR_EEP_OB_2, AH_NULL), 3, 197, 0); 288185377Ssam ar5416ModifyRfBuffer(priv->Bank6Data, 289185377Ssam ath_hal_eepromGet(ah, AR_EEP_DB_2, AH_NULL), 3, 194, 0); 290185377Ssam } else { 291220258Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: 5ghz: OB_5:%d, DB_5:%d\n", 292220258Sadrian __func__, 293220258Sadrian ath_hal_eepromGet(ah, AR_EEP_OB_5, AH_NULL), 294220258Sadrian ath_hal_eepromGet(ah, AR_EEP_DB_5, AH_NULL)); 295185377Ssam ar5416ModifyRfBuffer(priv->Bank6Data, 296185377Ssam ath_hal_eepromGet(ah, AR_EEP_OB_5, AH_NULL), 3, 203, 0); 297185377Ssam ar5416ModifyRfBuffer(priv->Bank6Data, 298185377Ssam ath_hal_eepromGet(ah, AR_EEP_DB_5, AH_NULL), 3, 200, 0); 299185377Ssam } 300185377Ssam /* Setup Bank 7 Setup */ 301185377Ssam ath_hal_ini_bank_setup(priv->Bank7Data, &AH5416(ah)->ah_ini_bank7, 1); 302185377Ssam 303185377Ssam /* Write Analog registers */ 304185377Ssam writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank0, 305185377Ssam priv->Bank0Data, 0); 306185377Ssam writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank1, 307185377Ssam priv->Bank1Data, writes); 308185377Ssam writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank2, 309185377Ssam priv->Bank2Data, writes); 310185377Ssam writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank3, 311185377Ssam priv->Bank3Data, writes); 312185377Ssam writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank6, 313185377Ssam priv->Bank6Data, writes); 314185377Ssam (void) ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank7, 315185377Ssam priv->Bank7Data, writes); 316185377Ssam 317185377Ssam return AH_TRUE; 318185377Ssam#undef RF_BANK_SETUP 319185377Ssam} 320185377Ssam 321185377Ssam/* 322185377Ssam * Read the transmit power levels from the structures taken from EEPROM 323185377Ssam * Interpolate read transmit power values for this channel 324185377Ssam * Organize the transmit power values into a table for writing into the hardware 325185377Ssam */ 326185377Ssam 327185377Ssamstatic HAL_BOOL 328185377Ssamar2133SetPowerTable(struct ath_hal *ah, int16_t *pPowerMin, int16_t *pPowerMax, 329187831Ssam const struct ieee80211_channel *chan, uint16_t *rfXpdGain) 330185377Ssam{ 331185377Ssam return AH_TRUE; 332185377Ssam} 333185377Ssam 334185377Ssam#if 0 335185377Ssamstatic int16_t 336185377Ssamar2133GetMinPower(struct ath_hal *ah, EXPN_DATA_PER_CHANNEL_5112 *data) 337185377Ssam{ 338185377Ssam int i, minIndex; 339185377Ssam int16_t minGain,minPwr,minPcdac,retVal; 340185377Ssam 341185377Ssam /* Assume NUM_POINTS_XPD0 > 0 */ 342185377Ssam minGain = data->pDataPerXPD[0].xpd_gain; 343185377Ssam for (minIndex=0,i=1; i<NUM_XPD_PER_CHANNEL; i++) { 344185377Ssam if (data->pDataPerXPD[i].xpd_gain < minGain) { 345185377Ssam minIndex = i; 346185377Ssam minGain = data->pDataPerXPD[i].xpd_gain; 347185377Ssam } 348185377Ssam } 349185377Ssam minPwr = data->pDataPerXPD[minIndex].pwr_t4[0]; 350185377Ssam minPcdac = data->pDataPerXPD[minIndex].pcdac[0]; 351185377Ssam for (i=1; i<NUM_POINTS_XPD0; i++) { 352185377Ssam if (data->pDataPerXPD[minIndex].pwr_t4[i] < minPwr) { 353185377Ssam minPwr = data->pDataPerXPD[minIndex].pwr_t4[i]; 354185377Ssam minPcdac = data->pDataPerXPD[minIndex].pcdac[i]; 355185377Ssam } 356185377Ssam } 357185377Ssam retVal = minPwr - (minPcdac*2); 358185377Ssam return(retVal); 359185377Ssam} 360185377Ssam#endif 361185377Ssam 362185377Ssamstatic HAL_BOOL 363187831Ssamar2133GetChannelMaxMinPower(struct ath_hal *ah, 364187831Ssam const struct ieee80211_channel *chan, 365187831Ssam int16_t *maxPow, int16_t *minPow) 366185377Ssam{ 367185377Ssam#if 0 368185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 369185377Ssam int numChannels=0,i,last; 370185377Ssam int totalD, totalF,totalMin; 371185377Ssam EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL; 372185377Ssam EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL; 373185377Ssam 374185377Ssam *maxPow = 0; 375185377Ssam if (IS_CHAN_A(chan)) { 376185377Ssam powerArray = ahp->ah_modePowerArray5112; 377185377Ssam data = powerArray[headerInfo11A].pDataPerChannel; 378185377Ssam numChannels = powerArray[headerInfo11A].numChannels; 379185377Ssam } else if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) { 380185377Ssam /* XXX - is this correct? Should we also use the same power for turbo G? */ 381185377Ssam powerArray = ahp->ah_modePowerArray5112; 382185377Ssam data = powerArray[headerInfo11G].pDataPerChannel; 383185377Ssam numChannels = powerArray[headerInfo11G].numChannels; 384185377Ssam } else if (IS_CHAN_B(chan)) { 385185377Ssam powerArray = ahp->ah_modePowerArray5112; 386185377Ssam data = powerArray[headerInfo11B].pDataPerChannel; 387185377Ssam numChannels = powerArray[headerInfo11B].numChannels; 388185377Ssam } else { 389185377Ssam return (AH_TRUE); 390185377Ssam } 391185377Ssam /* Make sure the channel is in the range of the TP values 392185377Ssam * (freq piers) 393185377Ssam */ 394185377Ssam if ((numChannels < 1) || 395185377Ssam (chan->channel < data[0].channelValue) || 396185377Ssam (chan->channel > data[numChannels-1].channelValue)) 397185377Ssam return(AH_FALSE); 398185377Ssam 399185377Ssam /* Linearly interpolate the power value now */ 400185377Ssam for (last=0,i=0; 401185377Ssam (i<numChannels) && (chan->channel > data[i].channelValue); 402185377Ssam last=i++); 403185377Ssam totalD = data[i].channelValue - data[last].channelValue; 404185377Ssam if (totalD > 0) { 405185377Ssam totalF = data[i].maxPower_t4 - data[last].maxPower_t4; 406185377Ssam *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + data[last].maxPower_t4*totalD)/totalD); 407185377Ssam 408185377Ssam totalMin = ar2133GetMinPower(ah,&data[i]) - ar2133GetMinPower(ah, &data[last]); 409185377Ssam *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + ar2133GetMinPower(ah, &data[last])*totalD)/totalD); 410185377Ssam return (AH_TRUE); 411185377Ssam } else { 412185377Ssam if (chan->channel == data[i].channelValue) { 413185377Ssam *maxPow = data[i].maxPower_t4; 414185377Ssam *minPow = ar2133GetMinPower(ah, &data[i]); 415185377Ssam return(AH_TRUE); 416185377Ssam } else 417185377Ssam return(AH_FALSE); 418185377Ssam } 419185377Ssam#else 420185377Ssam *maxPow = *minPow = 0; 421185377Ssam return AH_FALSE; 422185377Ssam#endif 423185377Ssam} 424185377Ssam 425219605Sadrian/* 426219605Sadrian * The ordering of nfarray is thus: 427219605Sadrian * 428219605Sadrian * nfarray[0]: Chain 0 ctl 429219605Sadrian * nfarray[1]: Chain 1 ctl 430219605Sadrian * nfarray[2]: Chain 2 ctl 431219605Sadrian * nfarray[3]: Chain 0 ext 432219605Sadrian * nfarray[4]: Chain 1 ext 433219605Sadrian * nfarray[5]: Chain 2 ext 434219605Sadrian */ 435185380Ssamstatic void 436185380Ssamar2133GetNoiseFloor(struct ath_hal *ah, int16_t nfarray[]) 437185380Ssam{ 438185380Ssam struct ath_hal_5416 *ahp = AH5416(ah); 439185380Ssam int16_t nf; 440185380Ssam 441219605Sadrian /* 442219605Sadrian * Blank nf array - some chips may only 443219605Sadrian * have one or two RX chainmasks enabled. 444219605Sadrian */ 445219605Sadrian nfarray[0] = nfarray[1] = nfarray[2] = 0; 446219605Sadrian nfarray[3] = nfarray[4] = nfarray[5] = 0; 447219605Sadrian 448185380Ssam switch (ahp->ah_rx_chainmask) { 449185380Ssam case 0x7: 450185380Ssam nf = MS(OS_REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR); 451185380Ssam if (nf & 0x100) 452185380Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 453185380Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 454185380Ssam "NF calibrated [ctl] [chain 2] is %d\n", nf); 455219605Sadrian nfarray[2] = nf; 456185380Ssam 457185380Ssam nf = MS(OS_REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR); 458185380Ssam if (nf & 0x100) 459185380Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 460185380Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 461185380Ssam "NF calibrated [ext] [chain 2] is %d\n", nf); 462185380Ssam nfarray[5] = nf; 463185380Ssam /* fall thru... */ 464185380Ssam case 0x3: 465185380Ssam case 0x5: 466185380Ssam nf = MS(OS_REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR); 467185380Ssam if (nf & 0x100) 468185380Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 469185380Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 470185380Ssam "NF calibrated [ctl] [chain 1] is %d\n", nf); 471219605Sadrian nfarray[1] = nf; 472185380Ssam 473185380Ssam 474185380Ssam nf = MS(OS_REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR); 475185380Ssam if (nf & 0x100) 476185380Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 477185380Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 478185380Ssam "NF calibrated [ext] [chain 1] is %d\n", nf); 479219605Sadrian nfarray[4] = nf; 480185380Ssam /* fall thru... */ 481185380Ssam case 0x1: 482185380Ssam nf = MS(OS_REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); 483185380Ssam if (nf & 0x100) 484185380Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 485185380Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 486185380Ssam "NF calibrated [ctl] [chain 0] is %d\n", nf); 487185380Ssam nfarray[0] = nf; 488185380Ssam 489185380Ssam nf = MS(OS_REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR); 490185380Ssam if (nf & 0x100) 491185380Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 492185380Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 493185380Ssam "NF calibrated [ext] [chain 0] is %d\n", nf); 494219605Sadrian nfarray[3] = nf; 495185380Ssam 496185380Ssam break; 497185380Ssam } 498185380Ssam} 499185380Ssam 500185377Ssam/* 501185377Ssam * Adjust NF based on statistical values for 5GHz frequencies. 502185377Ssam * Stubbed:Not used by Fowl 503185377Ssam */ 504187831Ssamstatic int16_t 505185377Ssamar2133GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 506185377Ssam{ 507185377Ssam return 0; 508185377Ssam} 509185377Ssam 510185377Ssam/* 511185377Ssam * Free memory for analog bank scratch buffers 512185377Ssam */ 513185377Ssamstatic void 514185377Ssamar2133RfDetach(struct ath_hal *ah) 515185377Ssam{ 516185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 517185377Ssam 518185377Ssam HALASSERT(ahp->ah_rfHal != AH_NULL); 519185377Ssam ath_hal_free(ahp->ah_rfHal); 520185377Ssam ahp->ah_rfHal = AH_NULL; 521185377Ssam} 522185377Ssam 523185377Ssam/* 524185377Ssam * Allocate memory for analog bank scratch buffers 525185377Ssam * Scratch Buffer will be reinitialized every reset so no need to zero now 526185377Ssam */ 527185377SsamHAL_BOOL 528185377Ssamar2133RfAttach(struct ath_hal *ah, HAL_STATUS *status) 529185377Ssam{ 530185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 531185377Ssam struct ar2133State *priv; 532185377Ssam uint32_t *bankData; 533185377Ssam 534188980Ssam HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: attach AR2133 radio\n", __func__); 535188980Ssam 536185377Ssam HALASSERT(ahp->ah_rfHal == AH_NULL); 537185377Ssam priv = ath_hal_malloc(sizeof(struct ar2133State) 538185377Ssam + AH5416(ah)->ah_ini_bank0.rows * sizeof(uint32_t) 539185377Ssam + AH5416(ah)->ah_ini_bank1.rows * sizeof(uint32_t) 540185377Ssam + AH5416(ah)->ah_ini_bank2.rows * sizeof(uint32_t) 541185377Ssam + AH5416(ah)->ah_ini_bank3.rows * sizeof(uint32_t) 542185377Ssam + AH5416(ah)->ah_ini_bank6.rows * sizeof(uint32_t) 543185377Ssam + AH5416(ah)->ah_ini_bank7.rows * sizeof(uint32_t) 544185377Ssam ); 545185377Ssam if (priv == AH_NULL) { 546185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 547185377Ssam "%s: cannot allocate private state\n", __func__); 548185377Ssam *status = HAL_ENOMEM; /* XXX */ 549185377Ssam return AH_FALSE; 550185377Ssam } 551185377Ssam priv->base.rfDetach = ar2133RfDetach; 552185377Ssam priv->base.writeRegs = ar2133WriteRegs; 553185377Ssam priv->base.getRfBank = ar2133GetRfBank; 554185377Ssam priv->base.setChannel = ar2133SetChannel; 555185377Ssam priv->base.setRfRegs = ar2133SetRfRegs; 556185377Ssam priv->base.setPowerTable = ar2133SetPowerTable; 557185377Ssam priv->base.getChannelMaxMinPower = ar2133GetChannelMaxMinPower; 558185377Ssam priv->base.getNfAdjust = ar2133GetNfAdjust; 559185377Ssam 560185377Ssam bankData = (uint32_t *) &priv[1]; 561185377Ssam priv->Bank0Data = bankData, bankData += AH5416(ah)->ah_ini_bank0.rows; 562185377Ssam priv->Bank1Data = bankData, bankData += AH5416(ah)->ah_ini_bank1.rows; 563185377Ssam priv->Bank2Data = bankData, bankData += AH5416(ah)->ah_ini_bank2.rows; 564185377Ssam priv->Bank3Data = bankData, bankData += AH5416(ah)->ah_ini_bank3.rows; 565185377Ssam priv->Bank6Data = bankData, bankData += AH5416(ah)->ah_ini_bank6.rows; 566185377Ssam priv->Bank7Data = bankData, bankData += AH5416(ah)->ah_ini_bank7.rows; 567185377Ssam 568185377Ssam ahp->ah_pcdacTable = priv->pcdacTable; 569185377Ssam ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); 570185377Ssam ahp->ah_rfHal = &priv->base; 571185377Ssam /* 572185377Ssam * Set noise floor adjust method; we arrange a 573185377Ssam * direct call instead of thunking. 574185377Ssam */ 575185377Ssam AH_PRIVATE(ah)->ah_getNfAdjust = priv->base.getNfAdjust; 576185380Ssam AH_PRIVATE(ah)->ah_getNoiseFloor = ar2133GetNoiseFloor; 577185377Ssam 578185377Ssam return AH_TRUE; 579185377Ssam} 580228517Sadrian 581228517Sadrianstatic HAL_BOOL 582228517Sadrianar2133Probe(struct ath_hal *ah) 583228517Sadrian{ 584228517Sadrian return (AR_SREV_OWL(ah) || AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)); 585228517Sadrian} 586228517Sadrian 587228517SadrianAH_RF(RF2133, ar2133Probe, ar2133RfAttach); 588