1185377Ssam/* 2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2004 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 * 17187611Ssam * $FreeBSD$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam 24185377Ssam#include "ar5210/ar5210.h" 25185377Ssam#include "ar5210/ar5210reg.h" 26185377Ssam#include "ar5210/ar5210phy.h" 27185377Ssam 28185380Ssam#include "ah_eeprom_v1.h" 29185380Ssam 30185377Ssamtypedef struct { 31185377Ssam uint32_t Offset; 32185377Ssam uint32_t Value; 33185377Ssam} REGISTER_VAL; 34185377Ssam 35185377Ssamstatic const REGISTER_VAL ar5k0007_init[] = { 36185377Ssam#include "ar5210/ar5k_0007.ini" 37185377Ssam}; 38185377Ssam 39185377Ssam/* Default Power Settings for channels outside of EEPROM range */ 40185377Ssamstatic const uint8_t ar5k0007_pwrSettings[17] = { 41185377Ssam/* gain delta pc dac */ 42185377Ssam/* 54 48 36 24 18 12 9 54 48 36 24 18 12 9 6 ob db */ 43185377Ssam 9, 9, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2 44185377Ssam}; 45185377Ssam 46185377Ssam/* 47185377Ssam * The delay, in usecs, between writing AR_RC with a reset 48185377Ssam * request and waiting for the chip to settle. If this is 49185377Ssam * too short then the chip does not come out of sleep state. 50185377Ssam * Note this value was empirically derived and may be dependent 51185377Ssam * on the host machine (don't know--the problem was identified 52185377Ssam * on an IBM 570e laptop; 10us delays worked on other systems). 53185377Ssam */ 54185377Ssam#define AR_RC_SETTLE_TIME 20000 55185377Ssam 56185377Ssamstatic HAL_BOOL ar5210SetResetReg(struct ath_hal *, 57185377Ssam uint32_t resetMask, u_int delay); 58187831Ssamstatic HAL_BOOL ar5210SetChannel(struct ath_hal *, struct ieee80211_channel *); 59185377Ssamstatic void ar5210SetOperatingMode(struct ath_hal *, int opmode); 60185377Ssam 61185377Ssam/* 62185377Ssam * Places the device in and out of reset and then places sane 63185377Ssam * values in the registers based on EEPROM config, initialization 64185377Ssam * vectors (as determined by the mode), and station configuration 65185377Ssam * 66185377Ssam * bChannelChange is used to preserve DMA/PCU registers across 67185377Ssam * a HW Reset during channel change. 68185377Ssam */ 69185377SsamHAL_BOOL 70185377Ssamar5210Reset(struct ath_hal *ah, HAL_OPMODE opmode, 71187831Ssam struct ieee80211_channel *chan, HAL_BOOL bChannelChange, 72290612Sadrian HAL_RESET_TYPE resetType, 73187831Ssam HAL_STATUS *status) 74185377Ssam{ 75185377Ssam#define N(a) (sizeof (a) /sizeof (a[0])) 76185377Ssam#define FAIL(_code) do { ecode = _code; goto bad; } while (0) 77185377Ssam struct ath_hal_5210 *ahp = AH5210(ah); 78185380Ssam const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; 79185377Ssam HAL_CHANNEL_INTERNAL *ichan; 80185377Ssam HAL_STATUS ecode; 81185377Ssam uint32_t ledstate; 82185377Ssam int i, q; 83185377Ssam 84185377Ssam HALDEBUG(ah, HAL_DEBUG_RESET, 85185377Ssam "%s: opmode %u channel %u/0x%x %s channel\n", __func__, 86187831Ssam opmode, chan->ic_freq, chan->ic_flags, 87185377Ssam bChannelChange ? "change" : "same"); 88185377Ssam 89187831Ssam if (!IEEE80211_IS_CHAN_5GHZ(chan)) { 90185377Ssam /* Only 11a mode */ 91202161Sgavin HALDEBUG(ah, HAL_DEBUG_ANY, "%s: channel not 5GHz\n", __func__); 92185377Ssam FAIL(HAL_EINVAL); 93185377Ssam } 94185377Ssam /* 95185377Ssam * Map public channel to private. 96185377Ssam */ 97185377Ssam ichan = ath_hal_checkchannel(ah, chan); 98185377Ssam if (ichan == AH_NULL) { 99185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 100185377Ssam "%s: invalid channel %u/0x%x; no mapping\n", 101187831Ssam __func__, chan->ic_freq, chan->ic_flags); 102185377Ssam FAIL(HAL_EINVAL); 103185377Ssam } 104185377Ssam switch (opmode) { 105185377Ssam case HAL_M_STA: 106185377Ssam case HAL_M_IBSS: 107185377Ssam case HAL_M_HOSTAP: 108185377Ssam case HAL_M_MONITOR: 109185377Ssam break; 110185377Ssam default: 111185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", 112185377Ssam __func__, opmode); 113185377Ssam FAIL(HAL_EINVAL); 114185377Ssam break; 115185377Ssam } 116185377Ssam 117185377Ssam ledstate = OS_REG_READ(ah, AR_PCICFG) & 118185377Ssam (AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT); 119185377Ssam 120185377Ssam if (!ar5210ChipReset(ah, chan)) { 121185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", 122185377Ssam __func__); 123185377Ssam FAIL(HAL_EIO); 124185377Ssam } 125185377Ssam 126185377Ssam OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); 127185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)); 128185377Ssam ar5210SetOperatingMode(ah, opmode); 129185377Ssam 130185377Ssam switch (opmode) { 131185377Ssam case HAL_M_HOSTAP: 132185377Ssam OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); 133185377Ssam OS_REG_WRITE(ah, AR_PCICFG, 134185377Ssam AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL); 135185377Ssam break; 136185377Ssam case HAL_M_IBSS: 137185377Ssam OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG | AR_BCR_BCMD); 138185377Ssam OS_REG_WRITE(ah, AR_PCICFG, 139185377Ssam AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL); 140185377Ssam break; 141185377Ssam case HAL_M_STA: 142185377Ssam OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); 143185377Ssam OS_REG_WRITE(ah, AR_PCICFG, 144185377Ssam AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL); 145185377Ssam break; 146185377Ssam case HAL_M_MONITOR: 147185377Ssam OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); 148185377Ssam OS_REG_WRITE(ah, AR_PCICFG, 149185377Ssam AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL); 150185377Ssam break; 151185377Ssam } 152185377Ssam 153185377Ssam /* Restore previous led state */ 154185377Ssam OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate); 155185377Ssam 156264899Sadrian#if 0 157185377Ssam OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 158185377Ssam OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); 159264899Sadrian#endif 160264899Sadrian /* BSSID, association id, ps-poll */ 161264899Sadrian ar5210WriteAssocid(ah, ahp->ah_bssid, ahp->ah_associd); 162185377Ssam 163185377Ssam OS_REG_WRITE(ah, AR_TXDP0, 0); 164185377Ssam OS_REG_WRITE(ah, AR_TXDP1, 0); 165185377Ssam OS_REG_WRITE(ah, AR_RXDP, 0); 166185377Ssam 167185377Ssam /* 168185377Ssam * Initialize interrupt state. 169185377Ssam */ 170185377Ssam (void) OS_REG_READ(ah, AR_ISR); /* cleared on read */ 171185377Ssam OS_REG_WRITE(ah, AR_IMR, 0); 172185377Ssam OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); 173185377Ssam ahp->ah_maskReg = 0; 174185377Ssam 175185377Ssam (void) OS_REG_READ(ah, AR_BSR); /* cleared on read */ 176185377Ssam OS_REG_WRITE(ah, AR_TXCFG, AR_DMASIZE_128B); 177185377Ssam OS_REG_WRITE(ah, AR_RXCFG, AR_DMASIZE_128B); 178185377Ssam 179185377Ssam OS_REG_WRITE(ah, AR_TOPS, 8); /* timeout prescale */ 180185377Ssam OS_REG_WRITE(ah, AR_RXNOFRM, 8); /* RX no frame timeout */ 181185377Ssam OS_REG_WRITE(ah, AR_RPGTO, 0); /* RX frame gap timeout */ 182185377Ssam OS_REG_WRITE(ah, AR_TXNOFRM, 0); /* TX no frame timeout */ 183185377Ssam 184185377Ssam OS_REG_WRITE(ah, AR_SFR, 0); 185185377Ssam OS_REG_WRITE(ah, AR_MIBC, 0); /* unfreeze ctrs + clr state */ 186185377Ssam OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); 187185377Ssam OS_REG_WRITE(ah, AR_CFP_DUR, 0); 188185377Ssam 189185377Ssam ar5210SetRxFilter(ah, 0); /* nothing for now */ 190185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL0, 0); /* multicast filter */ 191185377Ssam OS_REG_WRITE(ah, AR_MCAST_FIL1, 0); /* XXX was 2 */ 192185377Ssam 193185377Ssam OS_REG_WRITE(ah, AR_TX_MASK0, 0); 194185377Ssam OS_REG_WRITE(ah, AR_TX_MASK1, 0); 195185377Ssam OS_REG_WRITE(ah, AR_CLR_TMASK, 1); 196185377Ssam OS_REG_WRITE(ah, AR_TRIG_LEV, 1); /* minimum */ 197185377Ssam 198243317Sadrian ar5210UpdateDiagReg(ah, 0); 199185377Ssam 200185377Ssam OS_REG_WRITE(ah, AR_CFP_PERIOD, 0); 201185377Ssam OS_REG_WRITE(ah, AR_TIMER0, 0); /* next beacon time */ 202185377Ssam OS_REG_WRITE(ah, AR_TSF_L32, 0); /* local clock */ 203185377Ssam OS_REG_WRITE(ah, AR_TIMER1, ~0); /* next DMA beacon alert */ 204185377Ssam OS_REG_WRITE(ah, AR_TIMER2, ~0); /* next SW beacon alert */ 205185377Ssam OS_REG_WRITE(ah, AR_TIMER3, 1); /* next ATIM window */ 206185377Ssam 207185377Ssam /* Write the INI values for PHYreg initialization */ 208185377Ssam for (i = 0; i < N(ar5k0007_init); i++) { 209185377Ssam uint32_t reg = ar5k0007_init[i].Offset; 210185377Ssam /* On channel change, don't reset the PCU registers */ 211185377Ssam if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000))) 212185377Ssam OS_REG_WRITE(ah, reg, ar5k0007_init[i].Value); 213185377Ssam } 214185377Ssam 215185377Ssam /* Setup the transmit power values for cards since 0x0[0-2]05 */ 216185377Ssam if (!ar5210SetTransmitPower(ah, chan)) { 217185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 218185377Ssam "%s: error init'ing transmit power\n", __func__); 219185377Ssam FAIL(HAL_EIO); 220185377Ssam } 221185377Ssam 222185377Ssam OS_REG_WRITE(ah, AR_PHY(10), 223185377Ssam (OS_REG_READ(ah, AR_PHY(10)) & 0xFFFF00FF) | 224185380Ssam (ee->ee_xlnaOn << 8)); 225185377Ssam OS_REG_WRITE(ah, AR_PHY(13), 226185380Ssam (ee->ee_xpaOff << 24) | (ee->ee_xpaOff << 16) | 227185380Ssam (ee->ee_xpaOn << 8) | ee->ee_xpaOn); 228185377Ssam OS_REG_WRITE(ah, AR_PHY(17), 229185377Ssam (OS_REG_READ(ah, AR_PHY(17)) & 0xFFFFC07F) | 230185380Ssam ((ee->ee_antenna >> 1) & 0x3F80)); 231185377Ssam OS_REG_WRITE(ah, AR_PHY(18), 232185377Ssam (OS_REG_READ(ah, AR_PHY(18)) & 0xFFFC0FFF) | 233185380Ssam ((ee->ee_antenna << 10) & 0x3F000)); 234185377Ssam OS_REG_WRITE(ah, AR_PHY(25), 235185377Ssam (OS_REG_READ(ah, AR_PHY(25)) & 0xFFF80FFF) | 236185380Ssam ((ee->ee_thresh62 << 12) & 0x7F000)); 237185377Ssam OS_REG_WRITE(ah, AR_PHY(68), 238185377Ssam (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) | 239185380Ssam (ee->ee_antenna & 0x3)); 240185377Ssam 241187831Ssam if (!ar5210SetChannel(ah, chan)) { 242185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n", 243185377Ssam __func__); 244185377Ssam FAIL(HAL_EIO); 245185377Ssam } 246187831Ssam if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan)) 247187831Ssam chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; 248185377Ssam 249185377Ssam /* Activate the PHY */ 250185377Ssam OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ENABLE); 251185377Ssam 252185377Ssam OS_DELAY(1000); /* Wait a bit (1 msec) */ 253185377Ssam 254185377Ssam /* calibrate the HW and poll the bit going to 0 for completion */ 255185377Ssam OS_REG_WRITE(ah, AR_PHY_AGCCTL, 256185377Ssam OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL); 257185377Ssam (void) ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0); 258185377Ssam 259185377Ssam /* Perform noise floor calibration and set status */ 260185377Ssam if (!ar5210CalNoiseFloor(ah, ichan)) { 261187831Ssam chan->ic_state |= IEEE80211_CHANSTATE_CWINT; 262185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 263185377Ssam "%s: noise floor calibration failed\n", __func__); 264185377Ssam FAIL(HAL_EIO); 265185377Ssam } 266185377Ssam 267185377Ssam for (q = 0; q < HAL_NUM_TX_QUEUES; q++) 268185377Ssam ar5210ResetTxQueue(ah, q); 269185377Ssam 270185377Ssam if (AH_PRIVATE(ah)->ah_rfkillEnabled) 271185377Ssam ar5210EnableRfKill(ah); 272185377Ssam 273185377Ssam /* 274185377Ssam * Writing to AR_BEACON will start timers. Hence it should be 275185377Ssam * the last register to be written. Do not reset tsf, do not 276185377Ssam * enable beacons at this point, but preserve other values 277185377Ssam * like beaconInterval. 278185377Ssam */ 279185377Ssam OS_REG_WRITE(ah, AR_BEACON, 280185377Ssam (OS_REG_READ(ah, AR_BEACON) & 281185377Ssam ~(AR_BEACON_EN | AR_BEACON_RESET_TSF))); 282185377Ssam 283185377Ssam /* Restore user-specified slot time and timeouts */ 284185377Ssam if (ahp->ah_sifstime != (u_int) -1) 285185377Ssam ar5210SetSifsTime(ah, ahp->ah_sifstime); 286185377Ssam if (ahp->ah_slottime != (u_int) -1) 287185377Ssam ar5210SetSlotTime(ah, ahp->ah_slottime); 288185377Ssam if (ahp->ah_acktimeout != (u_int) -1) 289185377Ssam ar5210SetAckTimeout(ah, ahp->ah_acktimeout); 290185377Ssam if (ahp->ah_ctstimeout != (u_int) -1) 291185377Ssam ar5210SetCTSTimeout(ah, ahp->ah_ctstimeout); 292185377Ssam if (AH_PRIVATE(ah)->ah_diagreg != 0) 293243317Sadrian ar5210UpdateDiagReg(ah, AH_PRIVATE(ah)->ah_diagreg); 294185377Ssam 295185377Ssam AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ 296185377Ssam 297185377Ssam HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); 298185377Ssam 299185377Ssam return AH_TRUE; 300185377Ssambad: 301187611Ssam if (status != AH_NULL) 302185377Ssam *status = ecode; 303185377Ssam return AH_FALSE; 304185377Ssam#undef FAIL 305185377Ssam#undef N 306185377Ssam} 307185377Ssam 308185377Ssamstatic void 309185377Ssamar5210SetOperatingMode(struct ath_hal *ah, int opmode) 310185377Ssam{ 311185377Ssam struct ath_hal_5210 *ahp = AH5210(ah); 312185377Ssam uint32_t val; 313185377Ssam 314185377Ssam val = OS_REG_READ(ah, AR_STA_ID1) & 0xffff; 315185377Ssam switch (opmode) { 316185377Ssam case HAL_M_HOSTAP: 317185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, val 318185377Ssam | AR_STA_ID1_AP 319185377Ssam | AR_STA_ID1_NO_PSPOLL 320185377Ssam | AR_STA_ID1_DESC_ANTENNA 321185377Ssam | ahp->ah_staId1Defaults); 322185377Ssam break; 323185377Ssam case HAL_M_IBSS: 324185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, val 325185377Ssam | AR_STA_ID1_ADHOC 326185377Ssam | AR_STA_ID1_NO_PSPOLL 327185377Ssam | AR_STA_ID1_DESC_ANTENNA 328185377Ssam | ahp->ah_staId1Defaults); 329185377Ssam break; 330185377Ssam case HAL_M_STA: 331185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, val 332185377Ssam | AR_STA_ID1_NO_PSPOLL 333185377Ssam | AR_STA_ID1_PWR_SV 334185377Ssam | ahp->ah_staId1Defaults); 335185377Ssam break; 336185377Ssam case HAL_M_MONITOR: 337185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, val 338185377Ssam | AR_STA_ID1_NO_PSPOLL 339185377Ssam | ahp->ah_staId1Defaults); 340185377Ssam break; 341185377Ssam } 342185377Ssam} 343185377Ssam 344185377Ssamvoid 345185377Ssamar5210SetPCUConfig(struct ath_hal *ah) 346185377Ssam{ 347185377Ssam ar5210SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); 348185377Ssam} 349185377Ssam 350185377Ssam/* 351185377Ssam * Places the PHY and Radio chips into reset. A full reset 352185377Ssam * must be called to leave this state. The PCI/MAC/PCU are 353185377Ssam * not placed into reset as we must receive interrupt to 354185377Ssam * re-enable the hardware. 355185377Ssam */ 356185377SsamHAL_BOOL 357185377Ssamar5210PhyDisable(struct ath_hal *ah) 358185377Ssam{ 359185377Ssam return ar5210SetResetReg(ah, AR_RC_RPHY, 10); 360185377Ssam} 361185377Ssam 362185377Ssam/* 363185377Ssam * Places all of hardware into reset 364185377Ssam */ 365185377SsamHAL_BOOL 366185377Ssamar5210Disable(struct ath_hal *ah) 367185377Ssam{ 368185377Ssam#define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC) 369185377Ssam if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) 370185377Ssam return AH_FALSE; 371185377Ssam 372185377Ssam /* 373185377Ssam * Reset the HW - PCI must be reset after the rest of the 374185377Ssam * device has been reset 375185377Ssam */ 376185377Ssam if (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME)) 377185377Ssam return AH_FALSE; 378185377Ssam OS_DELAY(1000); 379185377Ssam (void) ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME); 380185377Ssam OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ 381185377Ssam 382185377Ssam return AH_TRUE; 383185377Ssam#undef AR_RC_HW 384185377Ssam} 385185377Ssam 386185377Ssam/* 387185377Ssam * Places the hardware into reset and then pulls it out of reset 388185377Ssam */ 389185377SsamHAL_BOOL 390187831Ssamar5210ChipReset(struct ath_hal *ah, struct ieee80211_channel *chan) 391185377Ssam{ 392185377Ssam#define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC) 393185377Ssam 394185377Ssam HALDEBUG(ah, HAL_DEBUG_RESET, "%s turbo %s\n", __func__, 395187831Ssam chan && IEEE80211_IS_CHAN_TURBO(chan) ? 396187831Ssam "enabled" : "disabled"); 397185377Ssam 398185377Ssam if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) 399185377Ssam return AH_FALSE; 400185377Ssam 401185377Ssam /* Place chip in turbo before reset to cleanly reset clocks */ 402185377Ssam OS_REG_WRITE(ah, AR_PHY_FRCTL, 403187831Ssam chan && IEEE80211_IS_CHAN_TURBO(chan) ? AR_PHY_TURBO_MODE : 0); 404185377Ssam 405185377Ssam /* 406185377Ssam * Reset the HW. 407185377Ssam * PCI must be reset after the rest of the device has been reset. 408185377Ssam */ 409185377Ssam if (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME)) 410185377Ssam return AH_FALSE; 411185377Ssam OS_DELAY(1000); 412185377Ssam if (!ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME)) 413185377Ssam return AH_FALSE; 414185377Ssam OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ 415185377Ssam 416185377Ssam /* 417185377Ssam * Bring out of sleep mode (AGAIN) 418185377Ssam * 419185377Ssam * WARNING WARNING WARNING 420185377Ssam * 421185377Ssam * There is a problem with the chip where it doesn't always indicate 422185377Ssam * that it's awake, so initializePowerUp() will fail. 423185377Ssam */ 424185377Ssam if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) 425185377Ssam return AH_FALSE; 426185377Ssam 427185377Ssam /* Clear warm reset reg */ 428185377Ssam return ar5210SetResetReg(ah, 0, 10); 429185377Ssam#undef AR_RC_HW 430185377Ssam} 431185377Ssam 432185377Ssamenum { 433185377Ssam FIRPWR_M = 0x03fc0000, 434185377Ssam FIRPWR_S = 18, 435185377Ssam KCOARSEHIGH_M = 0x003f8000, 436185377Ssam KCOARSEHIGH_S = 15, 437185377Ssam KCOARSELOW_M = 0x00007f80, 438185377Ssam KCOARSELOW_S = 7, 439185377Ssam ADCSAT_ICOUNT_M = 0x0001f800, 440185377Ssam ADCSAT_ICOUNT_S = 11, 441185377Ssam ADCSAT_THRESH_M = 0x000007e0, 442185377Ssam ADCSAT_THRESH_S = 5 443185377Ssam}; 444185377Ssam 445185377Ssam/* 446185377Ssam * Recalibrate the lower PHY chips to account for temperature/environment 447185377Ssam * changes. 448185377Ssam */ 449185377SsamHAL_BOOL 450187831Ssamar5210PerCalibrationN(struct ath_hal *ah, 451187831Ssam struct ieee80211_channel *chan, u_int chainMask, 452185380Ssam HAL_BOOL longCal, HAL_BOOL *isCalDone) 453185377Ssam{ 454185377Ssam uint32_t regBeacon; 455185377Ssam uint32_t reg9858, reg985c, reg9868; 456185377Ssam HAL_CHANNEL_INTERNAL *ichan; 457185377Ssam 458185377Ssam ichan = ath_hal_checkchannel(ah, chan); 459187831Ssam if (ichan == AH_NULL) 460185377Ssam return AH_FALSE; 461185377Ssam /* Disable tx and rx */ 462243317Sadrian ar5210UpdateDiagReg(ah, 463185377Ssam OS_REG_READ(ah, AR_DIAG_SW) | (AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX)); 464185377Ssam 465185377Ssam /* Disable Beacon Enable */ 466185377Ssam regBeacon = OS_REG_READ(ah, AR_BEACON); 467185377Ssam OS_REG_WRITE(ah, AR_BEACON, regBeacon & ~AR_BEACON_EN); 468185377Ssam 469185377Ssam /* Delay 4ms to ensure that all tx and rx activity has ceased */ 470185377Ssam OS_DELAY(4000); 471185377Ssam 472185377Ssam /* Disable AGC to radio traffic */ 473185377Ssam OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000); 474185377Ssam /* Wait for the AGC traffic to cease. */ 475185377Ssam OS_DELAY(10); 476185377Ssam 477185377Ssam /* Change Channel to relock synth */ 478187831Ssam if (!ar5210SetChannel(ah, chan)) 479185377Ssam return AH_FALSE; 480185377Ssam 481185377Ssam /* wait for the synthesizer lock to stabilize */ 482185377Ssam OS_DELAY(1000); 483185377Ssam 484185377Ssam /* Re-enable AGC to radio traffic */ 485185377Ssam OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000)); 486185377Ssam 487185377Ssam /* 488185377Ssam * Configure the AGC so that it is highly unlikely (if not 489185377Ssam * impossible) for it to send any gain changes to the analog 490185377Ssam * chip. We store off the current values so that they can 491185377Ssam * be rewritten below. Setting the following values: 492185377Ssam * firpwr = -1 493185377Ssam * Kcoursehigh = -1 494185377Ssam * Kcourselow = -127 495185377Ssam * ADCsat_icount = 2 496185377Ssam * ADCsat_thresh = 12 497185377Ssam */ 498185377Ssam reg9858 = OS_REG_READ(ah, 0x9858); 499185377Ssam reg985c = OS_REG_READ(ah, 0x985c); 500185377Ssam reg9868 = OS_REG_READ(ah, 0x9868); 501185377Ssam 502185377Ssam OS_REG_WRITE(ah, 0x9858, (reg9858 & ~FIRPWR_M) | 503185377Ssam ((-1 << FIRPWR_S) & FIRPWR_M)); 504185377Ssam OS_REG_WRITE(ah, 0x985c, 505185377Ssam (reg985c & ~(KCOARSEHIGH_M | KCOARSELOW_M)) | 506185377Ssam ((-1 << KCOARSEHIGH_S) & KCOARSEHIGH_M) | 507185377Ssam ((-127 << KCOARSELOW_S) & KCOARSELOW_M)); 508185377Ssam OS_REG_WRITE(ah, 0x9868, 509185377Ssam (reg9868 & ~(ADCSAT_ICOUNT_M | ADCSAT_THRESH_M)) | 510185377Ssam ((2 << ADCSAT_ICOUNT_S) & ADCSAT_ICOUNT_M) | 511185377Ssam ((12 << ADCSAT_THRESH_S) & ADCSAT_THRESH_M)); 512185377Ssam 513185377Ssam /* Wait for AGC changes to be enacted */ 514185377Ssam OS_DELAY(20); 515185377Ssam 516185377Ssam /* 517185377Ssam * We disable RF mix/gain stages for the PGA to avoid a 518185377Ssam * race condition that will occur with receiving a frame 519185377Ssam * and performing the AGC calibration. This will be 520185377Ssam * re-enabled at the end of offset cal. We turn off AGC 521185377Ssam * writes during this write as it will go over the analog bus. 522185377Ssam */ 523185377Ssam OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000); 524185377Ssam OS_DELAY(10); /* wait for the AGC traffic to cease */ 525185377Ssam OS_REG_WRITE(ah, 0x98D4, 0x21); 526185377Ssam OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000)); 527185377Ssam 528185377Ssam /* wait to make sure that additional AGC traffic has quiesced */ 529185377Ssam OS_DELAY(1000); 530185377Ssam 531185377Ssam /* AGC calibration (this was added to make the NF threshold check work) */ 532185377Ssam OS_REG_WRITE(ah, AR_PHY_AGCCTL, 533185377Ssam OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL); 534208643Srpaulo if (!ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0)) { 535185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: AGC calibration timeout\n", 536185377Ssam __func__); 537208643Srpaulo } 538185377Ssam 539185377Ssam /* Rewrite our AGC values we stored off earlier (return AGC to normal operation) */ 540185377Ssam OS_REG_WRITE(ah, 0x9858, reg9858); 541185377Ssam OS_REG_WRITE(ah, 0x985c, reg985c); 542185377Ssam OS_REG_WRITE(ah, 0x9868, reg9868); 543185377Ssam 544185377Ssam /* Perform noise floor and set status */ 545185377Ssam if (!ar5210CalNoiseFloor(ah, ichan)) { 546185377Ssam /* 547185377Ssam * Delay 5ms before retrying the noise floor - 548185377Ssam * just to make sure. We're in an error 549185377Ssam * condition here 550185377Ssam */ 551185377Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL | HAL_DEBUG_PERCAL, 552185377Ssam "%s: Performing 2nd Noise Cal\n", __func__); 553185377Ssam OS_DELAY(5000); 554185377Ssam if (!ar5210CalNoiseFloor(ah, ichan)) 555187831Ssam chan->ic_state |= IEEE80211_CHANSTATE_CWINT; 556185377Ssam } 557185377Ssam 558185377Ssam /* Clear tx and rx disable bit */ 559243317Sadrian ar5210UpdateDiagReg(ah, 560185377Ssam OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX)); 561185377Ssam 562185377Ssam /* Re-enable Beacons */ 563185377Ssam OS_REG_WRITE(ah, AR_BEACON, regBeacon); 564185377Ssam 565185380Ssam *isCalDone = AH_TRUE; 566185377Ssam 567185377Ssam return AH_TRUE; 568185377Ssam} 569185377Ssam 570185380SsamHAL_BOOL 571187831Ssamar5210PerCalibration(struct ath_hal *ah, struct ieee80211_channel *chan, 572187831Ssam HAL_BOOL *isIQdone) 573185380Ssam{ 574185380Ssam return ar5210PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone); 575185380Ssam} 576185380Ssam 577185380SsamHAL_BOOL 578187831Ssamar5210ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *chan) 579185380Ssam{ 580185380Ssam return AH_TRUE; 581185380Ssam} 582185380Ssam 583185377Ssam/* 584185377Ssam * Writes the given reset bit mask into the reset register 585185377Ssam */ 586185377Ssamstatic HAL_BOOL 587185377Ssamar5210SetResetReg(struct ath_hal *ah, uint32_t resetMask, u_int delay) 588185377Ssam{ 589185377Ssam uint32_t mask = resetMask ? resetMask : ~0; 590185377Ssam HAL_BOOL rt; 591185377Ssam 592185377Ssam OS_REG_WRITE(ah, AR_RC, resetMask); 593185377Ssam /* need to wait at least 128 clocks when reseting PCI before read */ 594185377Ssam OS_DELAY(delay); 595185377Ssam 596185377Ssam resetMask &= AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC; 597185377Ssam mask &= AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC; 598185377Ssam rt = ath_hal_wait(ah, AR_RC, mask, resetMask); 599185377Ssam if ((resetMask & AR_RC_RMAC) == 0) { 600185377Ssam if (isBigEndian()) { 601185377Ssam /* 602234450Sadrian * Set CFG, little-endian for descriptor accesses. 603185377Ssam */ 604234450Sadrian mask = INIT_CONFIG_STATUS | AR_CFG_SWTD | AR_CFG_SWRD; 605234450Sadrian OS_REG_WRITE(ah, AR_CFG, mask); 606185377Ssam } else 607185377Ssam OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); 608185377Ssam } 609185377Ssam return rt; 610185377Ssam} 611185377Ssam 612185377Ssam 613185377Ssam/* 614185377Ssam * Returns: the pcdac value 615185377Ssam */ 616185377Ssamstatic uint8_t 617185380SsamgetPcdac(struct ath_hal *ah, const struct tpcMap *pRD, uint8_t dBm) 618185377Ssam{ 619185377Ssam int32_t i; 620185377Ssam int useNextEntry = AH_FALSE; 621185377Ssam uint32_t interp; 622185377Ssam 623185377Ssam for (i = AR_TP_SCALING_ENTRIES - 1; i >= 0; i--) { 624185377Ssam /* Check for exact entry */ 625185377Ssam if (dBm == AR_I2DBM(i)) { 626185377Ssam if (pRD->pcdac[i] != 63) 627185377Ssam return pRD->pcdac[i]; 628185377Ssam useNextEntry = AH_TRUE; 629185377Ssam } else if (dBm + 1 == AR_I2DBM(i) && i > 0) { 630185377Ssam /* Interpolate for between entry with a logish scale */ 631185377Ssam if (pRD->pcdac[i] != 63 && pRD->pcdac[i-1] != 63) { 632185377Ssam interp = (350 * (pRD->pcdac[i] - pRD->pcdac[i-1])) + 999; 633185377Ssam interp = (interp / 1000) + pRD->pcdac[i-1]; 634185377Ssam return interp; 635185377Ssam } 636185377Ssam useNextEntry = AH_TRUE; 637185377Ssam } else if (useNextEntry == AH_TRUE) { 638185377Ssam /* Grab the next lowest */ 639185377Ssam if (pRD->pcdac[i] != 63) 640185377Ssam return pRD->pcdac[i]; 641185377Ssam } 642185377Ssam } 643185377Ssam 644185377Ssam /* Return the lowest Entry if we haven't returned */ 645185377Ssam for (i = 0; i < AR_TP_SCALING_ENTRIES; i++) 646185377Ssam if (pRD->pcdac[i] != 63) 647185377Ssam return pRD->pcdac[i]; 648185377Ssam 649185377Ssam /* No value to return from table */ 650185377Ssam#ifdef AH_DEBUG 651185377Ssam ath_hal_printf(ah, "%s: empty transmit power table?\n", __func__); 652185377Ssam#endif 653185377Ssam return 1; 654185377Ssam} 655185377Ssam 656185377Ssam/* 657185377Ssam * Find or interpolates the gainF value from the table ptr. 658185377Ssam */ 659185377Ssamstatic uint8_t 660185380SsamgetGainF(struct ath_hal *ah, const struct tpcMap *pRD, 661185380Ssam uint8_t pcdac, uint8_t *dBm) 662185377Ssam{ 663185377Ssam uint32_t interp; 664185377Ssam int low, high, i; 665185377Ssam 666185377Ssam low = high = -1; 667185377Ssam 668185377Ssam for (i = 0; i < AR_TP_SCALING_ENTRIES; i++) { 669185377Ssam if(pRD->pcdac[i] == 63) 670185377Ssam continue; 671185377Ssam if (pcdac == pRD->pcdac[i]) { 672185377Ssam *dBm = AR_I2DBM(i); 673185377Ssam return pRD->gainF[i]; /* Exact Match */ 674185377Ssam } 675185377Ssam if (pcdac > pRD->pcdac[i]) 676185377Ssam low = i; 677185377Ssam if (pcdac < pRD->pcdac[i]) { 678185377Ssam high = i; 679185377Ssam if (low == -1) { 680185377Ssam *dBm = AR_I2DBM(i); 681185377Ssam /* PCDAC is lower than lowest setting */ 682185377Ssam return pRD->gainF[i]; 683185377Ssam } 684185377Ssam break; 685185377Ssam } 686185377Ssam } 687185377Ssam if (i >= AR_TP_SCALING_ENTRIES && low == -1) { 688185377Ssam /* No settings were found */ 689185377Ssam#ifdef AH_DEBUG 690185377Ssam ath_hal_printf(ah, 691185377Ssam "%s: no valid entries in the pcdac table: %d\n", 692185377Ssam __func__, pcdac); 693185377Ssam#endif 694185377Ssam return 63; 695185377Ssam } 696185377Ssam if (i >= AR_TP_SCALING_ENTRIES) { 697185377Ssam /* PCDAC setting was above the max setting in the table */ 698185377Ssam *dBm = AR_I2DBM(low); 699185377Ssam return pRD->gainF[low]; 700185377Ssam } 701185377Ssam /* Only exact if table has no missing entries */ 702185377Ssam *dBm = (low + high) + 3; 703185377Ssam 704185377Ssam /* 705185377Ssam * Perform interpolation between low and high values to find gainF 706185377Ssam * linearly scale the pcdac between low and high 707185377Ssam */ 708185377Ssam interp = ((pcdac - pRD->pcdac[low]) * 1000) / 709185377Ssam (pRD->pcdac[high] - pRD->pcdac[low]); 710185377Ssam /* 711185377Ssam * Multiply the scale ratio by the gainF difference 712185377Ssam * (plus a rnd up factor) 713185377Ssam */ 714185377Ssam interp = ((interp * (pRD->gainF[high] - pRD->gainF[low])) + 999) / 1000; 715185377Ssam 716185377Ssam /* Add ratioed gain_f to low gain_f value */ 717185377Ssam return interp + pRD->gainF[low]; 718185377Ssam} 719185377Ssam 720185377SsamHAL_BOOL 721185377Ssamar5210SetTxPowerLimit(struct ath_hal *ah, uint32_t limit) 722185377Ssam{ 723185380Ssam AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, AR5210_MAX_RATE_POWER); 724185377Ssam /* XXX flush to h/w */ 725185377Ssam return AH_TRUE; 726185377Ssam} 727185377Ssam 728185377Ssam/* 729185377Ssam * Get TXPower values and set them in the radio 730185377Ssam */ 731185377Ssamstatic HAL_BOOL 732187831SsamsetupPowerSettings(struct ath_hal *ah, const struct ieee80211_channel *chan, 733187831Ssam uint8_t cp[17]) 734185377Ssam{ 735187831Ssam uint16_t freq = ath_hal_gethwchannel(ah, chan); 736185380Ssam const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; 737185377Ssam uint8_t gainFRD, gainF36, gainF48, gainF54; 738185377Ssam uint8_t dBmRD, dBm36, dBm48, dBm54, dontcare; 739185377Ssam uint32_t rd, group; 740185380Ssam const struct tpcMap *pRD; 741185377Ssam 742185377Ssam /* Set OB/DB Values regardless of channel */ 743185380Ssam cp[15] = (ee->ee_biasCurrents >> 4) & 0x7; 744185380Ssam cp[16] = ee->ee_biasCurrents & 0x7; 745185377Ssam 746187831Ssam if (freq < 5170 || freq > 5320) { 747185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u\n", 748187831Ssam __func__, freq); 749185377Ssam return AH_FALSE; 750185377Ssam } 751185377Ssam 752185380Ssam HALASSERT(ee->ee_version >= AR_EEPROM_VER1 && 753185380Ssam ee->ee_version < AR_EEPROM_VER3); 754185377Ssam 755185377Ssam /* Match regulatory domain */ 756185377Ssam for (rd = 0; rd < AR_REG_DOMAINS_MAX; rd++) 757185380Ssam if (AH_PRIVATE(ah)->ah_currentRD == ee->ee_regDomain[rd]) 758185377Ssam break; 759185377Ssam if (rd == AR_REG_DOMAINS_MAX) { 760185377Ssam#ifdef AH_DEBUG 761185377Ssam ath_hal_printf(ah, 762185377Ssam "%s: no calibrated regulatory domain matches the " 763185377Ssam "current regularly domain (0x%0x)\n", __func__, 764185377Ssam AH_PRIVATE(ah)->ah_currentRD); 765185377Ssam#endif 766185377Ssam return AH_FALSE; 767185377Ssam } 768187831Ssam group = ((freq - 5170) / 10); 769185377Ssam 770185377Ssam if (group > 11) { 771185377Ssam /* Pull 5.29 into the 5.27 group */ 772185377Ssam group--; 773185377Ssam } 774185377Ssam 775185377Ssam /* Integer divide will set group from 0 to 4 */ 776185377Ssam group = group / 3; 777185380Ssam pRD = &ee->ee_tpc[group]; 778185377Ssam 779185377Ssam /* Set PC DAC Values */ 780185377Ssam cp[14] = pRD->regdmn[rd]; 781185377Ssam cp[9] = AH_MIN(pRD->regdmn[rd], pRD->rate36); 782185377Ssam cp[8] = AH_MIN(pRD->regdmn[rd], pRD->rate48); 783185377Ssam cp[7] = AH_MIN(pRD->regdmn[rd], pRD->rate54); 784185377Ssam 785185377Ssam /* Find Corresponding gainF values for RD, 36, 48, 54 */ 786185377Ssam gainFRD = getGainF(ah, pRD, pRD->regdmn[rd], &dBmRD); 787185377Ssam gainF36 = getGainF(ah, pRD, cp[9], &dBm36); 788185377Ssam gainF48 = getGainF(ah, pRD, cp[8], &dBm48); 789185377Ssam gainF54 = getGainF(ah, pRD, cp[7], &dBm54); 790185377Ssam 791185377Ssam /* Power Scale if requested */ 792185377Ssam if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) { 793185377Ssam static const uint16_t tpcScaleReductionTable[5] = 794185380Ssam { 0, 3, 6, 9, AR5210_MAX_RATE_POWER }; 795185377Ssam uint16_t tpScale; 796185377Ssam 797185377Ssam tpScale = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale]; 798185377Ssam if (dBmRD < tpScale+3) 799185377Ssam dBmRD = 3; /* min */ 800185377Ssam else 801185377Ssam dBmRD -= tpScale; 802185377Ssam cp[14] = getPcdac(ah, pRD, dBmRD); 803185377Ssam gainFRD = getGainF(ah, pRD, cp[14], &dontcare); 804185377Ssam dBm36 = AH_MIN(dBm36, dBmRD); 805185377Ssam cp[9] = getPcdac(ah, pRD, dBm36); 806185377Ssam gainF36 = getGainF(ah, pRD, cp[9], &dontcare); 807185377Ssam dBm48 = AH_MIN(dBm48, dBmRD); 808185377Ssam cp[8] = getPcdac(ah, pRD, dBm48); 809185377Ssam gainF48 = getGainF(ah, pRD, cp[8], &dontcare); 810185377Ssam dBm54 = AH_MIN(dBm54, dBmRD); 811185377Ssam cp[7] = getPcdac(ah, pRD, dBm54); 812185377Ssam gainF54 = getGainF(ah, pRD, cp[7], &dontcare); 813185377Ssam } 814185377Ssam /* Record current dBm at rate 6 */ 815185377Ssam AH_PRIVATE(ah)->ah_maxPowerLevel = 2*dBmRD; 816185377Ssam 817185377Ssam cp[13] = cp[12] = cp[11] = cp[10] = cp[14]; 818185377Ssam 819185377Ssam /* Set GainF Values */ 820185377Ssam cp[0] = gainFRD - gainF54; 821185377Ssam cp[1] = gainFRD - gainF48; 822185377Ssam cp[2] = gainFRD - gainF36; 823185377Ssam /* 9, 12, 18, 24 have no gain_delta from 6 */ 824185377Ssam cp[3] = cp[4] = cp[5] = cp[6] = 0; 825185377Ssam return AH_TRUE; 826185377Ssam} 827185377Ssam 828185377Ssam/* 829185377Ssam * Places the device in and out of reset and then places sane 830185377Ssam * values in the registers based on EEPROM config, initialization 831185377Ssam * vectors (as determined by the mode), and station configuration 832185377Ssam */ 833185377SsamHAL_BOOL 834187831Ssamar5210SetTransmitPower(struct ath_hal *ah, const struct ieee80211_channel *chan) 835185377Ssam{ 836185377Ssam#define N(a) (sizeof (a) / sizeof (a[0])) 837185377Ssam static const uint32_t pwr_regs_start[17] = { 838185377Ssam 0x00000000, 0x00000000, 0x00000000, 839185377Ssam 0x00000000, 0x00000000, 0xf0000000, 840185377Ssam 0xcc000000, 0x00000000, 0x00000000, 841185377Ssam 0x00000000, 0x0a000000, 0x000000e2, 842185377Ssam 0x0a000020, 0x01000002, 0x01000018, 843185377Ssam 0x40000000, 0x00000418 844185377Ssam }; 845185377Ssam uint16_t i; 846185377Ssam uint8_t cp[sizeof(ar5k0007_pwrSettings)]; 847185377Ssam uint32_t pwr_regs[17]; 848185377Ssam 849185377Ssam OS_MEMCPY(pwr_regs, pwr_regs_start, sizeof(pwr_regs)); 850185377Ssam OS_MEMCPY(cp, ar5k0007_pwrSettings, sizeof(cp)); 851185377Ssam 852185377Ssam /* Check the EEPROM tx power calibration settings */ 853185377Ssam if (!setupPowerSettings(ah, chan, cp)) { 854185377Ssam#ifdef AH_DEBUG 855185377Ssam ath_hal_printf(ah, "%s: unable to setup power settings\n", 856185377Ssam __func__); 857185377Ssam#endif 858185377Ssam return AH_FALSE; 859185377Ssam } 860185377Ssam if (cp[15] < 1 || cp[15] > 5) { 861185377Ssam#ifdef AH_DEBUG 862185377Ssam ath_hal_printf(ah, "%s: OB out of range (%u)\n", 863185377Ssam __func__, cp[15]); 864185377Ssam#endif 865185377Ssam return AH_FALSE; 866185377Ssam } 867185377Ssam if (cp[16] < 1 || cp[16] > 5) { 868185377Ssam#ifdef AH_DEBUG 869185377Ssam ath_hal_printf(ah, "%s: DB out of range (%u)\n", 870185377Ssam __func__, cp[16]); 871185377Ssam#endif 872185377Ssam return AH_FALSE; 873185377Ssam } 874185377Ssam 875185377Ssam /* reverse bits of the transmit power array */ 876185377Ssam for (i = 0; i < 7; i++) 877185377Ssam cp[i] = ath_hal_reverseBits(cp[i], 5); 878185377Ssam for (i = 7; i < 15; i++) 879185377Ssam cp[i] = ath_hal_reverseBits(cp[i], 6); 880185377Ssam 881185380Ssam /* merge transmit power values into the register - quite gross */ 882185377Ssam pwr_regs[0] |= ((cp[1] << 5) & 0xE0) | (cp[0] & 0x1F); 883185377Ssam pwr_regs[1] |= ((cp[3] << 7) & 0x80) | ((cp[2] << 2) & 0x7C) | 884185377Ssam ((cp[1] >> 3) & 0x03); 885185377Ssam pwr_regs[2] |= ((cp[4] << 4) & 0xF0) | ((cp[3] >> 1) & 0x0F); 886185377Ssam pwr_regs[3] |= ((cp[6] << 6) & 0xC0) | ((cp[5] << 1) & 0x3E) | 887185377Ssam ((cp[4] >> 4) & 0x01); 888185377Ssam pwr_regs[4] |= ((cp[7] << 3) & 0xF8) | ((cp[6] >> 2) & 0x07); 889185377Ssam pwr_regs[5] |= ((cp[9] << 7) & 0x80) | ((cp[8] << 1) & 0x7E) | 890185377Ssam ((cp[7] >> 5) & 0x01); 891185377Ssam pwr_regs[6] |= ((cp[10] << 5) & 0xE0) | ((cp[9] >> 1) & 0x1F); 892185377Ssam pwr_regs[7] |= ((cp[11] << 3) & 0xF8) | ((cp[10] >> 3) & 0x07); 893185377Ssam pwr_regs[8] |= ((cp[12] << 1) & 0x7E) | ((cp[11] >> 5) & 0x01); 894185377Ssam pwr_regs[9] |= ((cp[13] << 5) & 0xE0); 895185377Ssam pwr_regs[10] |= ((cp[14] << 3) & 0xF8) | ((cp[13] >> 3) & 0x07); 896185377Ssam pwr_regs[11] |= ((cp[14] >> 5) & 0x01); 897185377Ssam 898185377Ssam /* Set OB */ 899185377Ssam pwr_regs[8] |= (ath_hal_reverseBits(cp[15], 3) << 7) & 0x80; 900185377Ssam pwr_regs[9] |= (ath_hal_reverseBits(cp[15], 3) >> 1) & 0x03; 901185377Ssam 902185377Ssam /* Set DB */ 903185377Ssam pwr_regs[9] |= (ath_hal_reverseBits(cp[16], 3) << 2) & 0x1C; 904185377Ssam 905185377Ssam /* Write the registers */ 906185377Ssam for (i = 0; i < N(pwr_regs)-1; i++) 907185377Ssam OS_REG_WRITE(ah, 0x0000989c, pwr_regs[i]); 908185377Ssam /* last write is a flush */ 909185377Ssam OS_REG_WRITE(ah, 0x000098d4, pwr_regs[i]); 910185377Ssam 911185377Ssam return AH_TRUE; 912185377Ssam#undef N 913185377Ssam} 914185377Ssam 915185377Ssam/* 916185377Ssam * Takes the MHz channel value and sets the Channel value 917185377Ssam * 918185377Ssam * ASSUMES: Writes enabled to analog bus before AGC is active 919185377Ssam * or by disabling the AGC. 920185377Ssam */ 921185377Ssamstatic HAL_BOOL 922187831Ssamar5210SetChannel(struct ath_hal *ah, struct ieee80211_channel *chan) 923185377Ssam{ 924187831Ssam uint16_t freq = ath_hal_gethwchannel(ah, chan); 925185377Ssam uint32_t data; 926185377Ssam 927185377Ssam /* Set the Channel */ 928187831Ssam data = ath_hal_reverseBits((freq - 5120)/10, 5); 929185377Ssam data = (data << 1) | 0x41; 930185377Ssam OS_REG_WRITE(ah, AR_PHY(0x27), data); 931185377Ssam OS_REG_WRITE(ah, AR_PHY(0x30), 0); 932185377Ssam AH_PRIVATE(ah)->ah_curchan = chan; 933185377Ssam return AH_TRUE; 934185377Ssam} 935185377Ssam 936185377Ssamint16_t 937185377Ssamar5210GetNoiseFloor(struct ath_hal *ah) 938185377Ssam{ 939185377Ssam int16_t nf; 940185377Ssam 941185377Ssam nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; 942185377Ssam if (nf & 0x100) 943185377Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 944185377Ssam return nf; 945185377Ssam} 946185377Ssam 947185377Ssam#define NORMAL_NF_THRESH (-72) 948185377Ssam/* 949185377Ssam * Peform the noisefloor calibration and check for 950185377Ssam * any constant channel interference 951185377Ssam * 952185377Ssam * Returns: TRUE for a successful noise floor calibration; else FALSE 953185377Ssam */ 954185377SsamHAL_BOOL 955187831Ssamar5210CalNoiseFloor(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 956185377Ssam{ 957185377Ssam int32_t nf, nfLoops; 958185377Ssam 959185377Ssam /* Calibrate the noise floor */ 960185377Ssam OS_REG_WRITE(ah, AR_PHY_AGCCTL, 961185377Ssam OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_NF); 962185377Ssam 963185377Ssam /* Do not read noise floor until it has done the first update */ 964185377Ssam if (!ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_NF, 0)) { 965185377Ssam#ifdef ATH_HAL_DEBUG 966185377Ssam ath_hal_printf(ah, " -PHY NF Reg state: 0x%x\n", 967185377Ssam OS_REG_READ(ah, AR_PHY_AGCCTL)); 968185377Ssam ath_hal_printf(ah, " -MAC Reset Reg state: 0x%x\n", 969185377Ssam OS_REG_READ(ah, AR_RC)); 970185377Ssam ath_hal_printf(ah, " -PHY Active Reg state: 0x%x\n", 971185377Ssam OS_REG_READ(ah, AR_PHY_ACTIVE)); 972185377Ssam#endif /* ATH_HAL_DEBUG */ 973185377Ssam return AH_FALSE; 974185377Ssam } 975185377Ssam 976185377Ssam nf = 0; 977185377Ssam /* Keep checking until the floor is below the threshold or the nf is done */ 978185377Ssam for (nfLoops = 0; ((nfLoops < 21) && (nf > NORMAL_NF_THRESH)); nfLoops++) { 979185377Ssam OS_DELAY(1000); /* Sleep for 1 ms */ 980185377Ssam nf = ar5210GetNoiseFloor(ah); 981185377Ssam } 982185377Ssam 983185377Ssam if (nf > NORMAL_NF_THRESH) { 984185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Bad noise cal %d\n", 985185377Ssam __func__, nf); 986187831Ssam ichan->rawNoiseFloor = 0; 987185377Ssam return AH_FALSE; 988185377Ssam } 989187831Ssam ichan->rawNoiseFloor = nf; 990185377Ssam return AH_TRUE; 991185377Ssam} 992185377Ssam 993185377Ssam/* 994185377Ssam * Adjust NF based on statistical values for 5GHz frequencies. 995185377Ssam */ 996185377Ssamint16_t 997185377Ssamar5210GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 998185377Ssam{ 999185377Ssam return 0; 1000185377Ssam} 1001185377Ssam 1002185377SsamHAL_RFGAIN 1003185377Ssamar5210GetRfgain(struct ath_hal *ah) 1004185377Ssam{ 1005185377Ssam return HAL_RFGAIN_INACTIVE; 1006185377Ssam} 1007