1 /* 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $FreeBSD$ 18 */ 19 #include "opt_ah.h" 20 21 #include "ah.h" 22 #include "ah_internal.h" 23 24 #include "ah_eeprom_v14.h" 25 26 #include "ar5416/ar5416.h" 27 #include "ar5416/ar5416reg.h" 28 #include "ar5416/ar5416phy.h" 29 30 #define N(a) (sizeof(a)/sizeof(a[0])) 31 32 struct ar2133State { 33 RF_HAL_FUNCS base; /* public state, must be first */ 34 uint16_t pcdacTable[1]; 35 36 uint32_t *Bank0Data; 37 uint32_t *Bank1Data; 38 uint32_t *Bank2Data; 39 uint32_t *Bank3Data; 40 uint32_t *Bank6Data; 41 uint32_t *Bank7Data; 42 43 /* NB: Bank*Data storage follows */ 44 }; 45 #define AR2133(ah) ((struct ar2133State *) AH5212(ah)->ah_rfHal) 46 47 #define ar5416ModifyRfBuffer ar5212ModifyRfBuffer /*XXX*/ 48 49 void ar5416ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, 50 uint32_t numBits, uint32_t firstBit, uint32_t column); 51 52 static void 53 ar2133WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, 54 int writes) 55 { 56 (void) ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_bb_rfgain, 57 freqIndex, writes); 58 } 59 60 /* 61 * Take the MHz channel value and set the Channel value 62 * 63 * ASSUMES: Writes enabled to analog bus 64 */ 65 static HAL_BOOL 66 ar2133SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) 67 { 68 uint32_t channelSel = 0; 69 uint32_t bModeSynth = 0; 70 uint32_t aModeRefSel = 0; 71 uint32_t reg32 = 0; 72 uint16_t freq; 73 CHAN_CENTERS centers; 74 75 OS_MARK(ah, AH_MARK_SETCHANNEL, chan->ic_freq); 76 77 ar5416GetChannelCenters(ah, chan, ¢ers); 78 freq = centers.synth_center; 79 80 if (freq < 4800) { 81 uint32_t txctl; 82 83 if (((freq - 2192) % 5) == 0) { 84 channelSel = ((freq - 672) * 2 - 3040)/10; 85 bModeSynth = 0; 86 } else if (((freq - 2224) % 5) == 0) { 87 channelSel = ((freq - 704) * 2 - 3040) / 10; 88 bModeSynth = 1; 89 } else { 90 HALDEBUG(ah, HAL_DEBUG_ANY, 91 "%s: invalid channel %u MHz\n", __func__, freq); 92 return AH_FALSE; 93 } 94 95 channelSel = (channelSel << 2) & 0xff; 96 channelSel = ath_hal_reverseBits(channelSel, 8); 97 98 txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); 99 if (freq == 2484) { 100 /* Enable channel spreading for channel 14 */ 101 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 102 txctl | AR_PHY_CCK_TX_CTRL_JAPAN); 103 } else { 104 OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, 105 txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); 106 } 107 } else if ((freq % 20) == 0 && freq >= 5120) { 108 channelSel = ath_hal_reverseBits(((freq - 4800) / 20 << 2), 8); 109 if (AR_SREV_SOWL_10_OR_LATER(ah)) 110 aModeRefSel = ath_hal_reverseBits(3, 2); 111 else 112 aModeRefSel = ath_hal_reverseBits(1, 2); 113 } else if ((freq % 10) == 0) { 114 channelSel = ath_hal_reverseBits(((freq - 4800) / 10 << 1), 8); 115 if (AR_SREV_SOWL_10_OR_LATER(ah)) 116 aModeRefSel = ath_hal_reverseBits(2, 2); 117 else 118 aModeRefSel = ath_hal_reverseBits(1, 2); 119 } else if ((freq % 5) == 0) { 120 channelSel = ath_hal_reverseBits((freq - 4800) / 5, 8); 121 aModeRefSel = ath_hal_reverseBits(1, 2); 122 } else { 123 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", 124 __func__, freq); 125 return AH_FALSE; 126 } 127 128 reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | 129 (1 << 5) | 0x1; 130 131 OS_REG_WRITE(ah, AR_PHY(0x37), reg32); 132 133 AH_PRIVATE(ah)->ah_curchan = chan; 134 return AH_TRUE; 135 136 } 137 138 /* 139 * Return a reference to the requested RF Bank. 140 */ 141 static uint32_t * 142 ar2133GetRfBank(struct ath_hal *ah, int bank) 143 { 144 struct ar2133State *priv = AR2133(ah); 145 146 HALASSERT(priv != AH_NULL); 147 switch (bank) { 148 case 1: return priv->Bank1Data; 149 case 2: return priv->Bank2Data; 150 case 3: return priv->Bank3Data; 151 case 6: return priv->Bank6Data; 152 case 7: return priv->Bank7Data; 153 } 154 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", 155 __func__, bank); 156 return AH_NULL; 157 } 158 159 /* 160 * Reads EEPROM header info from device structure and programs 161 * all rf registers 162 * 163 * REQUIRES: Access to the analog rf device 164 */ 165 static HAL_BOOL 166 ar2133SetRfRegs(struct ath_hal *ah, const struct ieee80211_channel *chan, 167 uint16_t modesIndex, uint16_t *rfXpdGain) 168 { 169 struct ar2133State *priv = AR2133(ah); 170 int writes; 171 172 HALASSERT(priv); 173 174 /* Setup Bank 0 Write */ 175 ath_hal_ini_bank_setup(priv->Bank0Data, &AH5416(ah)->ah_ini_bank0, 1); 176 177 /* Setup Bank 1 Write */ 178 ath_hal_ini_bank_setup(priv->Bank1Data, &AH5416(ah)->ah_ini_bank1, 1); 179 180 /* Setup Bank 2 Write */ 181 ath_hal_ini_bank_setup(priv->Bank2Data, &AH5416(ah)->ah_ini_bank2, 1); 182 183 /* Setup Bank 3 Write */ 184 ath_hal_ini_bank_setup(priv->Bank3Data, &AH5416(ah)->ah_ini_bank3, modesIndex); 185 186 /* Setup Bank 6 Write */ 187 ath_hal_ini_bank_setup(priv->Bank6Data, &AH5416(ah)->ah_ini_bank6, modesIndex); 188 189 /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ 190 if (IEEE80211_IS_CHAN_2GHZ(chan)) { 191 ar5416ModifyRfBuffer(priv->Bank6Data, 192 ath_hal_eepromGet(ah, AR_EEP_OB_2, AH_NULL), 3, 197, 0); 193 ar5416ModifyRfBuffer(priv->Bank6Data, 194 ath_hal_eepromGet(ah, AR_EEP_DB_2, AH_NULL), 3, 194, 0); 195 } else { 196 ar5416ModifyRfBuffer(priv->Bank6Data, 197 ath_hal_eepromGet(ah, AR_EEP_OB_5, AH_NULL), 3, 203, 0); 198 ar5416ModifyRfBuffer(priv->Bank6Data, 199 ath_hal_eepromGet(ah, AR_EEP_DB_5, AH_NULL), 3, 200, 0); 200 } 201 /* Setup Bank 7 Setup */ 202 ath_hal_ini_bank_setup(priv->Bank7Data, &AH5416(ah)->ah_ini_bank7, 1); 203 204 /* Write Analog registers */ 205 writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank0, 206 priv->Bank0Data, 0); 207 writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank1, 208 priv->Bank1Data, writes); 209 writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank2, 210 priv->Bank2Data, writes); 211 writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank3, 212 priv->Bank3Data, writes); 213 writes = ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank6, 214 priv->Bank6Data, writes); 215 (void) ath_hal_ini_bank_write(ah, &AH5416(ah)->ah_ini_bank7, 216 priv->Bank7Data, writes); 217 218 return AH_TRUE; 219 #undef RF_BANK_SETUP 220 } 221 222 /* 223 * Read the transmit power levels from the structures taken from EEPROM 224 * Interpolate read transmit power values for this channel 225 * Organize the transmit power values into a table for writing into the hardware 226 */ 227 228 static HAL_BOOL 229 ar2133SetPowerTable(struct ath_hal *ah, int16_t *pPowerMin, int16_t *pPowerMax, 230 const struct ieee80211_channel *chan, uint16_t *rfXpdGain) 231 { 232 return AH_TRUE; 233 } 234 235 #if 0 236 static int16_t 237 ar2133GetMinPower(struct ath_hal *ah, EXPN_DATA_PER_CHANNEL_5112 *data) 238 { 239 int i, minIndex; 240 int16_t minGain,minPwr,minPcdac,retVal; 241 242 /* Assume NUM_POINTS_XPD0 > 0 */ 243 minGain = data->pDataPerXPD[0].xpd_gain; 244 for (minIndex=0,i=1; i<NUM_XPD_PER_CHANNEL; i++) { 245 if (data->pDataPerXPD[i].xpd_gain < minGain) { 246 minIndex = i; 247 minGain = data->pDataPerXPD[i].xpd_gain; 248 } 249 } 250 minPwr = data->pDataPerXPD[minIndex].pwr_t4[0]; 251 minPcdac = data->pDataPerXPD[minIndex].pcdac[0]; 252 for (i=1; i<NUM_POINTS_XPD0; i++) { 253 if (data->pDataPerXPD[minIndex].pwr_t4[i] < minPwr) { 254 minPwr = data->pDataPerXPD[minIndex].pwr_t4[i]; 255 minPcdac = data->pDataPerXPD[minIndex].pcdac[i]; 256 } 257 } 258 retVal = minPwr - (minPcdac*2); 259 return(retVal); 260 } 261 #endif 262 263 static HAL_BOOL 264 ar2133GetChannelMaxMinPower(struct ath_hal *ah, 265 const struct ieee80211_channel *chan, 266 int16_t *maxPow, int16_t *minPow) 267 { 268 #if 0 269 struct ath_hal_5212 *ahp = AH5212(ah); 270 int numChannels=0,i,last; 271 int totalD, totalF,totalMin; 272 EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL; 273 EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL; 274 275 *maxPow = 0; 276 if (IS_CHAN_A(chan)) { 277 powerArray = ahp->ah_modePowerArray5112; 278 data = powerArray[headerInfo11A].pDataPerChannel; 279 numChannels = powerArray[headerInfo11A].numChannels; 280 } else if (IS_CHAN_G(chan) || IS_CHAN_108G(chan)) { 281 /* XXX - is this correct? Should we also use the same power for turbo G? */ 282 powerArray = ahp->ah_modePowerArray5112; 283 data = powerArray[headerInfo11G].pDataPerChannel; 284 numChannels = powerArray[headerInfo11G].numChannels; 285 } else if (IS_CHAN_B(chan)) { 286 powerArray = ahp->ah_modePowerArray5112; 287 data = powerArray[headerInfo11B].pDataPerChannel; 288 numChannels = powerArray[headerInfo11B].numChannels; 289 } else { 290 return (AH_TRUE); 291 } 292 /* Make sure the channel is in the range of the TP values 293 * (freq piers) 294 */ 295 if ((numChannels < 1) || 296 (chan->channel < data[0].channelValue) || 297 (chan->channel > data[numChannels-1].channelValue)) 298 return(AH_FALSE); 299 300 /* Linearly interpolate the power value now */ 301 for (last=0,i=0; 302 (i<numChannels) && (chan->channel > data[i].channelValue); 303 last=i++); 304 totalD = data[i].channelValue - data[last].channelValue; 305 if (totalD > 0) { 306 totalF = data[i].maxPower_t4 - data[last].maxPower_t4; 307 *maxPow = (int8_t) ((totalF*(chan->channel-data[last].channelValue) + data[last].maxPower_t4*totalD)/totalD); 308 309 totalMin = ar2133GetMinPower(ah,&data[i]) - ar2133GetMinPower(ah, &data[last]); 310 *minPow = (int8_t) ((totalMin*(chan->channel-data[last].channelValue) + ar2133GetMinPower(ah, &data[last])*totalD)/totalD); 311 return (AH_TRUE); 312 } else { 313 if (chan->channel == data[i].channelValue) { 314 *maxPow = data[i].maxPower_t4; 315 *minPow = ar2133GetMinPower(ah, &data[i]); 316 return(AH_TRUE); 317 } else 318 return(AH_FALSE); 319 } 320 #else 321 *maxPow = *minPow = 0; 322 return AH_FALSE; 323 #endif 324 } 325 326 static void 327 ar2133GetNoiseFloor(struct ath_hal *ah, int16_t nfarray[]) 328 { 329 struct ath_hal_5416 *ahp = AH5416(ah); 330 int16_t nf; 331 332 switch (ahp->ah_rx_chainmask) { 333 case 0x7: 334 nf = MS(OS_REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR); 335 if (nf & 0x100) 336 nf = 0 - ((nf ^ 0x1ff) + 1); 337 HALDEBUG(ah, HAL_DEBUG_NFCAL, 338 "NF calibrated [ctl] [chain 2] is %d\n", nf); 339 nfarray[4] = nf; 340 341 nf = MS(OS_REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR); 342 if (nf & 0x100) 343 nf = 0 - ((nf ^ 0x1ff) + 1); 344 HALDEBUG(ah, HAL_DEBUG_NFCAL, 345 "NF calibrated [ext] [chain 2] is %d\n", nf); 346 nfarray[5] = nf; 347 /* fall thru... */ 348 case 0x3: 349 case 0x5: 350 nf = MS(OS_REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR); 351 if (nf & 0x100) 352 nf = 0 - ((nf ^ 0x1ff) + 1); 353 HALDEBUG(ah, HAL_DEBUG_NFCAL, 354 "NF calibrated [ctl] [chain 1] is %d\n", nf); 355 nfarray[2] = nf; 356 357 358 nf = MS(OS_REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR); 359 if (nf & 0x100) 360 nf = 0 - ((nf ^ 0x1ff) + 1); 361 HALDEBUG(ah, HAL_DEBUG_NFCAL, 362 "NF calibrated [ext] [chain 1] is %d\n", nf); 363 nfarray[3] = nf; 364 /* fall thru... */ 365 case 0x1: 366 nf = MS(OS_REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); 367 if (nf & 0x100) 368 nf = 0 - ((nf ^ 0x1ff) + 1); 369 HALDEBUG(ah, HAL_DEBUG_NFCAL, 370 "NF calibrated [ctl] [chain 0] is %d\n", nf); 371 nfarray[0] = nf; 372 373 nf = MS(OS_REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR); 374 if (nf & 0x100) 375 nf = 0 - ((nf ^ 0x1ff) + 1); 376 HALDEBUG(ah, HAL_DEBUG_NFCAL, 377 "NF calibrated [ext] [chain 0] is %d\n", nf); 378 nfarray[1] = nf; 379 380 break; 381 } 382 } 383 384 /* 385 * Adjust NF based on statistical values for 5GHz frequencies. 386 * Stubbed:Not used by Fowl 387 */ 388 static int16_t 389 ar2133GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 390 { 391 return 0; 392 } 393 394 /* 395 * Free memory for analog bank scratch buffers 396 */ 397 static void 398 ar2133RfDetach(struct ath_hal *ah) 399 { 400 struct ath_hal_5212 *ahp = AH5212(ah); 401 402 HALASSERT(ahp->ah_rfHal != AH_NULL); 403 ath_hal_free(ahp->ah_rfHal); 404 ahp->ah_rfHal = AH_NULL; 405 } 406 407 /* 408 * Allocate memory for analog bank scratch buffers 409 * Scratch Buffer will be reinitialized every reset so no need to zero now 410 */ 411 HAL_BOOL 412 ar2133RfAttach(struct ath_hal *ah, HAL_STATUS *status) 413 { 414 struct ath_hal_5212 *ahp = AH5212(ah); 415 struct ar2133State *priv; 416 uint32_t *bankData; 417 418 HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: attach AR2133 radio\n", __func__); 419 420 HALASSERT(ahp->ah_rfHal == AH_NULL); 421 priv = ath_hal_malloc(sizeof(struct ar2133State) 422 + AH5416(ah)->ah_ini_bank0.rows * sizeof(uint32_t) 423 + AH5416(ah)->ah_ini_bank1.rows * sizeof(uint32_t) 424 + AH5416(ah)->ah_ini_bank2.rows * sizeof(uint32_t) 425 + AH5416(ah)->ah_ini_bank3.rows * sizeof(uint32_t) 426 + AH5416(ah)->ah_ini_bank6.rows * sizeof(uint32_t) 427 + AH5416(ah)->ah_ini_bank7.rows * sizeof(uint32_t) 428 ); 429 if (priv == AH_NULL) { 430 HALDEBUG(ah, HAL_DEBUG_ANY, 431 "%s: cannot allocate private state\n", __func__); 432 *status = HAL_ENOMEM; /* XXX */ 433 return AH_FALSE; 434 } 435 priv->base.rfDetach = ar2133RfDetach; 436 priv->base.writeRegs = ar2133WriteRegs; 437 priv->base.getRfBank = ar2133GetRfBank; 438 priv->base.setChannel = ar2133SetChannel; 439 priv->base.setRfRegs = ar2133SetRfRegs; 440 priv->base.setPowerTable = ar2133SetPowerTable; 441 priv->base.getChannelMaxMinPower = ar2133GetChannelMaxMinPower; 442 priv->base.getNfAdjust = ar2133GetNfAdjust; 443 444 bankData = (uint32_t *) &priv[1]; 445 priv->Bank0Data = bankData, bankData += AH5416(ah)->ah_ini_bank0.rows; 446 priv->Bank1Data = bankData, bankData += AH5416(ah)->ah_ini_bank1.rows; 447 priv->Bank2Data = bankData, bankData += AH5416(ah)->ah_ini_bank2.rows; 448 priv->Bank3Data = bankData, bankData += AH5416(ah)->ah_ini_bank3.rows; 449 priv->Bank6Data = bankData, bankData += AH5416(ah)->ah_ini_bank6.rows; 450 priv->Bank7Data = bankData, bankData += AH5416(ah)->ah_ini_bank7.rows; 451 452 ahp->ah_pcdacTable = priv->pcdacTable; 453 ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable); 454 ahp->ah_rfHal = &priv->base; 455 /* 456 * Set noise floor adjust method; we arrange a 457 * direct call instead of thunking. 458 */ 459 AH_PRIVATE(ah)->ah_getNfAdjust = priv->base.getNfAdjust; 460 AH_PRIVATE(ah)->ah_getNoiseFloor = ar2133GetNoiseFloor; 461 462 return AH_TRUE; 463 } 464