ar9300_reset.c revision 280829
1250003Sadrian/* 2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc. 3250003Sadrian * 4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any 5250003Sadrian * purpose with or without fee is hereby granted, provided that the above 6250003Sadrian * copyright notice and this permission notice appear in all copies. 7250003Sadrian * 8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14250003Sadrian * PERFORMANCE OF THIS SOFTWARE. 15250003Sadrian */ 16250003Sadrian 17250003Sadrian 18250003Sadrian 19250003Sadrian#include "opt_ah.h" 20250003Sadrian 21250003Sadrian#include "ah.h" 22250003Sadrian#include "ah_internal.h" 23250003Sadrian#include "ah_devid.h" 24250003Sadrian#include "ah_desc.h" 25250003Sadrian 26250003Sadrian#include "ar9300.h" 27250003Sadrian#include "ar9300reg.h" 28250003Sadrian#include "ar9300phy.h" 29250003Sadrian#include "ar9300desc.h" 30250003Sadrian 31250003Sadrian#define FIX_NOISE_FLOOR 1 32250003Sadrian 33250003Sadrian 34250003Sadrian/* Additional Time delay to wait after activiting the Base band */ 35250003Sadrian#define BASE_ACTIVATE_DELAY 100 /* usec */ 36250003Sadrian#define RTC_PLL_SETTLE_DELAY 100 /* usec */ 37250003Sadrian#define COEF_SCALE_S 24 38250003Sadrian#define HT40_CHANNEL_CENTER_SHIFT 10 /* MHz */ 39250003Sadrian 40250003Sadrian#define DELPT 32 41250003Sadrian 42250008Sadrian/* XXX Duplicates! (in ar9300desc.h) */ 43250008Sadrian#if 0 44250003Sadrianextern HAL_BOOL ar9300_reset_tx_queue(struct ath_hal *ah, u_int q); 45250003Sadrianextern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q); 46250008Sadrian#endif 47250003Sadrian 48250003Sadrian 49250003Sadrian#define MAX_MEASUREMENT 8 50250003Sadrian#define MAXIQCAL 3 51250003Sadrianstruct coeff_t { 52250003Sadrian int32_t mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; 53250003Sadrian int32_t phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; 54250003Sadrian int32_t iqc_coeff[2]; 55250003Sadrian int last_nmeasurement; 56250003Sadrian HAL_BOOL last_cal; 57250003Sadrian}; 58250003Sadrian 59250003Sadrianstatic HAL_BOOL ar9300_tx_iq_cal_hw_run(struct ath_hal *ah); 60250003Sadrianstatic void ar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, 61250003Sadrian int iqcal_idx, int max_iqcal, HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr); 62250003Sadrianstatic void ar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, 63250003Sadrian u_int32_t num_chains, struct coeff_t *coeff, HAL_BOOL is_cal_reusable); 64250003Sadrian#if ATH_SUPPORT_CAL_REUSE 65250003Sadrianstatic void ar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan); 66250003Sadrian#endif 67250003Sadrian 68250003Sadrian 69250003Sadrianstatic inline void ar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, int column); 70250008Sadrianstatic inline void ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan); 71250008Sadrianstatic inline HAL_BOOL ar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_corr); 72250003Sadrianstatic inline void ar9300_init_user_settings(struct ath_hal *ah); 73250003Sadrian 74250003Sadrian#ifdef HOST_OFFLOAD 75250003Sadrian/* 76250003Sadrian * For usb offload solution, some USB registers must be tuned 77250003Sadrian * to gain better stability/performance but these registers 78250003Sadrian * might be changed while doing wlan reset so do this here 79250003Sadrian */ 80250003Sadrian#define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah) \ 81250003Sadriando { \ 82250003Sadrian if (AR_SREV_HORNET(__ah) || AR_SREV_WASP(__ah)) { \ 83250003Sadrian volatile u_int32_t *usb_ctrl_r1 = (u_int32_t *) 0xb8116c84; \ 84250003Sadrian volatile u_int32_t *usb_ctrl_r2 = (u_int32_t *) 0xb8116c88; \ 85250003Sadrian *usb_ctrl_r1 = (*usb_ctrl_r1 & 0xffefffff); \ 86250003Sadrian *usb_ctrl_r2 = (*usb_ctrl_r2 & 0xfc1fffff) | (1 << 21) | (3 << 22); \ 87250003Sadrian } \ 88250003Sadrian} while (0) 89250003Sadrian#else 90250003Sadrian#define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah) 91250003Sadrian#endif 92250003Sadrian 93250003Sadrianstatic inline void 94250003Sadrianar9300_attach_hw_platform(struct ath_hal *ah) 95250003Sadrian{ 96250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 97250003Sadrian 98250003Sadrian ahp->ah_hwp = HAL_TRUE_CHIP; 99250003Sadrian return; 100250003Sadrian} 101250003Sadrian 102250003Sadrian/* Adjust various register settings based on half/quarter rate clock setting. 103250003Sadrian * This includes: +USEC, TX/RX latency, 104250003Sadrian * + IFS params: slot, eifs, misc etc. 105250003Sadrian * SIFS stays the same. 106250003Sadrian */ 107250003Sadrianstatic void 108250008Sadrianar9300_set_ifs_timing(struct ath_hal *ah, struct ieee80211_channel *chan) 109250003Sadrian{ 110250003Sadrian u_int32_t tx_lat, rx_lat, usec, slot, regval, eifs; 111250003Sadrian 112250003Sadrian regval = OS_REG_READ(ah, AR_USEC); 113250003Sadrian regval &= ~(AR_USEC_RX_LATENCY | AR_USEC_TX_LATENCY | AR_USEC_USEC); 114250008Sadrian if (IEEE80211_IS_CHAN_HALF(chan)) { /* half rates */ 115250003Sadrian slot = ar9300_mac_to_clks(ah, AR_SLOT_HALF); 116250003Sadrian eifs = ar9300_mac_to_clks(ah, AR_EIFS_HALF); 117250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */ 118250003Sadrian rx_lat = SM(AR_RX_LATENCY_HALF_FAST_CLOCK, AR_USEC_RX_LATENCY); 119250003Sadrian tx_lat = SM(AR_TX_LATENCY_HALF_FAST_CLOCK, AR_USEC_TX_LATENCY); 120250003Sadrian usec = SM(AR_USEC_HALF_FAST_CLOCK, AR_USEC_USEC); 121250003Sadrian } else { 122250003Sadrian rx_lat = SM(AR_RX_LATENCY_HALF, AR_USEC_RX_LATENCY); 123250003Sadrian tx_lat = SM(AR_TX_LATENCY_HALF, AR_USEC_TX_LATENCY); 124250003Sadrian usec = SM(AR_USEC_HALF, AR_USEC_USEC); 125250003Sadrian } 126250003Sadrian } else { /* quarter rate */ 127250003Sadrian slot = ar9300_mac_to_clks(ah, AR_SLOT_QUARTER); 128250003Sadrian eifs = ar9300_mac_to_clks(ah, AR_EIFS_QUARTER); 129250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */ 130250003Sadrian rx_lat = SM(AR_RX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_RX_LATENCY); 131250003Sadrian tx_lat = SM(AR_TX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_TX_LATENCY); 132250003Sadrian usec = SM(AR_USEC_QUARTER_FAST_CLOCK, AR_USEC_USEC); 133250003Sadrian } else { 134250003Sadrian rx_lat = SM(AR_RX_LATENCY_QUARTER, AR_USEC_RX_LATENCY); 135250003Sadrian tx_lat = SM(AR_TX_LATENCY_QUARTER, AR_USEC_TX_LATENCY); 136250003Sadrian usec = SM(AR_USEC_QUARTER, AR_USEC_USEC); 137250003Sadrian } 138250003Sadrian } 139250003Sadrian 140250003Sadrian OS_REG_WRITE(ah, AR_USEC, (usec | regval | tx_lat | rx_lat)); 141250003Sadrian OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 142250003Sadrian OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 143250003Sadrian} 144250003Sadrian 145250003Sadrian 146250003Sadrian/* 147250003Sadrian * This inline function configures the chip either 148250003Sadrian * to encrypt/decrypt management frames or pass thru 149250003Sadrian */ 150250003Sadrianstatic inline void 151250003Sadrianar9300_init_mfp(struct ath_hal * ah) 152250003Sadrian{ 153250003Sadrian u_int32_t mfpcap, mfp_qos; 154250003Sadrian 155250003Sadrian ath_hal_getcapability(ah, HAL_CAP_MFP, 0, &mfpcap); 156250003Sadrian 157250003Sadrian if (mfpcap == HAL_MFP_QOSDATA) { 158250003Sadrian /* Treat like legacy hardware. Do not touch the MFP registers. */ 159250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s forced to use QOSDATA\n", __func__); 160250003Sadrian return; 161250003Sadrian } 162250003Sadrian 163250003Sadrian /* MFP support (Sowl 1.0 or greater) */ 164250003Sadrian if (mfpcap == HAL_MFP_HW_CRYPTO) { 165250003Sadrian /* configure hardware MFP support */ 166250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s using HW crypto\n", __func__); 167250003Sadrian OS_REG_RMW_FIELD(ah, 168250003Sadrian AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, AR_AES_MUTE_MASK1_FC_MGMT_MFP); 169250003Sadrian OS_REG_RMW(ah, 170250003Sadrian AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE, 171250003Sadrian AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); 172250003Sadrian /* 173250003Sadrian * Mask used to construct AAD for CCMP-AES 174250003Sadrian * Cisco spec defined bits 0-3 as mask 175250003Sadrian * IEEE802.11w defined as bit 4. 176250003Sadrian */ 177250003Sadrian if (ath_hal_get_mfp_qos(ah)) { 178250003Sadrian mfp_qos = AR_MFP_QOS_MASK_IEEE; 179250003Sadrian } else { 180250003Sadrian mfp_qos = AR_MFP_QOS_MASK_CISCO; 181250003Sadrian } 182250003Sadrian OS_REG_RMW_FIELD(ah, 183250003Sadrian AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_QOS, mfp_qos); 184250003Sadrian } else if (mfpcap == HAL_MFP_PASSTHRU) { 185250003Sadrian /* Disable en/decrypt by hardware */ 186250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s using passthru\n", __func__); 187250003Sadrian OS_REG_RMW(ah, 188250003Sadrian AR_PCU_MISC_MODE2, 189250003Sadrian AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT, 190250003Sadrian AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); 191250003Sadrian } 192250003Sadrian} 193250003Sadrian 194250003Sadrianvoid 195250008Sadrianar9300_get_channel_centers(struct ath_hal *ah, const struct ieee80211_channel *chan, 196250003Sadrian CHAN_CENTERS *centers) 197250003Sadrian{ 198250003Sadrian int8_t extoff; 199250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 200250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 201250003Sadrian 202250008Sadrian if (!IEEE80211_IS_CHAN_HT40(chan)) { 203250003Sadrian centers->ctl_center = centers->ext_center = 204250008Sadrian centers->synth_center = ichan->channel; 205250003Sadrian return; 206250003Sadrian } 207250003Sadrian 208250008Sadrian HALASSERT(IEEE80211_IS_CHAN_HT40(chan)); 209250003Sadrian 210250003Sadrian /* 211250003Sadrian * In 20/40 phy mode, the center frequency is 212250003Sadrian * "between" the primary and extension channels. 213250003Sadrian */ 214250008Sadrian if (IEEE80211_IS_CHAN_HT40U(chan)) { 215250008Sadrian centers->synth_center = ichan->channel + HT40_CHANNEL_CENTER_SHIFT; 216250003Sadrian extoff = 1; 217250003Sadrian } else { 218250008Sadrian centers->synth_center = ichan->channel - HT40_CHANNEL_CENTER_SHIFT; 219250003Sadrian extoff = -1; 220250003Sadrian } 221250003Sadrian 222250003Sadrian centers->ctl_center = 223250003Sadrian centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); 224250003Sadrian centers->ext_center = 225250003Sadrian centers->synth_center + 226250003Sadrian (extoff * ((ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_20) ? 227250003Sadrian HT40_CHANNEL_CENTER_SHIFT : 15)); 228250003Sadrian} 229250003Sadrian 230250003Sadrian/* 231250003Sadrian * Read the noise-floor values from the HW. 232250003Sadrian * Specifically, read the minimum clear-channel assessment value for 233250003Sadrian * each chain, for both the control and extension channels. 234250003Sadrian * (The received power level during clear-channel periods is the 235250003Sadrian * noise floor.) 236250003Sadrian * These noise floor values computed by the HW will be stored in the 237250003Sadrian * NF history buffer. 238250003Sadrian * The HW sometimes produces bogus NF values. To avoid using these 239250003Sadrian * bogus values, the NF data is (a) range-limited, and (b) filtered. 240250003Sadrian * However, this data-processing is done when reading the NF values 241250003Sadrian * out of the history buffer. The history buffer stores the raw values. 242250003Sadrian * This allows the NF history buffer to be used to check for interference. 243250003Sadrian * A single high NF reading might be a bogus HW value, but if the NF 244250003Sadrian * readings are consistently high, it must be due to interference. 245250003Sadrian * This is the purpose of storing raw NF values in the history buffer, 246250003Sadrian * rather than processed values. By looking at a history of NF values 247250003Sadrian * that have not been range-limited, we can check if they are consistently 248250003Sadrian * high (due to interference). 249250003Sadrian */ 250250003Sadrian#define AH_NF_SIGN_EXTEND(nf) \ 251250003Sadrian ((nf) & 0x100) ? \ 252250003Sadrian 0 - (((nf) ^ 0x1ff) + 1) : \ 253250003Sadrian (nf) 254250003Sadrianvoid 255250003Sadrianar9300_upload_noise_floor(struct ath_hal *ah, int is_2g, 256250008Sadrian int16_t nfarray[HAL_NUM_NF_READINGS]) 257250003Sadrian{ 258250003Sadrian int16_t nf; 259250003Sadrian int chan, chain; 260250008Sadrian u_int32_t regs[HAL_NUM_NF_READINGS] = { 261250003Sadrian /* control channel */ 262250003Sadrian AR_PHY_CCA_0, /* chain 0 */ 263250003Sadrian AR_PHY_CCA_1, /* chain 1 */ 264250003Sadrian AR_PHY_CCA_2, /* chain 2 */ 265250003Sadrian /* extension channel */ 266250003Sadrian AR_PHY_EXT_CCA, /* chain 0 */ 267250003Sadrian AR_PHY_EXT_CCA_1, /* chain 1 */ 268250003Sadrian AR_PHY_EXT_CCA_2, /* chain 2 */ 269250003Sadrian }; 270250003Sadrian u_int8_t chainmask; 271250003Sadrian 272250003Sadrian /* 273250003Sadrian * Within a given channel (ctl vs. ext), the CH0, CH1, and CH2 274250003Sadrian * masks and shifts are the same, though they differ for the 275250003Sadrian * control vs. extension channels. 276250003Sadrian */ 277250003Sadrian u_int32_t masks[2] = { 278250003Sadrian AR_PHY_MINCCA_PWR, /* control channel */ 279250003Sadrian AR_PHY_EXT_MINCCA_PWR, /* extention channel */ 280250003Sadrian }; 281250003Sadrian u_int8_t shifts[2] = { 282250003Sadrian AR_PHY_MINCCA_PWR_S, /* control channel */ 283250003Sadrian AR_PHY_EXT_MINCCA_PWR_S, /* extention channel */ 284250003Sadrian }; 285250003Sadrian 286250003Sadrian /* 287250003Sadrian * Force NF calibration for all chains. 288250003Sadrian */ 289250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 290250003Sadrian chainmask = 0x01; 291250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { 292250003Sadrian chainmask = 0x03; 293250003Sadrian } else { 294250003Sadrian chainmask = 0x07; 295250003Sadrian } 296250003Sadrian 297250003Sadrian for (chan = 0; chan < 2 /*ctl,ext*/; chan++) { 298250003Sadrian for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { 299250003Sadrian int i; 300250003Sadrian 301250003Sadrian if (!((chainmask >> chain) & 0x1)) { 302250003Sadrian continue; 303250003Sadrian } 304250003Sadrian i = chan * AR9300_MAX_CHAINS + chain; 305250003Sadrian nf = (OS_REG_READ(ah, regs[i]) & masks[chan]) >> shifts[chan]; 306250003Sadrian nfarray[i] = AH_NF_SIGN_EXTEND(nf); 307250003Sadrian } 308250003Sadrian } 309250003Sadrian} 310250003Sadrian 311250003Sadrian/* ar9300_get_min_cca_pwr - 312250003Sadrian * Used by the scan function for a quick read of the noise floor. 313250003Sadrian * This is used to detect presence of CW interference such as video bridge. 314250003Sadrian * The noise floor is assumed to have been already started during reset 315250003Sadrian * called during channel change. The function checks if the noise floor 316250003Sadrian * reading is done. In case it has been done, it reads the noise floor value. 317250003Sadrian * If the noise floor calibration has not been finished, it assumes this is 318250003Sadrian * due to presence of CW interference an returns a high value for noise floor, 319250003Sadrian * derived from the CW interference threshold + margin fudge factor. 320250003Sadrian */ 321250003Sadrian#define BAD_SCAN_NF_MARGIN (30) 322250003Sadrianint16_t ar9300_get_min_cca_pwr(struct ath_hal *ah) 323250003Sadrian{ 324250003Sadrian int16_t nf; 325250008Sadrian// struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 326250003Sadrian 327278741Sadrian 328250003Sadrian if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) { 329250003Sadrian nf = MS(OS_REG_READ(ah, AR_PHY_CCA_0), AR9280_PHY_MINCCA_PWR); 330250003Sadrian if (nf & 0x100) { 331250003Sadrian nf = 0 - ((nf ^ 0x1ff) + 1); 332250003Sadrian } 333250003Sadrian } else { 334250003Sadrian /* NF calibration is not done, assume CW interference */ 335250008Sadrian nf = AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta + 336250008Sadrian BAD_SCAN_NF_MARGIN; 337250003Sadrian } 338250003Sadrian return nf; 339250003Sadrian} 340250003Sadrian 341250003Sadrian 342250003Sadrian/* 343250003Sadrian * Noise Floor values for all chains. 344250003Sadrian * Most recently updated values from the NF history buffer are used. 345250003Sadrian */ 346250003Sadrianvoid ar9300_chain_noise_floor(struct ath_hal *ah, int16_t *nf_buf, 347250008Sadrian struct ieee80211_channel *chan, int is_scan) 348250003Sadrian{ 349250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 350250003Sadrian int i, nf_hist_len, recent_nf_index = 0; 351250003Sadrian HAL_NFCAL_HIST_FULL *h; 352250003Sadrian u_int8_t rx_chainmask = ahp->ah_rx_chainmask | (ahp->ah_rx_chainmask << 3); 353250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 354250003Sadrian HALASSERT(ichan); 355250003Sadrian 356250003Sadrian#ifdef ATH_NF_PER_CHAN 357250003Sadrian /* Fill 0 if valid internal channel is not found */ 358250003Sadrian if (ichan == AH_NULL) { 359250008Sadrian OS_MEMZERO(nf_buf, sizeof(nf_buf[0])*HAL_NUM_NF_READINGS); 360250003Sadrian return; 361250003Sadrian } 362250003Sadrian h = &ichan->nf_cal_hist; 363250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 364250003Sadrian#else 365250003Sadrian /* 366250003Sadrian * If a scan is not in progress, then the most recent value goes 367250003Sadrian * into ahpriv->nf_cal_hist. If a scan is in progress, then 368250003Sadrian * the most recent value goes into ichan->nf_cal_hist. 369250003Sadrian * Thus, return the value from ahpriv->nf_cal_hist if there's 370250003Sadrian * no scan, and if the specified channel is the current channel. 371250003Sadrian * Otherwise, return the noise floor from ichan->nf_cal_hist. 372250003Sadrian */ 373250008Sadrian if ((!is_scan) && chan == AH_PRIVATE(ah)->ah_curchan) { 374250003Sadrian h = &AH_PRIVATE(ah)->nf_cal_hist; 375250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 376250003Sadrian } else { 377250003Sadrian /* Fill 0 if valid internal channel is not found */ 378250003Sadrian if (ichan == AH_NULL) { 379250008Sadrian OS_MEMZERO(nf_buf, sizeof(nf_buf[0])*HAL_NUM_NF_READINGS); 380250003Sadrian return; 381250003Sadrian } 382250003Sadrian /* 383250003Sadrian * It is okay to treat a HAL_NFCAL_HIST_SMALL struct as if it were a 384250003Sadrian * HAL_NFCAL_HIST_FULL struct, as long as only the index 0 of the 385250008Sadrian * nf_cal_buffer is used (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]) 386250003Sadrian */ 387250003Sadrian h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 388250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; 389250003Sadrian } 390250003Sadrian#endif 391250003Sadrian /* Get most recently updated values from nf cal history buffer */ 392250003Sadrian recent_nf_index = 393250003Sadrian (h->base.curr_index) ? h->base.curr_index - 1 : nf_hist_len - 1; 394250003Sadrian 395250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 396250003Sadrian /* Fill 0 for unsupported chains */ 397250003Sadrian if (!(rx_chainmask & (1 << i))) { 398250003Sadrian nf_buf[i] = 0; 399250003Sadrian continue; 400250003Sadrian } 401250003Sadrian nf_buf[i] = h->nf_cal_buffer[recent_nf_index][i]; 402250003Sadrian } 403250003Sadrian} 404250003Sadrian 405278741Sadrian/* 406278741Sadrian * Return the current NF value in register. 407278741Sadrian * If the current NF cal is not completed, return 0. 408278741Sadrian */ 409278741Sadrianint16_t ar9300_get_nf_from_reg(struct ath_hal *ah, struct ieee80211_channel *chan, int wait_time) 410278741Sadrian{ 411278741Sadrian int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; 412278741Sadrian int is_2g = 0; 413278741Sadrian HAL_CHANNEL_INTERNAL *ichan = NULL; 414250003Sadrian 415278741Sadrian ichan = ath_hal_checkchannel(ah, chan); 416278741Sadrian if (ichan == NULL) 417278741Sadrian return (0); 418278741Sadrian 419278741Sadrian if (wait_time <= 0) { 420278741Sadrian return 0; 421278741Sadrian } 422278741Sadrian 423278741Sadrian if (!ath_hal_waitfor(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF, 0, wait_time)) { 424278741Sadrian ath_hal_printf(ah, "%s: NF cal is not complete in %dus", __func__, wait_time); 425278741Sadrian return 0; 426278741Sadrian } 427278741Sadrian is_2g = !! (IS_CHAN_2GHZ(ichan)); 428278741Sadrian ar9300_upload_noise_floor(ah, is_2g, nfarray); 429278741Sadrian 430278741Sadrian return nfarray[0]; 431278741Sadrian} 432278741Sadrian 433250003Sadrian/* 434250003Sadrian * Pick up the medium one in the noise floor buffer and update the 435250003Sadrian * corresponding range for valid noise floor values 436250003Sadrian */ 437250003Sadrianstatic int16_t 438250003Sadrianar9300_get_nf_hist_mid(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, int reading, 439250003Sadrian int hist_len) 440250003Sadrian{ 441250003Sadrian int16_t nfval; 442250003Sadrian int16_t sort[HAL_NF_CAL_HIST_LEN_FULL]; /* upper bound for hist_len */ 443250003Sadrian int i, j; 444250003Sadrian 445278741Sadrian 446250003Sadrian for (i = 0; i < hist_len; i++) { 447250003Sadrian sort[i] = h->nf_cal_buffer[i][reading]; 448250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 449250003Sadrian "nf_cal_buffer[%d][%d] = %d\n", i, reading, (int)sort[i]); 450250003Sadrian } 451250003Sadrian for (i = 0; i < hist_len - 1; i++) { 452250003Sadrian for (j = 1; j < hist_len - i; j++) { 453250003Sadrian if (sort[j] > sort[j - 1]) { 454250003Sadrian nfval = sort[j]; 455250003Sadrian sort[j] = sort[j - 1]; 456250003Sadrian sort[j - 1] = nfval; 457250003Sadrian } 458250003Sadrian } 459250003Sadrian } 460250003Sadrian nfval = sort[(hist_len - 1) >> 1]; 461250003Sadrian 462250003Sadrian return nfval; 463250003Sadrian} 464250003Sadrian 465250003Sadrianstatic int16_t ar9300_limit_nf_range(struct ath_hal *ah, int16_t nf) 466250003Sadrian{ 467250008Sadrian if (nf < AH9300(ah)->nfp->min) { 468250008Sadrian return AH9300(ah)->nfp->nominal; 469250008Sadrian } else if (nf > AH9300(ah)->nfp->max) { 470250008Sadrian return AH9300(ah)->nfp->max; 471250003Sadrian } 472250003Sadrian return nf; 473250003Sadrian} 474250003Sadrian 475250003Sadrian#ifndef ATH_NF_PER_CHAN 476250003Sadrianinline static void 477250003Sadrianar9300_reset_nf_hist_buff(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 478250003Sadrian{ 479250003Sadrian HAL_CHAN_NFCAL_HIST *h = &ichan->nf_cal_hist; 480250003Sadrian HAL_NFCAL_HIST_FULL *home = &AH_PRIVATE(ah)->nf_cal_hist; 481250003Sadrian int i; 482278741Sadrian 483250003Sadrian /* 484250003Sadrian * Copy the value for the channel in question into the home-channel 485250003Sadrian * NF history buffer. The channel NF is probably a value filled in by 486250003Sadrian * a prior background channel scan, but if no scan has been done then 487250003Sadrian * it is the nominal noise floor filled in by ath_hal_init_NF_buffer 488250003Sadrian * for this chip and the channel's band. 489250003Sadrian * Replicate this channel NF into all entries of the home-channel NF 490250003Sadrian * history buffer. 491250003Sadrian * If the channel NF was filled in by a channel scan, it has not had 492250003Sadrian * bounds limits applied to it yet - do so now. It is important to 493250003Sadrian * apply bounds limits to the priv_nf value that gets loaded into the 494250003Sadrian * WLAN chip's min_cca_pwr register field. It is also necessary to 495250003Sadrian * apply bounds limits to the nf_cal_buffer[] elements. Since we are 496250003Sadrian * replicating a single NF reading into all nf_cal_buffer elements, 497250003Sadrian * if the single reading were above the CW_INT threshold, the CW_INT 498250003Sadrian * check in ar9300_get_nf would immediately conclude that CW interference 499250003Sadrian * is present, even though we're not supposed to set CW_INT unless 500250003Sadrian * NF values are _consistently_ above the CW_INT threshold. 501250003Sadrian * Applying the bounds limits to the nf_cal_buffer contents fixes this 502250003Sadrian * problem. 503250003Sadrian */ 504250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i ++) { 505250003Sadrian int j; 506250003Sadrian int16_t nf; 507250003Sadrian /* 508250003Sadrian * No need to set curr_index, since it already has a value in 509250003Sadrian * the range [0..HAL_NF_CAL_HIST_LEN_FULL), and all nf_cal_buffer 510250003Sadrian * values will be the same. 511250003Sadrian */ 512250003Sadrian nf = ar9300_limit_nf_range(ah, h->nf_cal_buffer[0][i]); 513250003Sadrian for (j = 0; j < HAL_NF_CAL_HIST_LEN_FULL; j++) { 514250003Sadrian home->nf_cal_buffer[j][i] = nf; 515250003Sadrian } 516250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.base.priv_nf[i] = nf; 517250003Sadrian } 518250003Sadrian} 519250003Sadrian#endif 520250003Sadrian 521250003Sadrian/* 522250003Sadrian * Update the noise floor buffer as a ring buffer 523250003Sadrian */ 524250003Sadrianstatic int16_t 525250003Sadrianar9300_update_nf_hist_buff(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, 526250003Sadrian int16_t *nfarray, int hist_len) 527250003Sadrian{ 528250003Sadrian int i, nr; 529250003Sadrian int16_t nf_no_lim_chain0; 530250003Sadrian 531250003Sadrian nf_no_lim_chain0 = ar9300_get_nf_hist_mid(ah, h, 0, hist_len); 532250003Sadrian 533250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] BEFORE\n", __func__, __LINE__); 534250003Sadrian for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) { 535250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 536250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 537250003Sadrian "nf_cal_buffer[%d][%d] = %d\n", 538250003Sadrian nr, i, (int)h->nf_cal_buffer[nr][i]); 539250003Sadrian } 540250003Sadrian } 541250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 542250003Sadrian h->nf_cal_buffer[h->base.curr_index][i] = nfarray[i]; 543250003Sadrian h->base.priv_nf[i] = ar9300_limit_nf_range( 544250003Sadrian ah, ar9300_get_nf_hist_mid(ah, h, i, hist_len)); 545250003Sadrian } 546250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] AFTER\n", __func__, __LINE__); 547250003Sadrian for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) { 548250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 549250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 550250003Sadrian "nf_cal_buffer[%d][%d] = %d\n", 551250003Sadrian nr, i, (int)h->nf_cal_buffer[nr][i]); 552250003Sadrian } 553250003Sadrian } 554250003Sadrian 555250003Sadrian if (++h->base.curr_index >= hist_len) { 556250003Sadrian h->base.curr_index = 0; 557250003Sadrian } 558250003Sadrian 559250003Sadrian return nf_no_lim_chain0; 560250003Sadrian} 561250003Sadrian 562250008Sadrian#ifdef UNUSED 563250003Sadrianstatic HAL_BOOL 564250003Sadrianget_noise_floor_thresh(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *chan, 565250003Sadrian int16_t *nft) 566250003Sadrian{ 567250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 568250003Sadrian 569278741Sadrian 570250003Sadrian switch (chan->channel_flags & CHANNEL_ALL_NOTURBO) { 571250003Sadrian case CHANNEL_A: 572250003Sadrian case CHANNEL_A_HT20: 573250003Sadrian case CHANNEL_A_HT40PLUS: 574250003Sadrian case CHANNEL_A_HT40MINUS: 575250003Sadrian *nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_5); 576250003Sadrian break; 577250003Sadrian case CHANNEL_B: 578250003Sadrian case CHANNEL_G: 579250003Sadrian case CHANNEL_G_HT20: 580250003Sadrian case CHANNEL_G_HT40PLUS: 581250003Sadrian case CHANNEL_G_HT40MINUS: 582250003Sadrian *nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_2); 583250003Sadrian break; 584250003Sadrian default: 585250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel flags 0x%x\n", 586250003Sadrian __func__, chan->channel_flags); 587250003Sadrian return AH_FALSE; 588250003Sadrian } 589250003Sadrian return AH_TRUE; 590250003Sadrian} 591250003Sadrian#endif 592250003Sadrian 593250003Sadrian/* 594250003Sadrian * Read the NF and check it against the noise floor threshhold 595250003Sadrian */ 596250003Sadrian#define IS(_c, _f) (((_c)->channel_flags & _f) || 0) 597250003Sadrianstatic int 598250008Sadrianar9300_store_new_nf(struct ath_hal *ah, struct ieee80211_channel *chan, 599250008Sadrian int is_scan) 600250003Sadrian{ 601250008Sadrian// struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 602250003Sadrian int nf_hist_len; 603250003Sadrian int16_t nf_no_lim; 604250008Sadrian int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; 605250003Sadrian HAL_NFCAL_HIST_FULL *h; 606250003Sadrian int is_2g = 0; 607250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 608250008Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 609250003Sadrian 610250003Sadrian if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 611250003Sadrian u_int32_t tsf32, nf_cal_dur_tsf; 612250003Sadrian /* 613250003Sadrian * The reason the NF calibration did not complete may just be that 614250003Sadrian * not enough time has passed since the NF calibration was started, 615250003Sadrian * because under certain conditions (when first moving to a new 616250003Sadrian * channel) the NF calibration may be checked very repeatedly. 617250003Sadrian * Or, there may be CW interference keeping the NF calibration 618250003Sadrian * from completing. Check the delta time between when the NF 619250003Sadrian * calibration was started and now to see whether the NF calibration 620250003Sadrian * should have already completed (but hasn't, probably due to CW 621250003Sadrian * interference), or hasn't had enough time to finish yet. 622250003Sadrian */ 623250003Sadrian /* 624250003Sadrian * AH_NF_CAL_DUR_MAX_TSF - A conservative maximum time that the 625250003Sadrian * HW should need to finish a NF calibration. If the HW 626250003Sadrian * does not complete a NF calibration within this time period, 627250003Sadrian * there must be a problem - probably CW interference. 628250003Sadrian * AH_NF_CAL_PERIOD_MAX_TSF - A conservative maximum time between 629250003Sadrian * check of the HW's NF calibration being finished. 630250003Sadrian * If the difference between the current TSF and the TSF 631250003Sadrian * recorded when the NF calibration started is larger than this 632250003Sadrian * value, the TSF must have been reset. 633250003Sadrian * In general, we expect the TSF to only be reset during 634250003Sadrian * regular operation for STAs, not for APs. However, an 635250003Sadrian * AP's TSF could be reset when joining an IBSS. 636250003Sadrian * There's an outside chance that this could result in the 637250003Sadrian * CW_INT flag being erroneously set, if the TSF adjustment 638250003Sadrian * is smaller than AH_NF_CAL_PERIOD_MAX_TSF but larger than 639250003Sadrian * AH_NF_CAL_DUR_TSF. However, even if this does happen, 640250003Sadrian * it shouldn't matter, as the IBSS case shouldn't be 641250003Sadrian * concerned about CW_INT. 642250003Sadrian */ 643250003Sadrian /* AH_NF_CAL_DUR_TSF - 90 sec in usec units */ 644250003Sadrian #define AH_NF_CAL_DUR_TSF (90 * 1000 * 1000) 645250003Sadrian /* AH_NF_CAL_PERIOD_MAX_TSF - 180 sec in usec units */ 646250003Sadrian #define AH_NF_CAL_PERIOD_MAX_TSF (180 * 1000 * 1000) 647250003Sadrian /* wraparound handled by using unsigned values */ 648250003Sadrian tsf32 = ar9300_get_tsf32(ah); 649250003Sadrian nf_cal_dur_tsf = tsf32 - AH9300(ah)->nf_tsf32; 650250003Sadrian if (nf_cal_dur_tsf > AH_NF_CAL_PERIOD_MAX_TSF) { 651250003Sadrian /* 652250003Sadrian * The TSF must have gotten reset during the NF cal - 653250003Sadrian * just reset the NF TSF timestamp, so the next time 654250003Sadrian * this function is called, the timestamp comparison 655250003Sadrian * will be valid. 656250003Sadrian */ 657250003Sadrian AH9300(ah)->nf_tsf32 = tsf32; 658250003Sadrian } else if (nf_cal_dur_tsf > AH_NF_CAL_DUR_TSF) { 659250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 660250003Sadrian "%s: NF did not complete in calibration window\n", __func__); 661250003Sadrian /* the NF incompletion is probably due to CW interference */ 662250008Sadrian chan->ic_state |= IEEE80211_CHANSTATE_CWINT; 663250003Sadrian } 664250003Sadrian return 0; /* HW's NF measurement not finished */ 665250003Sadrian } 666250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 667250008Sadrian "%s[%d] chan %d\n", __func__, __LINE__, ichan->channel); 668250008Sadrian is_2g = !! IS_CHAN_2GHZ(ichan); 669250003Sadrian ar9300_upload_noise_floor(ah, is_2g, nfarray); 670250003Sadrian 671250003Sadrian /* Update the NF buffer for each chain masked by chainmask */ 672250003Sadrian#ifdef ATH_NF_PER_CHAN 673250008Sadrian h = &ichan->nf_cal_hist; 674250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 675250003Sadrian#else 676250003Sadrian if (is_scan) { 677250003Sadrian /* 678250003Sadrian * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct 679250003Sadrian * rather than a HAL_NFCAL_HIST_FULL struct. 680250003Sadrian * As long as we only use the first history element of nf_cal_buffer 681250008Sadrian * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use 682250003Sadrian * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably. 683250003Sadrian */ 684250008Sadrian h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 685250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; 686250003Sadrian } else { 687250003Sadrian h = &AH_PRIVATE(ah)->nf_cal_hist; 688250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 689250003Sadrian } 690250003Sadrian#endif 691250003Sadrian 692250003Sadrian /* 693250003Sadrian * nf_no_lim = median value from NF history buffer without bounds limits, 694250003Sadrian * priv_nf = median value from NF history buffer with bounds limits. 695250003Sadrian */ 696250003Sadrian nf_no_lim = ar9300_update_nf_hist_buff(ah, h, nfarray, nf_hist_len); 697250008Sadrian ichan->rawNoiseFloor = h->base.priv_nf[0]; 698250003Sadrian 699250003Sadrian /* check if there is interference */ 700250008Sadrian// ichan->channel_flags &= (~CHANNEL_CW_INT); 701250003Sadrian /* 702250003Sadrian * Use AR9300_EMULATION to check for emulation purpose as PCIE Device ID 703250003Sadrian * 0xABCD is recognized as valid Osprey as WAR in some EVs. 704250003Sadrian */ 705250008Sadrian if (nf_no_lim > ahp->nfp->nominal + ahp->nf_cw_int_delta) { 706250003Sadrian /* 707250003Sadrian * Since this CW interference check is being applied to the 708250003Sadrian * median element of the NF history buffer, this indicates that 709250003Sadrian * the CW interference is persistent. A single high NF reading 710250003Sadrian * will not show up in the median, and thus will not cause the 711250003Sadrian * CW_INT flag to be set. 712250003Sadrian */ 713250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 714250003Sadrian "%s: NF Cal: CW interferer detected through NF: %d\n", 715250003Sadrian __func__, nf_no_lim); 716250008Sadrian chan->ic_state |= IEEE80211_CHANSTATE_CWINT; 717250003Sadrian } 718250003Sadrian return 1; /* HW's NF measurement finished */ 719250003Sadrian} 720250003Sadrian#undef IS 721250003Sadrian 722250003Sadrianstatic inline void 723250003Sadrianar9300_get_delta_slope_values(struct ath_hal *ah, u_int32_t coef_scaled, 724250003Sadrian u_int32_t *coef_mantissa, u_int32_t *coef_exponent) 725250003Sadrian{ 726250003Sadrian u_int32_t coef_exp, coef_man; 727250003Sadrian 728250003Sadrian /* 729250003Sadrian * ALGO -> coef_exp = 14-floor(log2(coef)); 730250003Sadrian * floor(log2(x)) is the highest set bit position 731250003Sadrian */ 732250003Sadrian for (coef_exp = 31; coef_exp > 0; coef_exp--) { 733250003Sadrian if ((coef_scaled >> coef_exp) & 0x1) { 734250003Sadrian break; 735250003Sadrian } 736250003Sadrian } 737250003Sadrian /* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */ 738250003Sadrian HALASSERT(coef_exp); 739250003Sadrian coef_exp = 14 - (coef_exp - COEF_SCALE_S); 740250003Sadrian 741250003Sadrian 742250003Sadrian /* 743250003Sadrian * ALGO -> coef_man = floor(coef* 2^coef_exp+0.5); 744250003Sadrian * The coefficient is already shifted up for scaling 745250003Sadrian */ 746250003Sadrian coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); 747250003Sadrian 748250003Sadrian *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); 749250003Sadrian *coef_exponent = coef_exp - 16; 750250003Sadrian} 751250003Sadrian 752250003Sadrian#define MAX_ANALOG_START 319 /* XXX */ 753250003Sadrian 754250003Sadrian/* 755250003Sadrian * Delta slope coefficient computation. 756250003Sadrian * Required for OFDM operation. 757250003Sadrian */ 758250003Sadrianstatic void 759250008Sadrianar9300_set_delta_slope(struct ath_hal *ah, struct ieee80211_channel *chan) 760250003Sadrian{ 761250003Sadrian u_int32_t coef_scaled, ds_coef_exp, ds_coef_man; 762250003Sadrian u_int32_t fclk = COEFF; /* clock * 2.5 */ 763250003Sadrian 764250003Sadrian u_int32_t clock_mhz_scaled = 0x1000000 * fclk; 765250003Sadrian CHAN_CENTERS centers; 766250003Sadrian 767250003Sadrian /* 768250003Sadrian * half and quarter rate can divide the scaled clock by 2 or 4 769250003Sadrian * scale for selected channel bandwidth 770250003Sadrian */ 771250008Sadrian if (IEEE80211_IS_CHAN_HALF(chan)) { 772250003Sadrian clock_mhz_scaled = clock_mhz_scaled >> 1; 773250008Sadrian } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { 774250003Sadrian clock_mhz_scaled = clock_mhz_scaled >> 2; 775250003Sadrian } 776250003Sadrian 777250003Sadrian /* 778250003Sadrian * ALGO -> coef = 1e8/fcarrier*fclock/40; 779250003Sadrian * scaled coef to provide precision for this floating calculation 780250003Sadrian */ 781250003Sadrian ar9300_get_channel_centers(ah, chan, ¢ers); 782250003Sadrian coef_scaled = clock_mhz_scaled / centers.synth_center; 783250003Sadrian 784250003Sadrian ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); 785250003Sadrian 786250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_MAN, ds_coef_man); 787250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); 788250003Sadrian 789250003Sadrian /* 790250003Sadrian * For Short GI, 791250003Sadrian * scaled coeff is 9/10 that of normal coeff 792250003Sadrian */ 793250003Sadrian coef_scaled = (9 * coef_scaled) / 10; 794250003Sadrian 795250003Sadrian ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); 796250003Sadrian 797250003Sadrian /* for short gi */ 798250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_MAN, ds_coef_man); 799250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_EXP, ds_coef_exp); 800250003Sadrian} 801250003Sadrian 802250008Sadrian#define IS(_c, _f) (IEEE80211_IS_ ## _f(_c)) 803250003Sadrian 804250008Sadrian/* 805250008Sadrian * XXX FreeBSD: This should be turned into something generic in ath_hal! 806250008Sadrian */ 807250008SadrianHAL_CHANNEL_INTERNAL * 808250008Sadrianar9300_check_chan(struct ath_hal *ah, const struct ieee80211_channel *chan) 809250003Sadrian{ 810251735Sadrian 811251735Sadrian if (chan == NULL) { 812251735Sadrian return AH_NULL; 813251735Sadrian } 814251735Sadrian 815250008Sadrian if ((IS(chan, CHAN_2GHZ) ^ IS(chan, CHAN_5GHZ)) == 0) { 816250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 817250003Sadrian "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n", 818250008Sadrian __func__, chan->ic_freq , chan->ic_flags); 819250003Sadrian return AH_NULL; 820250003Sadrian } 821250003Sadrian 822250008Sadrian /* 823250008Sadrian * FreeBSD sets multiple flags, so this will fail. 824250008Sadrian */ 825250008Sadrian#if 0 826250008Sadrian if ((IS(chan, CHAN_OFDM) ^ IS(chan, CHAN_CCK) ^ IS(chan, CHAN_DYN) ^ 827250008Sadrian IS(chan, CHAN_HT20) ^ IS(chan, CHAN_HT40U) ^ 828250008Sadrian IS(chan, CHAN_HT40D)) == 0) 829250003Sadrian { 830250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 831250003Sadrian "%s: invalid channel %u/0x%x; not marked as " 832250008Sadrian "OFDM or CCK or DYN or HT20 or HT40PLUS or HT40MINUS\n", 833250008Sadrian __func__, chan->ic_freq , chan->ic_flags); 834250003Sadrian return AH_NULL; 835250003Sadrian } 836250008Sadrian#endif 837250003Sadrian 838250003Sadrian return (ath_hal_checkchannel(ah, chan)); 839250003Sadrian} 840250003Sadrian#undef IS 841250003Sadrian 842250003Sadrianstatic void 843250008Sadrianar9300_set_11n_regs(struct ath_hal *ah, struct ieee80211_channel *chan, 844250003Sadrian HAL_HT_MACMODE macmode) 845250003Sadrian{ 846250003Sadrian u_int32_t phymode; 847250008Sadrian// struct ath_hal_9300 *ahp = AH9300(ah); 848250003Sadrian u_int32_t enable_dac_fifo; 849250003Sadrian 850250003Sadrian /* XXX */ 851250003Sadrian enable_dac_fifo = 852250003Sadrian OS_REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO; 853250003Sadrian 854250003Sadrian /* Enable 11n HT, 20 MHz */ 855250003Sadrian phymode = 856250003Sadrian AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_SHORT_GI_40 857250003Sadrian | enable_dac_fifo; 858250003Sadrian /* Configure baseband for dynamic 20/40 operation */ 859250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 860250003Sadrian phymode |= AR_PHY_GC_DYN2040_EN; 861250003Sadrian /* Configure control (primary) channel at +-10MHz */ 862250008Sadrian if (IEEE80211_IS_CHAN_HT40U(chan)) { 863250003Sadrian phymode |= AR_PHY_GC_DYN2040_PRI_CH; 864250003Sadrian } 865250003Sadrian 866250008Sadrian#if 0 867250003Sadrian /* Configure 20/25 spacing */ 868250003Sadrian if (ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_25) { 869250003Sadrian phymode |= AR_PHY_GC_DYN2040_EXT_CH; 870250003Sadrian } 871250008Sadrian#endif 872250003Sadrian } 873250003Sadrian 874250003Sadrian /* make sure we preserve INI settings */ 875250003Sadrian phymode |= OS_REG_READ(ah, AR_PHY_GEN_CTRL); 876250003Sadrian 877250003Sadrian /* EV 62881/64991 - turn off Green Field detection for Maverick STA beta */ 878250003Sadrian phymode &= ~AR_PHY_GC_GF_DETECT_EN; 879250003Sadrian 880250003Sadrian OS_REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode); 881250003Sadrian 882250003Sadrian /* Set IFS timing for half/quarter rates */ 883250008Sadrian if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) { 884250003Sadrian u_int32_t modeselect = OS_REG_READ(ah, AR_PHY_MODE); 885250003Sadrian 886250008Sadrian if (IEEE80211_IS_CHAN_HALF(chan)) { 887250003Sadrian modeselect |= AR_PHY_MS_HALF_RATE; 888250008Sadrian } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { 889250003Sadrian modeselect |= AR_PHY_MS_QUARTER_RATE; 890250003Sadrian } 891250003Sadrian OS_REG_WRITE(ah, AR_PHY_MODE, modeselect); 892250003Sadrian 893250003Sadrian ar9300_set_ifs_timing(ah, chan); 894250003Sadrian OS_REG_RMW_FIELD( 895250003Sadrian ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 0x3); 896250003Sadrian } 897250003Sadrian 898250003Sadrian /* Configure MAC for 20/40 operation */ 899250003Sadrian ar9300_set_11n_mac2040(ah, macmode); 900250003Sadrian 901250003Sadrian /* global transmit timeout (25 TUs default)*/ 902250003Sadrian /* XXX - put this elsewhere??? */ 903250003Sadrian OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); 904250003Sadrian 905250003Sadrian /* carrier sense timeout */ 906250003Sadrian OS_REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); 907250003Sadrian} 908250003Sadrian 909250003Sadrian/* 910250003Sadrian * Spur mitigation for MRC CCK 911250003Sadrian */ 912250003Sadrianstatic void 913250008Sadrianar9300_spur_mitigate_mrc_cck(struct ath_hal *ah, struct ieee80211_channel *chan) 914250003Sadrian{ 915250003Sadrian int i; 916250003Sadrian /* spur_freq_for_osprey - hardcoded by Systems team for now. */ 917250003Sadrian u_int32_t spur_freq_for_osprey[4] = { 2420, 2440, 2464, 2480 }; 918250003Sadrian u_int32_t spur_freq_for_jupiter[2] = { 2440, 2464}; 919250003Sadrian int cur_bb_spur, negative = 0, cck_spur_freq; 920250003Sadrian u_int8_t* spur_fbin_ptr = NULL; 921250003Sadrian int synth_freq; 922250003Sadrian int range = 10; 923250003Sadrian int max_spurcounts = OSPREY_EEPROM_MODAL_SPURS; 924250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 925250003Sadrian 926250003Sadrian /* 927250003Sadrian * Need to verify range +/- 10 MHz in control channel, otherwise spur 928250003Sadrian * is out-of-band and can be ignored. 929250003Sadrian */ 930250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || 931250003Sadrian AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 932250003Sadrian spur_fbin_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1); 933250003Sadrian if (spur_fbin_ptr[0] == 0) { 934250003Sadrian return; /* No spur in the mode */ 935250003Sadrian } 936250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 937250003Sadrian range = 19; 938250003Sadrian if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) 939250003Sadrian == 0x0) 940250003Sadrian { 941250008Sadrian synth_freq = ichan->channel + 10; 942250003Sadrian } else { 943250008Sadrian synth_freq = ichan->channel - 10; 944250003Sadrian } 945250003Sadrian } else { 946250003Sadrian range = 10; 947250008Sadrian synth_freq = ichan->channel; 948250003Sadrian } 949250003Sadrian } else if(AR_SREV_JUPITER(ah)) { 950250003Sadrian range = 5; 951250003Sadrian max_spurcounts = 2; /* Hardcoded by Jupiter Systems team for now. */ 952250008Sadrian synth_freq = ichan->channel; 953250003Sadrian } else { 954250003Sadrian range = 10; 955250003Sadrian max_spurcounts = 4; /* Hardcoded by Osprey Systems team for now. */ 956250008Sadrian synth_freq = ichan->channel; 957250003Sadrian } 958250003Sadrian 959250003Sadrian for (i = 0; i < max_spurcounts; i++) { 960250003Sadrian negative = 0; 961250003Sadrian 962250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || 963250003Sadrian AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 964250003Sadrian cur_bb_spur = 965250003Sadrian FBIN2FREQ(spur_fbin_ptr[i], HAL_FREQ_BAND_2GHZ) - synth_freq; 966250003Sadrian } else if(AR_SREV_JUPITER(ah)) { 967250003Sadrian cur_bb_spur = spur_freq_for_jupiter[i] - synth_freq; 968250003Sadrian } else { 969250003Sadrian cur_bb_spur = spur_freq_for_osprey[i] - synth_freq; 970250003Sadrian } 971250003Sadrian 972250003Sadrian if (cur_bb_spur < 0) { 973250003Sadrian negative = 1; 974250003Sadrian cur_bb_spur = -cur_bb_spur; 975250003Sadrian } 976250003Sadrian if (cur_bb_spur < range) { 977250003Sadrian cck_spur_freq = (int)((cur_bb_spur << 19) / 11); 978250003Sadrian if (negative == 1) { 979250003Sadrian cck_spur_freq = -cck_spur_freq; 980250003Sadrian } 981250003Sadrian cck_spur_freq = cck_spur_freq & 0xfffff; 982250003Sadrian /*OS_REG_WRITE_field(ah, BB_agc_control.ycok_max, 0x7);*/ 983250003Sadrian OS_REG_RMW_FIELD(ah, 984250003Sadrian AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7); 985250003Sadrian /*OS_REG_WRITE_field(ah, BB_cck_spur_mit.spur_rssi_thr, 0x7f);*/ 986250003Sadrian OS_REG_RMW_FIELD(ah, 987250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f); 988250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.spur_filter_type, 0x2);*/ 989250003Sadrian OS_REG_RMW_FIELD(ah, 990250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE, 0x2); 991250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x1);*/ 992250003Sadrian OS_REG_RMW_FIELD(ah, 993250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x1); 994250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, cck_spur_freq);*/ 995250003Sadrian OS_REG_RMW_FIELD(ah, 996250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 997250003Sadrian cck_spur_freq); 998250003Sadrian return; 999250003Sadrian } 1000250003Sadrian } 1001250003Sadrian 1002250003Sadrian /*OS_REG_WRITE(ah, BB_agc_control.ycok_max, 0x5);*/ 1003250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5); 1004250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x0);*/ 1005250003Sadrian OS_REG_RMW_FIELD(ah, 1006250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0); 1007250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, 0x0);*/ 1008250003Sadrian OS_REG_RMW_FIELD(ah, 1009250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0x0); 1010250003Sadrian} 1011250003Sadrian 1012250003Sadrian/* Spur mitigation for OFDM */ 1013250003Sadrianstatic void 1014250008Sadrianar9300_spur_mitigate_ofdm(struct ath_hal *ah, struct ieee80211_channel *chan) 1015250003Sadrian{ 1016250003Sadrian int synth_freq; 1017250003Sadrian int range = 10; 1018250003Sadrian int freq_offset = 0; 1019250003Sadrian int spur_freq_sd = 0; 1020250003Sadrian int spur_subchannel_sd = 0; 1021250003Sadrian int spur_delta_phase = 0; 1022250003Sadrian int mask_index = 0; 1023250003Sadrian int i; 1024250003Sadrian int mode; 1025250003Sadrian u_int8_t* spur_chans_ptr; 1026250008Sadrian struct ath_hal_9300 *ahp; 1027250008Sadrian ahp = AH9300(ah); 1028250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 1029250003Sadrian 1030250008Sadrian if (IS_CHAN_5GHZ(ichan)) { 1031250003Sadrian spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 0); 1032250003Sadrian mode = 0; 1033250003Sadrian } else { 1034250003Sadrian spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1); 1035250003Sadrian mode = 1; 1036250003Sadrian } 1037250003Sadrian 1038250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 1039250003Sadrian range = 19; 1040250003Sadrian if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) 1041250003Sadrian == 0x0) 1042250003Sadrian { 1043250008Sadrian synth_freq = ichan->channel - 10; 1044250003Sadrian } else { 1045250008Sadrian synth_freq = ichan->channel + 10; 1046250003Sadrian } 1047250003Sadrian } else { 1048250003Sadrian range = 10; 1049250008Sadrian synth_freq = ichan->channel; 1050250003Sadrian } 1051250003Sadrian 1052250003Sadrian /* Clean all spur register fields */ 1053250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0); 1054250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, 0); 1055250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0); 1056250003Sadrian OS_REG_RMW_FIELD(ah, 1057250003Sadrian AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 0); 1058250003Sadrian OS_REG_RMW_FIELD(ah, 1059250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0); 1060250003Sadrian OS_REG_RMW_FIELD(ah, 1061250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0); 1062250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0); 1063250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 0); 1064250003Sadrian OS_REG_RMW_FIELD(ah, 1065250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 0); 1066250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0); 1067250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0); 1068250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0); 1069250003Sadrian OS_REG_RMW_FIELD(ah, 1070250003Sadrian AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0); 1071250003Sadrian OS_REG_RMW_FIELD(ah, 1072250003Sadrian AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0); 1073250003Sadrian OS_REG_RMW_FIELD(ah, 1074250003Sadrian AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0); 1075250003Sadrian OS_REG_RMW_FIELD(ah, 1076250003Sadrian AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0); 1077250003Sadrian OS_REG_RMW_FIELD(ah, 1078250003Sadrian AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0); 1079250003Sadrian OS_REG_RMW_FIELD(ah, 1080250003Sadrian AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0); 1081250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0); 1082250003Sadrian 1083250003Sadrian i = 0; 1084250003Sadrian while (spur_chans_ptr[i] && i < 5) { 1085250003Sadrian freq_offset = FBIN2FREQ(spur_chans_ptr[i], mode) - synth_freq; 1086250003Sadrian if (abs(freq_offset) < range) { 1087250003Sadrian /* 1088250003Sadrian printf( 1089250003Sadrian "Spur Mitigation for OFDM: Synth Frequency = %d, " 1090250003Sadrian "Spur Frequency = %d\n", 1091250003Sadrian synth_freq, FBIN2FREQ(spur_chans_ptr[i], mode)); 1092250003Sadrian */ 1093250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 1094250003Sadrian if (freq_offset < 0) { 1095250003Sadrian if (OS_REG_READ_FIELD( 1096250003Sadrian ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0) 1097250003Sadrian { 1098250003Sadrian spur_subchannel_sd = 1; 1099250003Sadrian } else { 1100250003Sadrian spur_subchannel_sd = 0; 1101250003Sadrian } 1102250003Sadrian spur_freq_sd = ((freq_offset + 10) << 9) / 11; 1103250003Sadrian } else { 1104250003Sadrian if (OS_REG_READ_FIELD(ah, 1105250003Sadrian AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0) 1106250003Sadrian { 1107250003Sadrian spur_subchannel_sd = 0; 1108250003Sadrian } else { 1109250003Sadrian spur_subchannel_sd = 1; 1110250003Sadrian } 1111250003Sadrian spur_freq_sd = ((freq_offset - 10) << 9) / 11; 1112250003Sadrian } 1113250003Sadrian spur_delta_phase = (freq_offset << 17) / 5; 1114250003Sadrian } else { 1115250003Sadrian spur_subchannel_sd = 0; 1116250003Sadrian spur_freq_sd = (freq_offset << 9) / 11; 1117250003Sadrian spur_delta_phase = (freq_offset << 18) / 5; 1118250003Sadrian } 1119250003Sadrian spur_freq_sd = spur_freq_sd & 0x3ff; 1120250003Sadrian spur_delta_phase = spur_delta_phase & 0xfffff; 1121250003Sadrian /* 1122250003Sadrian printf( 1123250003Sadrian "spur_subchannel_sd = %d, spur_freq_sd = 0x%x, " 1124250003Sadrian "spur_delta_phase = 0x%x\n", spur_subchannel_sd, 1125250003Sadrian spur_freq_sd, spur_delta_phase); 1126250003Sadrian */ 1127250003Sadrian 1128250003Sadrian /* OFDM Spur mitigation */ 1129250003Sadrian OS_REG_RMW_FIELD(ah, 1130250003Sadrian AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0x1); 1131250003Sadrian OS_REG_RMW_FIELD(ah, 1132250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd); 1133250003Sadrian OS_REG_RMW_FIELD(ah, 1134250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 1135250003Sadrian spur_delta_phase); 1136250003Sadrian OS_REG_RMW_FIELD(ah, 1137250003Sadrian AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 1138250003Sadrian spur_subchannel_sd); 1139250003Sadrian OS_REG_RMW_FIELD(ah, 1140250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0x1); 1141250003Sadrian OS_REG_RMW_FIELD(ah, 1142250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 1143250003Sadrian 0x1); 1144250003Sadrian OS_REG_RMW_FIELD(ah, 1145250003Sadrian AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0x1); 1146250003Sadrian OS_REG_RMW_FIELD(ah, 1147250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34); 1148250003Sadrian OS_REG_RMW_FIELD(ah, 1149250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1); 1150250003Sadrian 1151250003Sadrian /* 1152250003Sadrian * Do not subtract spur power from noise floor for wasp. 1153250003Sadrian * This causes the maximum client test (on Veriwave) to fail 1154250003Sadrian * when run on spur channel (2464 MHz). 1155250003Sadrian * Refer to ev#82746 and ev#82744. 1156250003Sadrian */ 1157250003Sadrian if (!AR_SREV_WASP(ah) && (OS_REG_READ_FIELD(ah, AR_PHY_MODE, 1158250003Sadrian AR_PHY_MODE_DYNAMIC) == 0x1)) { 1159250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, 1160250003Sadrian AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1); 1161250003Sadrian } 1162250003Sadrian 1163250003Sadrian mask_index = (freq_offset << 4) / 5; 1164250003Sadrian if (mask_index < 0) { 1165250003Sadrian mask_index = mask_index - 1; 1166250003Sadrian } 1167250003Sadrian mask_index = mask_index & 0x7f; 1168250003Sadrian /*printf("Bin 0x%x\n", mask_index);*/ 1169250003Sadrian 1170250003Sadrian OS_REG_RMW_FIELD(ah, 1171250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0x1); 1172250003Sadrian OS_REG_RMW_FIELD(ah, 1173250003Sadrian AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0x1); 1174250003Sadrian OS_REG_RMW_FIELD(ah, 1175250003Sadrian AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1); 1176250003Sadrian OS_REG_RMW_FIELD(ah, 1177250003Sadrian AR_PHY_PILOT_SPUR_MASK, 1178250003Sadrian AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index); 1179250003Sadrian OS_REG_RMW_FIELD(ah, 1180250003Sadrian AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 1181250003Sadrian mask_index); 1182250003Sadrian OS_REG_RMW_FIELD(ah, 1183250003Sadrian AR_PHY_CHAN_SPUR_MASK, 1184250003Sadrian AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index); 1185250003Sadrian OS_REG_RMW_FIELD(ah, 1186250003Sadrian AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 1187250003Sadrian 0xc); 1188250003Sadrian OS_REG_RMW_FIELD(ah, 1189250003Sadrian AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 1190250003Sadrian 0xc); 1191250003Sadrian OS_REG_RMW_FIELD(ah, 1192250003Sadrian AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0); 1193250003Sadrian OS_REG_RMW_FIELD(ah, 1194250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff); 1195250003Sadrian /* 1196250003Sadrian printf("BB_timing_control_4 = 0x%x\n", 1197250003Sadrian OS_REG_READ(ah, AR_PHY_TIMING4)); 1198250003Sadrian printf("BB_timing_control_11 = 0x%x\n", 1199250003Sadrian OS_REG_READ(ah, AR_PHY_TIMING11)); 1200250003Sadrian printf("BB_ext_chan_scorr_thr = 0x%x\n", 1201250003Sadrian OS_REG_READ(ah, AR_PHY_SFCORR_EXT)); 1202250003Sadrian printf("BB_spur_mask_controls = 0x%x\n", 1203250003Sadrian OS_REG_READ(ah, AR_PHY_SPUR_REG)); 1204250003Sadrian printf("BB_pilot_spur_mask = 0x%x\n", 1205250003Sadrian OS_REG_READ(ah, AR_PHY_PILOT_SPUR_MASK)); 1206250003Sadrian printf("BB_chan_spur_mask = 0x%x\n", 1207250003Sadrian OS_REG_READ(ah, AR_PHY_CHAN_SPUR_MASK)); 1208250003Sadrian printf("BB_vit_spur_mask_A = 0x%x\n", 1209250003Sadrian OS_REG_READ(ah, AR_PHY_SPUR_MASK_A)); 1210250003Sadrian */ 1211250003Sadrian break; 1212250003Sadrian } 1213250003Sadrian i++; 1214250003Sadrian } 1215250003Sadrian} 1216250003Sadrian 1217250003Sadrian 1218250003Sadrian/* 1219250003Sadrian * Convert to baseband spur frequency given input channel frequency 1220250003Sadrian * and compute register settings below. 1221250003Sadrian */ 1222250003Sadrianstatic void 1223250008Sadrianar9300_spur_mitigate(struct ath_hal *ah, struct ieee80211_channel *chan) 1224250003Sadrian{ 1225250003Sadrian ar9300_spur_mitigate_ofdm(ah, chan); 1226250003Sadrian ar9300_spur_mitigate_mrc_cck(ah, chan); 1227250003Sadrian} 1228250003Sadrian 1229250003Sadrian/************************************************************** 1230250003Sadrian * ar9300_channel_change 1231250003Sadrian * Assumes caller wants to change channel, and not reset. 1232250003Sadrian */ 1233250003Sadrianstatic inline HAL_BOOL 1234250008Sadrianar9300_channel_change(struct ath_hal *ah, struct ieee80211_channel *chan, 1235250003Sadrian HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode) 1236250003Sadrian{ 1237250003Sadrian 1238250003Sadrian u_int32_t synth_delay, qnum; 1239250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1240250003Sadrian 1241250003Sadrian /* TX must be stopped by now */ 1242250003Sadrian for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { 1243250003Sadrian if (ar9300_num_tx_pending(ah, qnum)) { 1244250003Sadrian HALDEBUG(ah, HAL_DEBUG_QUEUE, 1245250003Sadrian "%s: Transmit frames pending on queue %d\n", __func__, qnum); 1246250003Sadrian HALASSERT(0); 1247250003Sadrian return AH_FALSE; 1248250003Sadrian } 1249250003Sadrian } 1250250003Sadrian 1251250003Sadrian 1252250003Sadrian /* 1253250003Sadrian * Kill last Baseband Rx Frame - Request analog bus grant 1254250003Sadrian */ 1255250003Sadrian OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); 1256250003Sadrian if (!ath_hal_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, 1257250008Sadrian AR_PHY_RFBUS_GRANT_EN)) 1258250003Sadrian { 1259250008Sadrian HALDEBUG(ah, HAL_DEBUG_PHYIO, 1260250003Sadrian "%s: Could not kill baseband RX\n", __func__); 1261250003Sadrian return AH_FALSE; 1262250003Sadrian } 1263250003Sadrian 1264250003Sadrian 1265250003Sadrian /* Setup 11n MAC/Phy mode registers */ 1266250003Sadrian ar9300_set_11n_regs(ah, chan, macmode); 1267250003Sadrian 1268250003Sadrian /* 1269250003Sadrian * Change the synth 1270250003Sadrian */ 1271250008Sadrian if (!ahp->ah_rf_hal.set_channel(ah, chan)) { 1272250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: failed to set channel\n", __func__); 1273250003Sadrian return AH_FALSE; 1274250003Sadrian } 1275250003Sadrian 1276250003Sadrian /* 1277250003Sadrian * Some registers get reinitialized during ATH_INI_POST INI programming. 1278250003Sadrian */ 1279250003Sadrian ar9300_init_user_settings(ah); 1280250003Sadrian 1281250003Sadrian /* 1282250003Sadrian * Setup the transmit power values. 1283250003Sadrian * 1284250003Sadrian * After the public to private hal channel mapping, ichan contains the 1285250003Sadrian * valid regulatory power value. 1286250003Sadrian * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan. 1287250003Sadrian */ 1288250003Sadrian if (ar9300_eeprom_set_transmit_power( 1289250008Sadrian ah, &ahp->ah_eeprom, chan, ath_hal_getctl(ah, chan), 1290250003Sadrian ath_hal_getantennaallowed(ah, chan), 1291250003Sadrian ath_hal_get_twice_max_regpower(AH_PRIVATE(ah), ichan, chan), 1292250008Sadrian AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit)) != HAL_OK) 1293250003Sadrian { 1294250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 1295250003Sadrian "%s: error init'ing transmit power\n", __func__); 1296250003Sadrian return AH_FALSE; 1297250003Sadrian } 1298250003Sadrian 1299250003Sadrian /* 1300250003Sadrian * Release the RFBus Grant. 1301250003Sadrian */ 1302250003Sadrian OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); 1303250003Sadrian 1304250003Sadrian /* 1305250003Sadrian * Write spur immunity and delta slope for OFDM enabled modes (A, G, Turbo) 1306250003Sadrian */ 1307250008Sadrian if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) { 1308250008Sadrian ar9300_set_delta_slope(ah, chan); 1309250003Sadrian } else { 1310250003Sadrian /* Set to Ini default */ 1311250003Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING3, 0x9c0a9f6b); 1312250003Sadrian OS_REG_WRITE(ah, AR_PHY_SGI_DELTA, 0x00046384); 1313250003Sadrian } 1314250003Sadrian 1315250003Sadrian ar9300_spur_mitigate(ah, chan); 1316250003Sadrian 1317250003Sadrian 1318250003Sadrian /* 1319250003Sadrian * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN). 1320250003Sadrian * Read the phy active delay register. Value is in 100ns increments. 1321250003Sadrian */ 1322250003Sadrian synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; 1323250008Sadrian if (IEEE80211_IS_CHAN_CCK(chan)) { 1324250003Sadrian synth_delay = (4 * synth_delay) / 22; 1325250003Sadrian } else { 1326250003Sadrian synth_delay /= 10; 1327250003Sadrian } 1328250003Sadrian 1329250003Sadrian OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY); 1330250003Sadrian 1331250003Sadrian /* 1332250003Sadrian * Do calibration. 1333250003Sadrian */ 1334250003Sadrian 1335250003Sadrian return AH_TRUE; 1336250003Sadrian} 1337250003Sadrian 1338250003Sadrianvoid 1339250003Sadrianar9300_set_operating_mode(struct ath_hal *ah, int opmode) 1340250003Sadrian{ 1341250003Sadrian u_int32_t val; 1342250003Sadrian 1343250003Sadrian val = OS_REG_READ(ah, AR_STA_ID1); 1344250003Sadrian val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); 1345250003Sadrian switch (opmode) { 1346250003Sadrian case HAL_M_HOSTAP: 1347250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, 1348250003Sadrian val | AR_STA_ID1_STA_AP | AR_STA_ID1_KSRCH_MODE); 1349250003Sadrian OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); 1350250003Sadrian break; 1351250003Sadrian case HAL_M_IBSS: 1352250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, 1353250003Sadrian val | AR_STA_ID1_ADHOC | AR_STA_ID1_KSRCH_MODE); 1354250003Sadrian OS_REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); 1355250003Sadrian break; 1356250003Sadrian case HAL_M_STA: 1357250003Sadrian case HAL_M_MONITOR: 1358250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); 1359250003Sadrian break; 1360250003Sadrian } 1361250003Sadrian} 1362250003Sadrian 1363250003Sadrian/* XXX need the logic for Osprey */ 1364257855Sianvoid 1365250008Sadrianar9300_init_pll(struct ath_hal *ah, struct ieee80211_channel *chan) 1366250003Sadrian{ 1367250003Sadrian u_int32_t pll; 1368250003Sadrian u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz; 1369250008Sadrian HAL_CHANNEL_INTERNAL *ichan = NULL; 1370250003Sadrian 1371250008Sadrian if (chan) 1372250008Sadrian ichan = ath_hal_checkchannel(ah, chan); 1373250008Sadrian 1374250003Sadrian if (AR_SREV_HORNET(ah)) { 1375250003Sadrian if (clk_25mhz) { 1376250003Sadrian /* Hornet uses PLL_CONTROL_2. Xtal is 25MHz for Hornet. 1377250003Sadrian * REFDIV set to 0x1. 1378250003Sadrian * $xtal_freq = 25; 1379250003Sadrian * $PLL2_div = (704/$xtal_freq); # 176 * 4 = 704. 1380250003Sadrian * MAC and BB run at 176 MHz. 1381250003Sadrian * $PLL2_divint = int($PLL2_div); 1382250003Sadrian * $PLL2_divfrac = $PLL2_div - $PLL2_divint; 1383250003Sadrian * $PLL2_divfrac = int($PLL2_divfrac * 0x4000); # 2^14 1384250003Sadrian * $PLL2_Val = ($PLL2_divint & 0x3f) << 19 | (0x1) << 14 | 1385250003Sadrian * $PLL2_divfrac & 0x3fff; 1386250003Sadrian * Therefore, $PLL2_Val = 0xe04a3d 1387250003Sadrian */ 1388250003Sadrian#define DPLL2_KD_VAL 0x1D 1389250003Sadrian#define DPLL2_KI_VAL 0x06 1390250003Sadrian#define DPLL3_PHASE_SHIFT_VAL 0x1 1391250003Sadrian 1392250003Sadrian /* Rewrite DDR PLL2 and PLL3 */ 1393250003Sadrian /* program DDR PLL ki and kd value, ki=0x6, kd=0x1d */ 1394250003Sadrian OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x18e82f01); 1395250003Sadrian 1396250003Sadrian /* program DDR PLL phase_shift to 0x1 */ 1397250003Sadrian OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3, 1398250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); 1399250003Sadrian 1400250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); 1401250003Sadrian OS_DELAY(1000); 1402250003Sadrian 1403250003Sadrian /* program refdiv, nint, frac to RTC register */ 1404250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0xe04a3d); 1405250003Sadrian 1406250003Sadrian /* program BB PLL ki and kd value, ki=0x6, kd=0x1d */ 1407250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1408250003Sadrian AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL); 1409250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1410250003Sadrian AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL); 1411250003Sadrian 1412250003Sadrian /* program BB PLL phase_shift to 0x1 */ 1413250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, 1414250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); 1415250003Sadrian } else { /* 40MHz */ 1416250003Sadrian#undef DPLL2_KD_VAL 1417250003Sadrian#undef DPLL2_KI_VAL 1418250003Sadrian#define DPLL2_KD_VAL 0x3D 1419250003Sadrian#define DPLL2_KI_VAL 0x06 1420250003Sadrian /* Rewrite DDR PLL2 and PLL3 */ 1421250003Sadrian /* program DDR PLL ki and kd value, ki=0x6, kd=0x3d */ 1422250003Sadrian OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x19e82f01); 1423250003Sadrian 1424250003Sadrian /* program DDR PLL phase_shift to 0x1 */ 1425250003Sadrian OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3, 1426250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); 1427250003Sadrian 1428250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); 1429250003Sadrian OS_DELAY(1000); 1430250003Sadrian 1431250003Sadrian /* program refdiv, nint, frac to RTC register */ 1432250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); 1433250003Sadrian 1434250003Sadrian /* program BB PLL ki and kd value, ki=0x6, kd=0x3d */ 1435250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1436250003Sadrian AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL); 1437250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1438250003Sadrian AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL); 1439250003Sadrian 1440250003Sadrian /* program BB PLL phase_shift to 0x1 */ 1441250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, 1442250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); 1443250003Sadrian } 1444250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); 1445250003Sadrian OS_DELAY(1000); 1446250003Sadrian } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 1447250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_PLL_PWD, 0x1); 1448250003Sadrian 1449250003Sadrian /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */ 1450250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1451250003Sadrian AR_PHY_BB_DPLL2_KD, 0x40); 1452250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1453250003Sadrian AR_PHY_BB_DPLL2_KI, 0x4); 1454250003Sadrian 1455250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, 1456250003Sadrian AR_PHY_BB_DPLL1_REFDIV, 0x5); 1457250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, 1458250003Sadrian AR_PHY_BB_DPLL1_NINI, 0x58); 1459250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, 1460250003Sadrian AR_PHY_BB_DPLL1_NFRAC, 0x0); 1461250003Sadrian 1462250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1463250003Sadrian AR_PHY_BB_DPLL2_OUTDIV, 0x1); 1464250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1465250003Sadrian AR_PHY_BB_DPLL2_LOCAL_PLL, 0x1); 1466250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1467250003Sadrian AR_PHY_BB_DPLL2_EN_NEGTRIG, 0x1); 1468250003Sadrian 1469250003Sadrian /* program BB PLL phase_shift to 0x6 */ 1470250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, 1471250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, 0x6); 1472250003Sadrian 1473250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1474250003Sadrian AR_PHY_BB_DPLL2_PLL_PWD, 0x0); 1475250003Sadrian OS_DELAY(1000); 1476250003Sadrian 1477250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); 1478250003Sadrian OS_DELAY(1000); 1479250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 1480250003Sadrian#define SRIF_PLL 1 1481250003Sadrian u_int32_t regdata, pll2_divint, pll2_divfrac; 1482250003Sadrian 1483250003Sadrian#ifndef SRIF_PLL 1484250003Sadrian u_int32_t pll2_clkmode; 1485250003Sadrian#endif 1486250003Sadrian 1487250003Sadrian#ifdef SRIF_PLL 1488250003Sadrian u_int32_t refdiv; 1489250003Sadrian#endif 1490250003Sadrian if (clk_25mhz) { 1491250003Sadrian#ifndef SRIF_PLL 1492250003Sadrian pll2_divint = 0x1c; 1493250003Sadrian pll2_divfrac = 0xa3d7; 1494250003Sadrian#else 1495250003Sadrian pll2_divint = 0x54; 1496250003Sadrian pll2_divfrac = 0x1eb85; 1497250003Sadrian refdiv = 3; 1498250003Sadrian#endif 1499250003Sadrian } else { 1500250003Sadrian#ifndef SRIF_PLL 1501250003Sadrian pll2_divint = 0x11; 1502250003Sadrian pll2_divfrac = 0x26666; 1503250003Sadrian#else 1504250003Sadrian if (AR_SREV_WASP(ah)) { 1505250003Sadrian pll2_divint = 88; 1506250003Sadrian pll2_divfrac = 0; 1507250003Sadrian refdiv = 5; 1508250003Sadrian } else { 1509250003Sadrian pll2_divint = 0x11; 1510250003Sadrian pll2_divfrac = 0x26666; 1511250003Sadrian refdiv = 1; 1512250003Sadrian } 1513250003Sadrian#endif 1514250003Sadrian } 1515250003Sadrian#ifndef SRIF_PLL 1516250003Sadrian pll2_clkmode = 0x3d; 1517250003Sadrian#endif 1518250003Sadrian /* PLL programming through SRIF Local Mode */ 1519250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); /* Bypass mode */ 1520250003Sadrian OS_DELAY(1000); 1521250003Sadrian do { 1522250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); 1523250003Sadrian regdata = regdata | (0x1 << 16); 1524250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 1 */ 1525250003Sadrian OS_DELAY(100); 1526250003Sadrian /* override int, frac, refdiv */ 1527250003Sadrian#ifndef SRIF_PLL 1528250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL, 1529250003Sadrian ((1 << 27) | (pll2_divint << 18) | pll2_divfrac)); 1530250003Sadrian#else 1531250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL, 1532250003Sadrian ((refdiv << 27) | (pll2_divint << 18) | pll2_divfrac)); 1533250003Sadrian#endif 1534250003Sadrian OS_DELAY(100); 1535250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); 1536250003Sadrian#ifndef SRIF_PLL 1537250003Sadrian regdata = (regdata & 0x80071fff) | 1538250003Sadrian (0x1 << 30) | (0x1 << 13) | (0x6 << 26) | (pll2_clkmode << 19); 1539250003Sadrian#else 1540250003Sadrian if (AR_SREV_WASP(ah)) { 1541250003Sadrian regdata = (regdata & 0x80071fff) | 1542250003Sadrian (0x1 << 30) | (0x1 << 13) | (0x4 << 26) | (0x18 << 19); 1543250003Sadrian } else { 1544250003Sadrian regdata = (regdata & 0x80071fff) | 1545250003Sadrian (0x3 << 30) | (0x1 << 13) | (0x4 << 26) | (0x60 << 19); 1546250003Sadrian } 1547250003Sadrian#endif 1548250003Sadrian /* Ki, Kd, Local PLL, Outdiv */ 1549250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); 1550250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); 1551250003Sadrian regdata = (regdata & 0xfffeffff); 1552250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 0 */ 1553250003Sadrian OS_DELAY(1000); 1554250003Sadrian if (AR_SREV_WASP(ah)) { 1555250003Sadrian /* clear do measure */ 1556250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); 1557250003Sadrian regdata &= ~(1 << 30); 1558250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); 1559250003Sadrian OS_DELAY(100); 1560250003Sadrian 1561250003Sadrian /* set do measure */ 1562250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); 1563250003Sadrian regdata |= (1 << 30); 1564250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); 1565250003Sadrian 1566250003Sadrian /* wait for measure done */ 1567250003Sadrian do { 1568250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL4); 1569250003Sadrian } while ((regdata & (1 << 3)) == 0); 1570250003Sadrian 1571250003Sadrian /* clear do measure */ 1572250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); 1573250003Sadrian regdata &= ~(1 << 30); 1574250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); 1575250003Sadrian 1576250003Sadrian /* get measure sqsum dvc */ 1577250003Sadrian regdata = (OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3) & 0x007FFFF8) >> 3; 1578250003Sadrian } else { 1579250003Sadrian break; 1580250003Sadrian } 1581250003Sadrian } while (regdata >= 0x40000); 1582250003Sadrian 1583250003Sadrian /* Remove from Bypass mode */ 1584250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); 1585250003Sadrian OS_DELAY(1000); 1586250003Sadrian } else { 1587250003Sadrian pll = SM(0x5, AR_RTC_PLL_REFDIV); 1588250003Sadrian 1589250003Sadrian /* Supposedly not needed on Osprey */ 1590250003Sadrian#if 0 1591250003Sadrian if (chan && IS_CHAN_HALF_RATE(chan)) { 1592250003Sadrian pll |= SM(0x1, AR_RTC_PLL_CLKSEL); 1593250003Sadrian } else if (chan && IS_CHAN_QUARTER_RATE(chan)) { 1594250003Sadrian pll |= SM(0x2, AR_RTC_PLL_CLKSEL); 1595250003Sadrian } 1596250003Sadrian#endif 1597250008Sadrian if (ichan && IS_CHAN_5GHZ(ichan)) { 1598250003Sadrian pll |= SM(0x28, AR_RTC_PLL_DIV); 1599250003Sadrian /* 1600250003Sadrian * When doing fast clock, set PLL to 0x142c 1601250003Sadrian */ 1602250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { 1603250003Sadrian pll = 0x142c; 1604250003Sadrian } 1605250003Sadrian } else { 1606250003Sadrian pll |= SM(0x2c, AR_RTC_PLL_DIV); 1607250003Sadrian } 1608250003Sadrian 1609250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); 1610250003Sadrian } 1611250003Sadrian 1612250003Sadrian /* TODO: 1613250003Sadrian * For multi-band owl, switch between bands by reiniting the PLL. 1614250003Sadrian */ 1615250003Sadrian OS_DELAY(RTC_PLL_SETTLE_DELAY); 1616250003Sadrian 1617250003Sadrian OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, 1618250003Sadrian AR_RTC_FORCE_DERIVED_CLK | AR_RTC_PCIE_RST_PWDN_EN); 1619250003Sadrian 1620250003Sadrian if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 1621250003Sadrian if (clk_25mhz) { 1622250003Sadrian OS_REG_WRITE(ah, 1623250003Sadrian AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); /* 32KHz sleep clk */ 1624250003Sadrian OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); 1625250003Sadrian OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); 1626250003Sadrian } else { 1627250003Sadrian OS_REG_WRITE(ah, 1628250003Sadrian AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); /* 32KHz sleep clk */ 1629250003Sadrian OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); 1630250003Sadrian OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); 1631250003Sadrian } 1632250003Sadrian OS_DELAY(100); 1633250003Sadrian } 1634250003Sadrian} 1635250003Sadrian 1636250003Sadrianstatic inline HAL_BOOL 1637250003Sadrianar9300_set_reset(struct ath_hal *ah, int type) 1638250003Sadrian{ 1639250003Sadrian u_int32_t rst_flags; 1640250003Sadrian u_int32_t tmp_reg; 1641278741Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1642250003Sadrian 1643250003Sadrian HALASSERT(type == HAL_RESET_WARM || type == HAL_RESET_COLD); 1644250003Sadrian 1645250003Sadrian /* 1646250003Sadrian * RTC Force wake should be done before resetting the MAC. 1647250003Sadrian * MDK/ART does it that way. 1648250003Sadrian */ 1649250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); 1650250003Sadrian OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ 1651250003Sadrian OS_REG_WRITE(ah, 1652250003Sadrian AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); 1653250003Sadrian 1654250003Sadrian /* Reset AHB */ 1655250003Sadrian /* Bug26871 */ 1656250003Sadrian tmp_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)); 1657250003Sadrian if (AR_SREV_WASP(ah)) { 1658250003Sadrian if (tmp_reg & (AR9340_INTR_SYNC_LOCAL_TIMEOUT)) { 1659250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); 1660250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); 1661250003Sadrian } 1662250003Sadrian } else { 1663250003Sadrian if (tmp_reg & (AR9300_INTR_SYNC_LOCAL_TIMEOUT | AR9300_INTR_SYNC_RADM_CPL_TIMEOUT)) { 1664250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); 1665250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); 1666250003Sadrian } 1667250003Sadrian else { 1668250003Sadrian /* NO AR_RC_AHB in Osprey */ 1669250003Sadrian /*OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_AHB);*/ 1670250003Sadrian } 1671250003Sadrian } 1672250003Sadrian 1673250003Sadrian rst_flags = AR_RTC_RC_MAC_WARM; 1674250003Sadrian if (type == HAL_RESET_COLD) { 1675250003Sadrian rst_flags |= AR_RTC_RC_MAC_COLD; 1676250003Sadrian } 1677250003Sadrian 1678250003Sadrian#ifdef AH_SUPPORT_HORNET 1679250003Sadrian /* Hornet WAR: trigger SoC to reset WMAC if ... 1680250003Sadrian * (1) doing cold reset. Ref: EV 69254 1681250003Sadrian * (2) beacon pending. Ref: EV 70983 1682250003Sadrian */ 1683250003Sadrian if (AR_SREV_HORNET(ah) && 1684250003Sadrian (ar9300_num_tx_pending( 1685250008Sadrian ah, AH_PRIVATE(ah)->ah_caps.halTotalQueues - 1) != 0 || 1686250003Sadrian type == HAL_RESET_COLD)) 1687250003Sadrian { 1688250003Sadrian u_int32_t time_out; 1689250003Sadrian#define AR_SOC_RST_RESET 0xB806001C 1690250003Sadrian#define AR_SOC_BOOT_STRAP 0xB80600AC 1691250003Sadrian#define AR_SOC_WLAN_RST 0x00000800 /* WLAN reset */ 1692250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 1693250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 1694250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Hornet SoC reset WMAC.\n", __func__); 1695250003Sadrian 1696250003Sadrian REG_WRITE(AR_SOC_RST_RESET, 1697250003Sadrian REG_READ(AR_SOC_RST_RESET) | AR_SOC_WLAN_RST); 1698250003Sadrian REG_WRITE(AR_SOC_RST_RESET, 1699250003Sadrian REG_READ(AR_SOC_RST_RESET) & (~AR_SOC_WLAN_RST)); 1700250003Sadrian 1701250003Sadrian time_out = 0; 1702250003Sadrian 1703250003Sadrian while (1) { 1704250003Sadrian tmp_reg = REG_READ(AR_SOC_BOOT_STRAP); 1705250003Sadrian if ((tmp_reg & 0x10) == 0) { 1706250003Sadrian break; 1707250003Sadrian } 1708250003Sadrian if (time_out > 20) { 1709250003Sadrian break; 1710250003Sadrian } 1711250003Sadrian OS_DELAY(10000); 1712250003Sadrian time_out++; 1713250003Sadrian } 1714250003Sadrian 1715250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 1716250003Sadrian#undef REG_READ 1717250003Sadrian#undef REG_WRITE 1718250003Sadrian#undef AR_SOC_WLAN_RST 1719250003Sadrian#undef AR_SOC_RST_RESET 1720250003Sadrian#undef AR_SOC_BOOT_STRAP 1721250003Sadrian } 1722250003Sadrian#endif /* AH_SUPPORT_HORNET */ 1723250003Sadrian 1724250003Sadrian#ifdef AH_SUPPORT_SCORPION 1725250003Sadrian if (AR_SREV_SCORPION(ah)) { 1726250003Sadrian#define DDR_CTL_CONFIG_ADDRESS 0xb8000000 1727250003Sadrian#define DDR_CTL_CONFIG_OFFSET 0x0108 1728250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MSB 29 1729250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB 21 1730250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK 0x3fe00000 1731250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(x) (((x) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) >> DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) 1732250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_SET(x) (((x) << DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) 1733250003Sadrian#define MAC_DMA_CFG_ADDRESS 0xb8100000 1734250003Sadrian#define MAC_DMA_CFG_OFFSET 0x0014 1735250003Sadrian 1736250003Sadrian#define MAC_DMA_CFG_HALT_REQ_MSB 11 1737250003Sadrian#define MAC_DMA_CFG_HALT_REQ_LSB 11 1738250003Sadrian#define MAC_DMA_CFG_HALT_REQ_MASK 0x00000800 1739250003Sadrian#define MAC_DMA_CFG_HALT_REQ_GET(x) (((x) & MAC_DMA_CFG_HALT_REQ_MASK) >> MAC_DMA_CFG_HALT_REQ_LSB) 1740250003Sadrian#define MAC_DMA_CFG_HALT_REQ_SET(x) (((x) << MAC_DMA_CFG_HALT_REQ_LSB) & MAC_DMA_CFG_HALT_REQ_MASK) 1741250003Sadrian#define MAC_DMA_CFG_HALT_ACK_MSB 12 1742250003Sadrian#define MAC_DMA_CFG_HALT_ACK_LSB 12 1743250003Sadrian#define MAC_DMA_CFG_HALT_ACK_MASK 0x00001000 1744250003Sadrian#define MAC_DMA_CFG_HALT_ACK_GET(x) (((x) & MAC_DMA_CFG_HALT_ACK_MASK) >> MAC_DMA_CFG_HALT_ACK_LSB) 1745250003Sadrian#define MAC_DMA_CFG_HALT_ACK_SET(x) (((x) << MAC_DMA_CFG_HALT_ACK_LSB) & MAC_DMA_CFG_HALT_ACK_MASK) 1746250003Sadrian 1747250003Sadrian#define RST_RESET 0xB806001c 1748250003Sadrian#define RTC_RESET (1<<27) 1749250003Sadrian 1750250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 1751250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 1752250003Sadrian 1753250003Sadrian#define DDR_REG_READ(_ah, _reg) \ 1754250003Sadrian *((volatile u_int32_t *)( DDR_CTL_CONFIG_ADDRESS + (_reg))) 1755250003Sadrian#define DDR_REG_WRITE(_ah, _reg, _val) \ 1756250003Sadrian *((volatile u_int32_t *)(DDR_CTL_CONFIG_ADDRESS + (_reg))) = (_val) 1757250003Sadrian 1758250003Sadrian OS_REG_WRITE(ah,MAC_DMA_CFG_OFFSET, (OS_REG_READ(ah,MAC_DMA_CFG_OFFSET) & ~MAC_DMA_CFG_HALT_REQ_MASK) | 1759250003Sadrian MAC_DMA_CFG_HALT_REQ_SET(1)); 1760250003Sadrian 1761250003Sadrian { 1762250003Sadrian int count; 1763250003Sadrian u_int32_t data; 1764250003Sadrian 1765250003Sadrian count = 0; 1766250003Sadrian while (!MAC_DMA_CFG_HALT_ACK_GET(OS_REG_READ(ah, MAC_DMA_CFG_OFFSET) )) 1767250003Sadrian { 1768250003Sadrian count++; 1769250003Sadrian if (count > 10) { 1770250003Sadrian ath_hal_printf(ah, "Halt ACK timeout\n"); 1771250003Sadrian break; 1772250003Sadrian } 1773250003Sadrian OS_DELAY(10); 1774250003Sadrian } 1775250003Sadrian 1776250003Sadrian data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET); 1777250003Sadrian ath_hal_printf(ah, "check DDR Activity - HIGH\n"); 1778250003Sadrian 1779250003Sadrian count = 0; 1780250003Sadrian while (DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(data)) { 1781250003Sadrian // AVE_DEBUG(0,"DDR Activity - HIGH\n"); 1782250003Sadrian ath_hal_printf(ah, "DDR Activity - HIGH\n"); 1783250003Sadrian count++; 1784250003Sadrian OS_DELAY(10); 1785250003Sadrian data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET); 1786250003Sadrian if (count > 10) { 1787250003Sadrian ath_hal_printf(ah, "DDR Activity timeout\n"); 1788250003Sadrian break; 1789250003Sadrian } 1790250003Sadrian } 1791250003Sadrian } 1792250003Sadrian 1793250003Sadrian 1794250003Sadrian { 1795250003Sadrian //Force RTC reset 1796250003Sadrian REG_WRITE(RST_RESET, (REG_READ(RST_RESET) | RTC_RESET)); 1797250003Sadrian OS_DELAY(10); 1798250003Sadrian REG_WRITE(RST_RESET, (REG_READ(RST_RESET) & ~RTC_RESET)); 1799250003Sadrian OS_DELAY(10); 1800250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 0); 1801250003Sadrian OS_DELAY(10); 1802250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 1803250003Sadrian OS_DELAY(10); 1804250003Sadrian ath_hal_printf(ah,"%s: Scorpion SoC RTC reset done.\n", __func__); 1805250003Sadrian } 1806250003Sadrian#undef REG_READ 1807250003Sadrian#undef REG_WRITE 1808250003Sadrian } 1809250003Sadrian#endif /* AH_SUPPORT_SCORPION */ 1810250003Sadrian 1811250003Sadrian /* 1812250003Sadrian * Set Mac(BB,Phy) Warm Reset 1813250003Sadrian */ 1814250003Sadrian OS_REG_WRITE(ah, AR_RTC_RC, rst_flags); 1815250003Sadrian 1816250003Sadrian OS_DELAY(50); /* XXX 50 usec */ 1817250003Sadrian 1818250003Sadrian /* 1819250003Sadrian * Clear resets and force wakeup 1820250003Sadrian */ 1821250003Sadrian OS_REG_WRITE(ah, AR_RTC_RC, 0); 1822250008Sadrian if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) { 1823250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1824250003Sadrian "%s: RTC stuck in MAC reset\n", __FUNCTION__); 1825250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1826250003Sadrian "%s: AR_RTC_RC = 0x%x\n", __func__, OS_REG_READ(ah, AR_RTC_RC)); 1827250003Sadrian return AH_FALSE; 1828250003Sadrian } 1829250003Sadrian 1830250003Sadrian /* Clear AHB reset */ 1831250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0); 1832250003Sadrian 1833250003Sadrian ar9300_attach_hw_platform(ah); 1834250003Sadrian 1835278741Sadrian ahp->ah_chip_reset_done = 1; 1836250003Sadrian return AH_TRUE; 1837250003Sadrian} 1838250003Sadrian 1839250003Sadrianstatic inline HAL_BOOL 1840250003Sadrianar9300_set_reset_power_on(struct ath_hal *ah) 1841250003Sadrian{ 1842250003Sadrian /* Force wake */ 1843250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); 1844250003Sadrian OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ 1845250003Sadrian OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, 1846250003Sadrian AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); 1847250003Sadrian /* 1848250003Sadrian * RTC reset and clear. Some delay in between is needed 1849250003Sadrian * to give the chip time to settle. 1850250003Sadrian */ 1851250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 0); 1852250003Sadrian OS_DELAY(2); 1853250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 1854250003Sadrian 1855250003Sadrian /* 1856250003Sadrian * Poll till RTC is ON 1857250003Sadrian */ 1858250003Sadrian if (!ath_hal_wait(ah, 1859250003Sadrian AR_RTC_STATUS, AR_RTC_STATUS_M, 1860250008Sadrian AR_RTC_STATUS_ON)) 1861250003Sadrian { 1862250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1863250008Sadrian "%s: RTC not waking up for %d\n", __FUNCTION__, 1000); 1864250003Sadrian return AH_FALSE; 1865250003Sadrian } 1866250003Sadrian 1867250003Sadrian /* 1868250003Sadrian * Read Revisions from Chip right after RTC is on for the first time. 1869250003Sadrian * This helps us detect the chip type early and initialize it accordingly. 1870250003Sadrian */ 1871250003Sadrian ar9300_read_revisions(ah); 1872250003Sadrian 1873250003Sadrian /* 1874250003Sadrian * Warm reset if we aren't really powering on, 1875250003Sadrian * just restarting the driver. 1876250003Sadrian */ 1877250003Sadrian return ar9300_set_reset(ah, HAL_RESET_WARM); 1878250003Sadrian} 1879250003Sadrian 1880250003Sadrian/* 1881250003Sadrian * Write the given reset bit mask into the reset register 1882250003Sadrian */ 1883250003SadrianHAL_BOOL 1884250003Sadrianar9300_set_reset_reg(struct ath_hal *ah, u_int32_t type) 1885250003Sadrian{ 1886250003Sadrian HAL_BOOL ret = AH_FALSE; 1887250003Sadrian 1888250003Sadrian /* 1889250003Sadrian * Set force wake 1890250003Sadrian */ 1891250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); 1892250003Sadrian OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ 1893250003Sadrian OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, 1894250003Sadrian AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); 1895250003Sadrian 1896250003Sadrian switch (type) { 1897250003Sadrian case HAL_RESET_POWER_ON: 1898250003Sadrian ret = ar9300_set_reset_power_on(ah); 1899250003Sadrian break; 1900250003Sadrian case HAL_RESET_WARM: 1901250003Sadrian case HAL_RESET_COLD: 1902250003Sadrian ret = ar9300_set_reset(ah, type); 1903250003Sadrian break; 1904250003Sadrian default: 1905250003Sadrian break; 1906250003Sadrian } 1907250003Sadrian 1908250003Sadrian#if ATH_SUPPORT_MCI 1909250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { 1910250003Sadrian OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); 1911250003Sadrian } 1912250003Sadrian#endif 1913250003Sadrian 1914250003Sadrian return ret; 1915250003Sadrian} 1916250003Sadrian 1917250003Sadrian/* 1918250003Sadrian * Places the PHY and Radio chips into reset. A full reset 1919250003Sadrian * must be called to leave this state. The PCI/MAC/PCU are 1920250003Sadrian * not placed into reset as we must receive interrupt to 1921250003Sadrian * re-enable the hardware. 1922250003Sadrian */ 1923250003SadrianHAL_BOOL 1924250003Sadrianar9300_phy_disable(struct ath_hal *ah) 1925250003Sadrian{ 1926250003Sadrian if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) { 1927250003Sadrian return AH_FALSE; 1928250003Sadrian } 1929250003Sadrian 1930250003Sadrian#ifdef ATH_SUPPORT_LED 1931250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 1932250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 1933250003Sadrian#define ATH_GPIO_OE 0xB8040000 1934250003Sadrian#define ATH_GPIO_OUT 0xB8040008 /* GPIO Ouput Value reg.*/ 1935250003Sadrian if (AR_SREV_WASP(ah)) { 1936250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 1937250003Sadrian REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13))); 1938250003Sadrian } 1939250003Sadrian else { 1940250003Sadrian REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12))); 1941250003Sadrian } 1942250003Sadrian } 1943250003Sadrian else if (AR_SREV_SCORPION(ah)) { 1944250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 1945250003Sadrian REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13))); 1946250003Sadrian } 1947250003Sadrian else { 1948250003Sadrian REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12))); 1949250003Sadrian } 1950250003Sadrian /* Turn off JMPST led */ 1951250003Sadrian REG_WRITE(ATH_GPIO_OUT, (REG_READ(ATH_GPIO_OUT) | (0x1 << 15))); 1952250003Sadrian } 1953250003Sadrian#undef REG_READ 1954250003Sadrian#undef REG_WRITE 1955250003Sadrian#endif 1956250003Sadrian 1957250003Sadrian if ( AR_SREV_OSPREY(ah) ) { 1958250003Sadrian OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1), 0x0, 0x1f); 1959250003Sadrian } 1960250003Sadrian 1961250003Sadrian 1962250003Sadrian ar9300_init_pll(ah, AH_NULL); 1963250003Sadrian 1964250003Sadrian return AH_TRUE; 1965250003Sadrian} 1966250003Sadrian 1967250003Sadrian/* 1968250003Sadrian * Places all of hardware into reset 1969250003Sadrian */ 1970250003SadrianHAL_BOOL 1971250003Sadrianar9300_disable(struct ath_hal *ah) 1972250003Sadrian{ 1973250003Sadrian if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { 1974250003Sadrian return AH_FALSE; 1975250003Sadrian } 1976250003Sadrian if (!ar9300_set_reset_reg(ah, HAL_RESET_COLD)) { 1977250003Sadrian return AH_FALSE; 1978250003Sadrian } 1979250003Sadrian 1980250003Sadrian ar9300_init_pll(ah, AH_NULL); 1981250003Sadrian 1982250003Sadrian return AH_TRUE; 1983250003Sadrian} 1984250003Sadrian 1985250003Sadrian/* 1986250003Sadrian * TODO: Only write the PLL if we're changing to or from CCK mode 1987250003Sadrian * 1988250003Sadrian * WARNING: The order of the PLL and mode registers must be correct. 1989250003Sadrian */ 1990250003Sadrianstatic inline void 1991250008Sadrianar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan) 1992250003Sadrian{ 1993250003Sadrian u_int32_t rf_mode = 0; 1994250003Sadrian 1995250003Sadrian if (chan == AH_NULL) { 1996250003Sadrian return; 1997250003Sadrian } 1998250003Sadrian switch (AH9300(ah)->ah_hwp) { 1999250003Sadrian case HAL_TRUE_CHIP: 2000250008Sadrian rf_mode |= (IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_G(chan)) ? 2001250003Sadrian AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; 2002250003Sadrian break; 2003250003Sadrian default: 2004250003Sadrian HALASSERT(0); 2005250003Sadrian break; 2006250003Sadrian } 2007250003Sadrian /* Phy mode bits for 5GHz channels requiring Fast Clock */ 2008250003Sadrian if ( IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { 2009250003Sadrian rf_mode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); 2010250003Sadrian } 2011250003Sadrian OS_REG_WRITE(ah, AR_PHY_MODE, rf_mode); 2012250003Sadrian} 2013250003Sadrian 2014250003Sadrian/* 2015250003Sadrian * Places the hardware into reset and then pulls it out of reset 2016250003Sadrian */ 2017250003SadrianHAL_BOOL 2018250008Sadrianar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan) 2019250003Sadrian{ 2020250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2021269748Sadrian int type = HAL_RESET_WARM; 2022250003Sadrian 2023250008Sadrian OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0); 2024250008Sadrian 2025250003Sadrian /* 2026250003Sadrian * Warm reset is optimistic. 2027269748Sadrian * 2028269748Sadrian * If the TX/RX DMA engines aren't shut down (eg, they're 2029269748Sadrian * wedged) then we're better off doing a full cold reset 2030269748Sadrian * to try and shake that condition. 2031250003Sadrian */ 2032269748Sadrian if (ahp->ah_chip_full_sleep || 2033269748Sadrian (ah->ah_config.ah_force_full_reset == 1) || 2034269748Sadrian OS_REG_READ(ah, AR_Q_TXE) || 2035269748Sadrian (OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) { 2036269748Sadrian type = HAL_RESET_COLD; 2037269748Sadrian } 2038269748Sadrian 2039269748Sadrian if (!ar9300_set_reset_reg(ah, type)) { 2040250003Sadrian return AH_FALSE; 2041250003Sadrian } 2042250003Sadrian 2043250003Sadrian /* Bring out of sleep mode (AGAIN) */ 2044250003Sadrian if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { 2045250003Sadrian return AH_FALSE; 2046250003Sadrian } 2047250003Sadrian 2048250003Sadrian ahp->ah_chip_full_sleep = AH_FALSE; 2049250003Sadrian 2050250003Sadrian if (AR_SREV_HORNET(ah)) { 2051250003Sadrian ar9300_internal_regulator_apply(ah); 2052250003Sadrian } 2053250003Sadrian 2054250003Sadrian ar9300_init_pll(ah, chan); 2055250003Sadrian 2056250003Sadrian /* 2057250003Sadrian * Perform warm reset before the mode/PLL/turbo registers 2058250003Sadrian * are changed in order to deactivate the radio. Mode changes 2059250003Sadrian * with an active radio can result in corrupted shifts to the 2060250003Sadrian * radio device. 2061250003Sadrian */ 2062250003Sadrian ar9300_set_rf_mode(ah, chan); 2063250003Sadrian 2064250003Sadrian return AH_TRUE; 2065250003Sadrian} 2066250003Sadrian 2067250003Sadrian/* ar9300_setup_calibration 2068250003Sadrian * Setup HW to collect samples used for current cal 2069250003Sadrian */ 2070250003Sadrianinline static void 2071250003Sadrianar9300_setup_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal) 2072250003Sadrian{ 2073250003Sadrian /* Select calibration to run */ 2074250003Sadrian switch (curr_cal->cal_data->cal_type) { 2075250003Sadrian case IQ_MISMATCH_CAL: 2076250003Sadrian /* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ 2077250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, 2078250003Sadrian AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, 2079250003Sadrian curr_cal->cal_data->cal_count_max); 2080250003Sadrian OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 2081250003Sadrian 2082250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2083250003Sadrian "%s: starting IQ Mismatch Calibration\n", __func__); 2084250003Sadrian 2085250003Sadrian /* Kick-off cal */ 2086250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); 2087250003Sadrian 2088250003Sadrian break; 2089250003Sadrian case TEMP_COMP_CAL: 2090250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || 2091250003Sadrian AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 2092250003Sadrian OS_REG_RMW_FIELD(ah, 2093250003Sadrian AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2094250003Sadrian OS_REG_RMW_FIELD(ah, 2095250003Sadrian AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); 2096250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 2097250003Sadrian OS_REG_RMW_FIELD(ah, 2098250003Sadrian AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2099250003Sadrian OS_REG_RMW_FIELD(ah, 2100250003Sadrian AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_START, 1); 2101250003Sadrian } else { 2102250003Sadrian OS_REG_RMW_FIELD(ah, 2103250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2104250003Sadrian OS_REG_RMW_FIELD(ah, 2105250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); 2106250003Sadrian } 2107250003Sadrian 2108250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2109250003Sadrian "%s: starting Temperature Compensation Calibration\n", __func__); 2110250003Sadrian break; 2111250003Sadrian default: 2112250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 2113250003Sadrian "%s called with incorrect calibration type.\n", __func__); 2114250003Sadrian } 2115250003Sadrian} 2116250003Sadrian 2117250003Sadrian/* ar9300_reset_calibration 2118250003Sadrian * Initialize shared data structures and prepare a cal to be run. 2119250003Sadrian */ 2120250003Sadrianinline static void 2121250003Sadrianar9300_reset_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal) 2122250003Sadrian{ 2123250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2124250003Sadrian int i; 2125250003Sadrian 2126250003Sadrian /* Setup HW for new calibration */ 2127250003Sadrian ar9300_setup_calibration(ah, curr_cal); 2128250003Sadrian 2129250003Sadrian /* Change SW state to RUNNING for this calibration */ 2130250003Sadrian curr_cal->cal_state = CAL_RUNNING; 2131250003Sadrian 2132250003Sadrian /* Reset data structures shared between different calibrations */ 2133250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 2134250003Sadrian ahp->ah_meas0.sign[i] = 0; 2135250003Sadrian ahp->ah_meas1.sign[i] = 0; 2136250003Sadrian ahp->ah_meas2.sign[i] = 0; 2137250003Sadrian ahp->ah_meas3.sign[i] = 0; 2138250003Sadrian } 2139250003Sadrian 2140250003Sadrian ahp->ah_cal_samples = 0; 2141250003Sadrian} 2142250003Sadrian 2143250003Sadrian#ifdef XXX_UNUSED_FUNCTION 2144250003Sadrian/* 2145250003Sadrian * Find out which of the RX chains are enabled 2146250003Sadrian */ 2147250003Sadrianstatic u_int32_t 2148250003Sadrianar9300_get_rx_chain_mask(struct ath_hal *ah) 2149250003Sadrian{ 2150250003Sadrian u_int32_t ret_val = OS_REG_READ(ah, AR_PHY_RX_CHAINMASK); 2151250003Sadrian /* The bits [2:0] indicate the rx chain mask and are to be 2152250003Sadrian * interpreted as follows: 2153250003Sadrian * 00x => Only chain 0 is enabled 2154250003Sadrian * 01x => Chain 1 and 0 enabled 2155250003Sadrian * 1xx => Chain 2,1 and 0 enabled 2156250003Sadrian */ 2157250003Sadrian return (ret_val & 0x7); 2158250003Sadrian} 2159250003Sadrian#endif 2160250003Sadrian 2161250003Sadrianstatic void 2162250003Sadrianar9300_get_nf_hist_base(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, 2163250003Sadrian int is_scan, int16_t nf[]) 2164250003Sadrian{ 2165250003Sadrian HAL_NFCAL_BASE *h_base; 2166250003Sadrian 2167250003Sadrian#ifdef ATH_NF_PER_CHAN 2168250003Sadrian h_base = &chan->nf_cal_hist.base; 2169250003Sadrian#else 2170250003Sadrian if (is_scan) { 2171250003Sadrian /* 2172250003Sadrian * The channel we are currently on is not the home channel, 2173250003Sadrian * so we shouldn't use the home channel NF buffer's values on 2174250003Sadrian * this channel. Instead, use the NF single value already 2175250003Sadrian * read for this channel. (Or, if we haven't read the NF for 2176250003Sadrian * this channel yet, the SW default for this chip/band will 2177250003Sadrian * be used.) 2178250003Sadrian */ 2179250003Sadrian h_base = &chan->nf_cal_hist.base; 2180250003Sadrian } else { 2181250003Sadrian /* use the home channel NF info */ 2182250003Sadrian h_base = &AH_PRIVATE(ah)->nf_cal_hist.base; 2183250003Sadrian } 2184250003Sadrian#endif 2185250003Sadrian OS_MEMCPY(nf, h_base->priv_nf, sizeof(h_base->priv_nf)); 2186250003Sadrian} 2187250003Sadrian 2188250003SadrianHAL_BOOL 2189250003Sadrianar9300_load_nf(struct ath_hal *ah, int16_t nf[]) 2190250003Sadrian{ 2191250003Sadrian int i, j; 2192250003Sadrian int32_t val; 2193250003Sadrian /* XXX where are EXT regs defined */ 2194250003Sadrian const u_int32_t ar9300_cca_regs[] = { 2195250003Sadrian AR_PHY_CCA_0, 2196250003Sadrian AR_PHY_CCA_1, 2197250003Sadrian AR_PHY_CCA_2, 2198250003Sadrian AR_PHY_EXT_CCA, 2199250003Sadrian AR_PHY_EXT_CCA_1, 2200250003Sadrian AR_PHY_EXT_CCA_2, 2201250003Sadrian }; 2202250003Sadrian u_int8_t chainmask; 2203250003Sadrian 2204250003Sadrian /* 2205250003Sadrian * Force NF calibration for all chains, otherwise Vista station 2206250003Sadrian * would conduct a bad performance 2207250003Sadrian */ 2208250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 2209250003Sadrian chainmask = 0x9; 2210250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { 2211250003Sadrian chainmask = 0x1b; 2212250003Sadrian } else { 2213250003Sadrian chainmask = 0x3F; 2214250003Sadrian } 2215250003Sadrian 2216250003Sadrian /* 2217250003Sadrian * Write filtered NF values into max_cca_pwr register parameter 2218250003Sadrian * so we can load below. 2219250003Sadrian */ 2220250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 2221250003Sadrian if (chainmask & (1 << i)) { 2222250003Sadrian val = OS_REG_READ(ah, ar9300_cca_regs[i]); 2223250003Sadrian val &= 0xFFFFFE00; 2224250003Sadrian val |= (((u_int32_t)(nf[i]) << 1) & 0x1ff); 2225250003Sadrian OS_REG_WRITE(ah, ar9300_cca_regs[i], val); 2226250003Sadrian } 2227250003Sadrian } 2228250003Sadrian 2229250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s: load %d %d %d %d %d %d\n", 2230250008Sadrian __func__, 2231250008Sadrian nf[0], nf[1], nf[2], 2232250008Sadrian nf[3], nf[4], nf[5]); 2233250008Sadrian 2234250003Sadrian /* 2235250003Sadrian * Load software filtered NF value into baseband internal min_cca_pwr 2236250003Sadrian * variable. 2237250003Sadrian */ 2238250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); 2239250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 2240250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 2241250003Sadrian 2242250003Sadrian /* Wait for load to complete, should be fast, a few 10s of us. */ 2243250003Sadrian /* Changed the max delay 250us back to 10000us, since 250us often 2244250003Sadrian * results in NF load timeout and causes deaf condition 2245250003Sadrian * during stress testing 12/12/2009 2246250003Sadrian */ 2247250003Sadrian for (j = 0; j < 10000; j++) { 2248250003Sadrian if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){ 2249250003Sadrian break; 2250250003Sadrian } 2251250003Sadrian OS_DELAY(10); 2252250003Sadrian } 2253250003Sadrian if (j == 10000) { 2254250003Sadrian /* 2255250003Sadrian * We timed out waiting for the noisefloor to load, probably 2256250003Sadrian * due to an in-progress rx. Simply return here and allow 2257250003Sadrian * the load plenty of time to complete before the next 2258250003Sadrian * calibration interval. We need to avoid trying to load -50 2259250003Sadrian * (which happens below) while the previous load is still in 2260250003Sadrian * progress as this can cause rx deafness (see EV 66368,62830). 2261250003Sadrian * Instead by returning here, the baseband nf cal will 2262250003Sadrian * just be capped by our present noisefloor until the next 2263250003Sadrian * calibration timer. 2264250003Sadrian */ 2265250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 2266250003Sadrian "%s: *** TIMEOUT while waiting for nf to load: " 2267250003Sadrian "AR_PHY_AGC_CONTROL=0x%x ***\n", 2268250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); 2269250003Sadrian return AH_FALSE; 2270250003Sadrian } 2271250003Sadrian 2272250003Sadrian /* 2273250003Sadrian * Restore max_cca_power register parameter again so that we're not capped 2274250003Sadrian * by the median we just loaded. This will be initial (and max) value 2275250003Sadrian * of next noise floor calibration the baseband does. 2276250003Sadrian */ 2277250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 2278250003Sadrian if (chainmask & (1 << i)) { 2279250003Sadrian val = OS_REG_READ(ah, ar9300_cca_regs[i]); 2280250003Sadrian val &= 0xFFFFFE00; 2281250003Sadrian val |= (((u_int32_t)(-50) << 1) & 0x1ff); 2282250003Sadrian OS_REG_WRITE(ah, ar9300_cca_regs[i], val); 2283250003Sadrian } 2284250003Sadrian } 2285250003Sadrian return AH_TRUE; 2286250003Sadrian} 2287250003Sadrian 2288250003Sadrian/* ar9300_per_calibration 2289250003Sadrian * Generic calibration routine. 2290250003Sadrian * Recalibrate the lower PHY chips to account for temperature/environment 2291250003Sadrian * changes. 2292250003Sadrian */ 2293250003Sadrianinline static void 2294250003Sadrianar9300_per_calibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, 2295250003Sadrian u_int8_t rxchainmask, HAL_CAL_LIST *curr_cal, HAL_BOOL *is_cal_done) 2296250003Sadrian{ 2297250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2298250003Sadrian 2299250003Sadrian /* Cal is assumed not done until explicitly set below */ 2300250003Sadrian *is_cal_done = AH_FALSE; 2301250003Sadrian 2302250003Sadrian /* Calibration in progress. */ 2303250003Sadrian if (curr_cal->cal_state == CAL_RUNNING) { 2304250003Sadrian /* Check to see if it has finished. */ 2305250003Sadrian if (!(OS_REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { 2306250003Sadrian int i, num_chains = 0; 2307250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 2308250003Sadrian if (rxchainmask & (1 << i)) { 2309250003Sadrian num_chains++; 2310250003Sadrian } 2311250003Sadrian } 2312250003Sadrian 2313250003Sadrian /* 2314250003Sadrian * Accumulate cal measures for active chains 2315250003Sadrian */ 2316250003Sadrian curr_cal->cal_data->cal_collect(ah, num_chains); 2317250003Sadrian 2318250003Sadrian ahp->ah_cal_samples++; 2319250003Sadrian 2320250003Sadrian if (ahp->ah_cal_samples >= curr_cal->cal_data->cal_num_samples) { 2321250003Sadrian /* 2322250003Sadrian * Process accumulated data 2323250003Sadrian */ 2324250003Sadrian curr_cal->cal_data->cal_post_proc(ah, num_chains); 2325250003Sadrian 2326250003Sadrian /* Calibration has finished. */ 2327250008Sadrian ichan->calValid |= curr_cal->cal_data->cal_type; 2328250003Sadrian curr_cal->cal_state = CAL_DONE; 2329250003Sadrian *is_cal_done = AH_TRUE; 2330250003Sadrian } else { 2331250003Sadrian /* Set-up collection of another sub-sample until we 2332250003Sadrian * get desired number 2333250003Sadrian */ 2334250003Sadrian ar9300_setup_calibration(ah, curr_cal); 2335250003Sadrian } 2336250003Sadrian } 2337250008Sadrian } else if (!(ichan->calValid & curr_cal->cal_data->cal_type)) { 2338250003Sadrian /* If current cal is marked invalid in channel, kick it off */ 2339250003Sadrian ar9300_reset_calibration(ah, curr_cal); 2340250003Sadrian } 2341250003Sadrian} 2342250003Sadrian 2343250003Sadrianstatic void 2344250003Sadrianar9300_start_nf_cal(struct ath_hal *ah) 2345250003Sadrian{ 2346278741Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2347250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); 2348250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 2349250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 2350250003Sadrian AH9300(ah)->nf_tsf32 = ar9300_get_tsf32(ah); 2351278741Sadrian 2352278741Sadrian/* 2353278741Sadrian * We are reading the NF values before we start the NF operation, because 2354278741Sadrian * of that we are getting very high values like -45. 2355278741Sadrian * This triggers the CW_INT detected and EACS module triggers the channel change 2356278741Sadrian * chip_reset_done value is used to fix this issue. 2357278741Sadrian * chip_reset_flag is set during the RTC reset. 2358278741Sadrian * chip_reset_flag is cleared during the starting NF operation. 2359278741Sadrian * if flag is set we will clear the flag and will not read the NF values. 2360278741Sadrian */ 2361278741Sadrian ahp->ah_chip_reset_done = 0; 2362250003Sadrian} 2363250003Sadrian 2364250003Sadrian/* ar9300_calibration 2365250003Sadrian * Wrapper for a more generic Calibration routine. Primarily to abstract to 2366250003Sadrian * upper layers whether there is 1 or more calibrations to be run. 2367250003Sadrian */ 2368250003SadrianHAL_BOOL 2369250008Sadrianar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask, 2370250003Sadrian HAL_BOOL do_nf_cal, HAL_BOOL *is_cal_done, int is_scan, 2371250003Sadrian u_int32_t *sched_cals) 2372250003Sadrian{ 2373250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2374250003Sadrian HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr; 2375250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2376250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 2377250003Sadrian 2378250003Sadrian *is_cal_done = AH_TRUE; 2379250003Sadrian 2380250003Sadrian 2381250003Sadrian /* XXX: For initial wasp bringup - disable periodic calibration */ 2382250003Sadrian /* Invalid channel check */ 2383250003Sadrian if (ichan == AH_NULL) { 2384250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 2385250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 2386250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 2387250003Sadrian return AH_FALSE; 2388250003Sadrian } 2389250003Sadrian 2390250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2391250003Sadrian "%s: Entering, Doing NF Cal = %d\n", __func__, do_nf_cal); 2392250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 0 Rx IQ Cal Correction 0x%08x\n", 2393250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 2394250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) { 2395250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2396250003Sadrian "%s: Chain 1 Rx IQ Cal Correction 0x%08x\n", 2397250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B1)); 2398250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 2399250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2400250003Sadrian "%s: Chain 2 Rx IQ Cal Correction 0x%08x\n", 2401250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B2)); 2402250003Sadrian } 2403250003Sadrian } 2404250003Sadrian 2405250008Sadrian OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq); 2406250003Sadrian 2407250003Sadrian /* For given calibration: 2408250003Sadrian * 1. Call generic cal routine 2409250003Sadrian * 2. When this cal is done (is_cal_done) if we have more cals waiting 2410250003Sadrian * (eg after reset), mask this to upper layers by not propagating 2411250003Sadrian * is_cal_done if it is set to TRUE. 2412250003Sadrian * Instead, change is_cal_done to FALSE and setup the waiting cal(s) 2413250003Sadrian * to be run. 2414250003Sadrian */ 2415250003Sadrian if (curr_cal && (curr_cal->cal_data->cal_type & *sched_cals) && 2416250003Sadrian (curr_cal->cal_state == CAL_RUNNING || 2417250003Sadrian curr_cal->cal_state == CAL_WAITING)) 2418250003Sadrian { 2419250003Sadrian ar9300_per_calibration(ah, ichan, rxchainmask, curr_cal, is_cal_done); 2420250003Sadrian 2421250003Sadrian if (*is_cal_done == AH_TRUE) { 2422250003Sadrian ahp->ah_cal_list_curr = curr_cal = curr_cal->cal_next; 2423250003Sadrian 2424250003Sadrian if (curr_cal && curr_cal->cal_state == CAL_WAITING) { 2425250003Sadrian *is_cal_done = AH_FALSE; 2426250003Sadrian ar9300_reset_calibration(ah, curr_cal); 2427250003Sadrian } else { 2428250003Sadrian *sched_cals &= ~IQ_MISMATCH_CAL; 2429250003Sadrian } 2430250003Sadrian } 2431250003Sadrian } 2432250003Sadrian 2433250003Sadrian /* Do NF cal only at longer intervals */ 2434250003Sadrian if (do_nf_cal) { 2435250003Sadrian int nf_done; 2436250003Sadrian 2437250003Sadrian /* Get the value from the previous NF cal and update history buffer */ 2438250008Sadrian nf_done = ar9300_store_new_nf(ah, chan, is_scan); 2439250008Sadrian#if 0 2440250003Sadrian if (ichan->channel_flags & CHANNEL_CW_INT) { 2441250003Sadrian chan->channel_flags |= CHANNEL_CW_INT; 2442250003Sadrian } 2443250008Sadrian#endif 2444250008Sadrian chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; 2445250003Sadrian 2446250003Sadrian if (nf_done) { 2447250003Sadrian /* 2448250003Sadrian * Load the NF from history buffer of the current channel. 2449250003Sadrian * NF is slow time-variant, so it is OK to use a historical value. 2450250003Sadrian */ 2451250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 2452250003Sadrian ar9300_load_nf(ah, nf_buf); 2453250003Sadrian 2454250003Sadrian /* start NF calibration, without updating BB NF register*/ 2455278741Sadrian ar9300_start_nf_cal(ah); 2456250003Sadrian } 2457250003Sadrian } 2458250003Sadrian return AH_TRUE; 2459250003Sadrian} 2460250003Sadrian 2461250003Sadrian/* ar9300_iq_cal_collect 2462250003Sadrian * Collect data from HW to later perform IQ Mismatch Calibration 2463250003Sadrian */ 2464250003Sadrianvoid 2465250003Sadrianar9300_iq_cal_collect(struct ath_hal *ah, u_int8_t num_chains) 2466250003Sadrian{ 2467250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2468250003Sadrian int i; 2469250003Sadrian 2470250003Sadrian /* 2471250003Sadrian * Accumulate IQ cal measures for active chains 2472250003Sadrian */ 2473250003Sadrian for (i = 0; i < num_chains; i++) { 2474250003Sadrian ahp->ah_total_power_meas_i[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 2475250003Sadrian ahp->ah_total_power_meas_q[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 2476250003Sadrian ahp->ah_total_iq_corr_meas[i] = 2477250003Sadrian (int32_t) OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 2478250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2479250003Sadrian "%d: Chn %d " 2480250003Sadrian "Reg Offset(0x%04x)pmi=0x%08x; " 2481250003Sadrian "Reg Offset(0x%04x)pmq=0x%08x; " 2482250003Sadrian "Reg Offset (0x%04x)iqcm=0x%08x;\n", 2483250003Sadrian ahp->ah_cal_samples, 2484250003Sadrian i, 2485250003Sadrian (unsigned) AR_PHY_CAL_MEAS_0(i), 2486250003Sadrian ahp->ah_total_power_meas_i[i], 2487250003Sadrian (unsigned) AR_PHY_CAL_MEAS_1(i), 2488250003Sadrian ahp->ah_total_power_meas_q[i], 2489250003Sadrian (unsigned) AR_PHY_CAL_MEAS_2(i), 2490250003Sadrian ahp->ah_total_iq_corr_meas[i]); 2491250003Sadrian } 2492250003Sadrian} 2493250003Sadrian 2494250003Sadrian/* ar9300_iq_calibration 2495250003Sadrian * Use HW data to perform IQ Mismatch Calibration 2496250003Sadrian */ 2497250003Sadrianvoid 2498250003Sadrianar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains) 2499250003Sadrian{ 2500250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2501250003Sadrian u_int32_t power_meas_q, power_meas_i, iq_corr_meas; 2502250003Sadrian u_int32_t q_coff_denom, i_coff_denom; 2503250003Sadrian int32_t q_coff, i_coff; 2504250003Sadrian int iq_corr_neg, i; 2505278741Sadrian HAL_CHANNEL_INTERNAL *ichan; 2506250003Sadrian static const u_int32_t offset_array[3] = { 2507250003Sadrian AR_PHY_RX_IQCAL_CORR_B0, 2508250003Sadrian AR_PHY_RX_IQCAL_CORR_B1, 2509250003Sadrian AR_PHY_RX_IQCAL_CORR_B2, 2510250003Sadrian }; 2511250003Sadrian 2512278741Sadrian ichan = ath_hal_checkchannel(ah, AH_PRIVATE(ah)->ah_curchan); 2513278741Sadrian 2514250003Sadrian for (i = 0; i < num_chains; i++) { 2515250003Sadrian power_meas_i = ahp->ah_total_power_meas_i[i]; 2516250003Sadrian power_meas_q = ahp->ah_total_power_meas_q[i]; 2517250003Sadrian iq_corr_meas = ahp->ah_total_iq_corr_meas[i]; 2518250003Sadrian 2519250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2520250003Sadrian "Starting IQ Cal and Correction for Chain %d\n", i); 2521250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2522250003Sadrian "Orignal: Chn %diq_corr_meas = 0x%08x\n", 2523250003Sadrian i, ahp->ah_total_iq_corr_meas[i]); 2524250003Sadrian 2525250003Sadrian iq_corr_neg = 0; 2526250003Sadrian 2527250003Sadrian /* iq_corr_meas is always negative. */ 2528250003Sadrian if (iq_corr_meas > 0x80000000) { 2529250003Sadrian iq_corr_meas = (0xffffffff - iq_corr_meas) + 1; 2530250003Sadrian iq_corr_neg = 1; 2531250003Sadrian } 2532250003Sadrian 2533250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2534250003Sadrian "Chn %d pwr_meas_i = 0x%08x\n", i, power_meas_i); 2535250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2536250003Sadrian "Chn %d pwr_meas_q = 0x%08x\n", i, power_meas_q); 2537250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2538250003Sadrian "iq_corr_neg is 0x%08x\n", iq_corr_neg); 2539250003Sadrian 2540250003Sadrian i_coff_denom = (power_meas_i / 2 + power_meas_q / 2) / 256; 2541250003Sadrian q_coff_denom = power_meas_q / 64; 2542250003Sadrian 2543250003Sadrian /* Protect against divide-by-0 */ 2544250003Sadrian if ((i_coff_denom != 0) && (q_coff_denom != 0)) { 2545250003Sadrian /* IQ corr_meas is already negated if iqcorr_neg == 1 */ 2546250003Sadrian i_coff = iq_corr_meas / i_coff_denom; 2547250003Sadrian q_coff = power_meas_i / q_coff_denom - 64; 2548250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2549250003Sadrian "Chn %d i_coff = 0x%08x\n", i, i_coff); 2550250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2551250003Sadrian "Chn %d q_coff = 0x%08x\n", i, q_coff); 2552250003Sadrian 2553250003Sadrian /* Force bounds on i_coff */ 2554250003Sadrian if (i_coff >= 63) { 2555250003Sadrian i_coff = 63; 2556250003Sadrian } else if (i_coff <= -63) { 2557250003Sadrian i_coff = -63; 2558250003Sadrian } 2559250003Sadrian 2560250003Sadrian /* Negate i_coff if iq_corr_neg == 0 */ 2561250003Sadrian if (iq_corr_neg == 0x0) { 2562250003Sadrian i_coff = -i_coff; 2563250003Sadrian } 2564250003Sadrian 2565250003Sadrian /* Force bounds on q_coff */ 2566250003Sadrian if (q_coff >= 63) { 2567250003Sadrian q_coff = 63; 2568250003Sadrian } else if (q_coff <= -63) { 2569250003Sadrian q_coff = -63; 2570250003Sadrian } 2571250003Sadrian 2572250003Sadrian i_coff = i_coff & 0x7f; 2573250003Sadrian q_coff = q_coff & 0x7f; 2574250003Sadrian 2575250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2576250003Sadrian "Chn %d : i_coff = 0x%x q_coff = 0x%x\n", i, i_coff, q_coff); 2577250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2578250003Sadrian "Register offset (0x%04x) before update = 0x%x\n", 2579250003Sadrian offset_array[i], OS_REG_READ(ah, offset_array[i])); 2580250003Sadrian 2581250003Sadrian OS_REG_RMW_FIELD(ah, offset_array[i], 2582250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff); 2583250003Sadrian OS_REG_RMW_FIELD(ah, offset_array[i], 2584250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff); 2585250003Sadrian 2586278741Sadrian /* store the RX cal results */ 2587278741Sadrian if (ichan != NULL) { 2588278741Sadrian ahp->ah_rx_cal_corr[i] = OS_REG_READ(ah, offset_array[i]) & 0x7fff; 2589278741Sadrian ahp->ah_rx_cal_complete = AH_TRUE; 2590278741Sadrian ahp->ah_rx_cal_chan = ichan->channel; 2591278741Sadrian// ahp->ah_rx_cal_chan_flag = ichan->channel_flags &~ CHANNEL_PASSIVE; 2592278741Sadrian ahp->ah_rx_cal_chan_flag = 0; /* XXX */ 2593278741Sadrian } else { 2594278741Sadrian /* XXX? Is this what I should do? */ 2595278741Sadrian ahp->ah_rx_cal_complete = AH_FALSE; 2596278741Sadrian 2597278741Sadrian } 2598278741Sadrian 2599250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2600250003Sadrian "Register offset (0x%04x) QI COFF (bitfields 0x%08x) " 2601250003Sadrian "after update = 0x%x\n", 2602250003Sadrian offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 2603250003Sadrian OS_REG_READ(ah, offset_array[i])); 2604250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2605250003Sadrian "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) " 2606250003Sadrian "after update = 0x%x\n", 2607250003Sadrian offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 2608250003Sadrian OS_REG_READ(ah, offset_array[i])); 2609250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2610250003Sadrian "IQ Cal and Correction done for Chain %d\n", i); 2611250003Sadrian } 2612250003Sadrian } 2613250003Sadrian 2614250003Sadrian OS_REG_SET_BIT(ah, 2615250003Sadrian AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); 2616250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2617250003Sadrian "IQ Cal and Correction (offset 0x%04x) enabled " 2618250003Sadrian "(bit position 0x%08x). New Value 0x%08x\n", 2619250003Sadrian (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), 2620250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, 2621250003Sadrian OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 2622250003Sadrian} 2623250003Sadrian 2624250003Sadrian/* 2625278741Sadrian * When coming back from offchan, we do not perform RX IQ Cal. 2626278741Sadrian * But the chip reset will clear all previous results 2627278741Sadrian * We store the previous results and restore here. 2628278741Sadrian */ 2629278741Sadrianstatic void 2630278741Sadrianar9300_rx_iq_cal_restore(struct ath_hal *ah) 2631278741Sadrian{ 2632278741Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2633278741Sadrian u_int32_t i_coff, q_coff; 2634278741Sadrian HAL_BOOL is_restore = AH_FALSE; 2635278741Sadrian int i; 2636278741Sadrian static const u_int32_t offset_array[3] = { 2637278741Sadrian AR_PHY_RX_IQCAL_CORR_B0, 2638278741Sadrian AR_PHY_RX_IQCAL_CORR_B1, 2639278741Sadrian AR_PHY_RX_IQCAL_CORR_B2, 2640278741Sadrian }; 2641278741Sadrian 2642278741Sadrian for (i=0; i<AR9300_MAX_CHAINS; i++) { 2643278741Sadrian if (ahp->ah_rx_cal_corr[i]) { 2644278741Sadrian i_coff = (ahp->ah_rx_cal_corr[i] & 2645278741Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF) >> 2646278741Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S; 2647278741Sadrian q_coff = (ahp->ah_rx_cal_corr[i] & 2648278741Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF) >> 2649278741Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S; 2650278741Sadrian 2651278741Sadrian OS_REG_RMW_FIELD(ah, offset_array[i], 2652278741Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff); 2653278741Sadrian OS_REG_RMW_FIELD(ah, offset_array[i], 2654278741Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff); 2655278741Sadrian 2656278741Sadrian is_restore = AH_TRUE; 2657278741Sadrian } 2658278741Sadrian } 2659278741Sadrian 2660278741Sadrian if (is_restore) 2661278741Sadrian OS_REG_SET_BIT(ah, 2662278741Sadrian AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); 2663278741Sadrian 2664278741Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2665278741Sadrian "%s: IQ Cal and Correction (offset 0x%04x) enabled " 2666278741Sadrian "(bit position 0x%08x). New Value 0x%08x\n", 2667278741Sadrian __func__, 2668278741Sadrian (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), 2669278741Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, 2670278741Sadrian OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 2671278741Sadrian} 2672278741Sadrian 2673278741Sadrian/* 2674250003Sadrian * Set a limit on the overall output power. Used for dynamic 2675250003Sadrian * transmit power control and the like. 2676250003Sadrian * 2677250003Sadrian * NB: limit is in units of 0.5 dbM. 2678250003Sadrian */ 2679250003SadrianHAL_BOOL 2680250003Sadrianar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit, 2681250003Sadrian u_int16_t extra_txpow, u_int16_t tpc_in_db) 2682250003Sadrian{ 2683250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2684250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 2685250008Sadrian const struct ieee80211_channel *chan = ahpriv->ah_curchan; 2686250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2687250003Sadrian 2688250003Sadrian if (NULL == chan) { 2689250008Sadrian return AH_FALSE; 2690250008Sadrian } 2691250003Sadrian 2692250008Sadrian ahpriv->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); 2693250008Sadrian ahpriv->ah_extraTxPow = extra_txpow; 2694250008Sadrian 2695250003Sadrian if(chan == NULL) { 2696250003Sadrian return AH_FALSE; 2697250003Sadrian } 2698250008Sadrian if (ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan, 2699250003Sadrian ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), 2700250003Sadrian ath_hal_get_twice_max_regpower(ahpriv, ichan, chan), 2701250008Sadrian AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)) != HAL_OK) 2702250003Sadrian { 2703250003Sadrian return AH_FALSE; 2704250003Sadrian } 2705250003Sadrian return AH_TRUE; 2706250003Sadrian} 2707250003Sadrian 2708250003Sadrian/* 2709250003Sadrian * Exported call to check for a recent gain reading and return 2710250003Sadrian * the current state of the thermal calibration gain engine. 2711250003Sadrian */ 2712250003SadrianHAL_RFGAIN 2713250003Sadrianar9300_get_rfgain(struct ath_hal *ah) 2714250003Sadrian{ 2715250003Sadrian return HAL_RFGAIN_INACTIVE; 2716250003Sadrian} 2717250003Sadrian 2718250003Sadrian#define HAL_GREEN_AP_RX_MASK 0x1 2719250003Sadrian 2720250003Sadrianstatic inline void 2721250003Sadrianar9300_init_chain_masks(struct ath_hal *ah, int rx_chainmask, int tx_chainmask) 2722250003Sadrian{ 2723250008Sadrian if (AH9300(ah)->green_ap_ps_on) { 2724250003Sadrian rx_chainmask = HAL_GREEN_AP_RX_MASK; 2725250003Sadrian } 2726250003Sadrian if (rx_chainmask == 0x5) { 2727250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); 2728250003Sadrian } 2729250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 2730250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 2731250003Sadrian 2732250003Sadrian /* 2733250003Sadrian * Adaptive Power Management: 2734250003Sadrian * Some 3 stream chips exceed the PCIe power requirements. 2735250003Sadrian * This workaround will reduce power consumption by using 2 tx chains 2736250003Sadrian * for 1 and 2 stream rates (5 GHz only). 2737250003Sadrian * 2738250003Sadrian * Set the self gen mask to 2 tx chains when APM is enabled. 2739250003Sadrian * 2740250003Sadrian */ 2741250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halApmEnable && (tx_chainmask == 0x7)) { 2742250003Sadrian OS_REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); 2743250003Sadrian } 2744250003Sadrian else { 2745250003Sadrian OS_REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); 2746250003Sadrian } 2747250003Sadrian 2748250003Sadrian if (tx_chainmask == 0x5) { 2749250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); 2750250003Sadrian } 2751250003Sadrian} 2752250003Sadrian 2753250003Sadrian/* 2754250003Sadrian * Override INI values with chip specific configuration. 2755250003Sadrian */ 2756250003Sadrianstatic inline void 2757250008Sadrianar9300_override_ini(struct ath_hal *ah, struct ieee80211_channel *chan) 2758250003Sadrian{ 2759250003Sadrian u_int32_t val; 2760250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 2761250003Sadrian 2762250003Sadrian /* 2763250003Sadrian * Set the RX_ABORT and RX_DIS and clear it only after 2764250003Sadrian * RXE is set for MAC. This prevents frames with 2765250003Sadrian * corrupted descriptor status. 2766250003Sadrian */ 2767250003Sadrian OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); 2768250003Sadrian /* 2769250003Sadrian * For Merlin and above, there is a new feature that allows Multicast 2770250003Sadrian * search based on both MAC Address and Key ID. 2771250003Sadrian * By default, this feature is enabled. 2772250003Sadrian * But since the driver is not using this feature, we switch it off; 2773250003Sadrian * otherwise multicast search based on MAC addr only will fail. 2774250003Sadrian */ 2775250003Sadrian val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE); 2776250003Sadrian OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, 2777250003Sadrian val | AR_BUG_58603_FIX_ENABLE | AR_AGG_WEP_ENABLE); 2778250003Sadrian 2779250003Sadrian 2780250003Sadrian /* Osprey revision specific configuration */ 2781250003Sadrian 2782250003Sadrian /* Osprey 2.0+ - if SW RAC support is disabled, must also disable 2783250003Sadrian * the Osprey 2.0 hardware RAC fix. 2784250003Sadrian */ 2785250008Sadrian if (p_cap->halIsrRacSupport == AH_FALSE) { 2786250003Sadrian OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_MISSING_TX_INTR_FIX_ENABLE); 2787250003Sadrian } 2788250003Sadrian 2789250003Sadrian /* try to enable old pal if it is needed for h/w green tx */ 2790250003Sadrian ar9300_hwgreentx_set_pal_spare(ah, 1); 2791250003Sadrian} 2792250003Sadrian 2793250003Sadrianstatic inline void 2794250003Sadrianar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, 2795250003Sadrian int column) 2796250003Sadrian{ 2797250003Sadrian int i, reg_writes = 0; 2798250003Sadrian 2799250003Sadrian /* New INI format: Array may be undefined (pre, core, post arrays) */ 2800250003Sadrian if (ini_arr->ia_array == NULL) { 2801250003Sadrian return; 2802250003Sadrian } 2803250003Sadrian 2804250003Sadrian /* 2805250003Sadrian * New INI format: Pre, core, and post arrays for a given subsystem may be 2806250003Sadrian * modal (> 2 columns) or non-modal (2 columns). 2807250003Sadrian * Determine if the array is non-modal and force the column to 1. 2808250003Sadrian */ 2809250003Sadrian if (column >= ini_arr->ia_columns) { 2810250003Sadrian column = 1; 2811250003Sadrian } 2812250003Sadrian 2813250003Sadrian for (i = 0; i < ini_arr->ia_rows; i++) { 2814250003Sadrian u_int32_t reg = INI_RA(ini_arr, i, 0); 2815250003Sadrian u_int32_t val = INI_RA(ini_arr, i, column); 2816250003Sadrian 2817250003Sadrian /* 2818250003Sadrian ** Determine if this is a shift register value 2819250003Sadrian ** (reg >= 0x16000 && reg < 0x17000 for Osprey) , 2820250003Sadrian ** and insert the configured delay if so. 2821250003Sadrian ** -this delay is not required for Osprey (EV#71410) 2822250003Sadrian */ 2823250003Sadrian OS_REG_WRITE(ah, reg, val); 2824250003Sadrian WAR_6773(reg_writes); 2825250003Sadrian 2826250003Sadrian } 2827250003Sadrian} 2828250003Sadrian 2829250003Sadrianstatic inline HAL_STATUS 2830250008Sadrianar9300_process_ini(struct ath_hal *ah, struct ieee80211_channel *chan, 2831250003Sadrian HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode) 2832250003Sadrian{ 2833250003Sadrian int reg_writes = 0; 2834250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2835250003Sadrian u_int modes_index, modes_txgaintable_index = 0; 2836250003Sadrian int i; 2837250003Sadrian HAL_STATUS status; 2838250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 2839250003Sadrian /* Setup the indices for the next set of register array writes */ 2840250003Sadrian /* TODO: 2841250003Sadrian * If the channel marker is indicative of the current mode rather 2842250003Sadrian * than capability, we do not need to check the phy mode below. 2843250003Sadrian */ 2844250008Sadrian#if 0 2845250003Sadrian switch (chan->channel_flags & CHANNEL_ALL) { 2846250003Sadrian case CHANNEL_A: 2847250003Sadrian case CHANNEL_A_HT20: 2848250003Sadrian if (AR_SREV_SCORPION(ah)){ 2849250003Sadrian if (chan->channel <= 5350){ 2850250003Sadrian modes_txgaintable_index = 1; 2851250003Sadrian }else if ((chan->channel > 5350) && (chan->channel <= 5600)){ 2852250003Sadrian modes_txgaintable_index = 3; 2853250003Sadrian }else if (chan->channel > 5600){ 2854250003Sadrian modes_txgaintable_index = 5; 2855250003Sadrian } 2856250003Sadrian } 2857250003Sadrian modes_index = 1; 2858250003Sadrian break; 2859250003Sadrian 2860250003Sadrian case CHANNEL_A_HT40PLUS: 2861250003Sadrian case CHANNEL_A_HT40MINUS: 2862250003Sadrian if (AR_SREV_SCORPION(ah)){ 2863250003Sadrian if (chan->channel <= 5350){ 2864250003Sadrian modes_txgaintable_index = 2; 2865250003Sadrian }else if ((chan->channel > 5350) && (chan->channel <= 5600)){ 2866250003Sadrian modes_txgaintable_index = 4; 2867250003Sadrian }else if (chan->channel > 5600){ 2868250003Sadrian modes_txgaintable_index = 6; 2869250003Sadrian } 2870250003Sadrian } 2871250003Sadrian modes_index = 2; 2872250003Sadrian break; 2873250003Sadrian 2874250003Sadrian case CHANNEL_PUREG: 2875250003Sadrian case CHANNEL_G_HT20: 2876250003Sadrian case CHANNEL_B: 2877250003Sadrian if (AR_SREV_SCORPION(ah)){ 2878250003Sadrian modes_txgaintable_index = 8; 2879250003Sadrian } 2880250003Sadrian modes_index = 4; 2881250003Sadrian break; 2882250003Sadrian 2883250003Sadrian case CHANNEL_G_HT40PLUS: 2884250003Sadrian case CHANNEL_G_HT40MINUS: 2885250003Sadrian if (AR_SREV_SCORPION(ah)){ 2886250003Sadrian modes_txgaintable_index = 7; 2887250003Sadrian } 2888250003Sadrian modes_index = 3; 2889250003Sadrian break; 2890250003Sadrian 2891250003Sadrian case CHANNEL_108G: 2892250003Sadrian modes_index = 5; 2893250003Sadrian break; 2894250003Sadrian 2895250003Sadrian default: 2896250003Sadrian HALASSERT(0); 2897250003Sadrian return HAL_EINVAL; 2898250003Sadrian } 2899250008Sadrian#endif 2900250003Sadrian 2901250008Sadrian /* FreeBSD */ 2902250008Sadrian if (IS_CHAN_5GHZ(ichan)) { 2903250008Sadrian if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) { 2904250008Sadrian if (AR_SREV_SCORPION(ah)){ 2905250008Sadrian if (ichan->channel <= 5350){ 2906250008Sadrian modes_txgaintable_index = 2; 2907250008Sadrian }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){ 2908250008Sadrian modes_txgaintable_index = 4; 2909250008Sadrian }else if (ichan->channel > 5600){ 2910250008Sadrian modes_txgaintable_index = 6; 2911250008Sadrian } 2912250008Sadrian } 2913250008Sadrian modes_index = 2; 2914250008Sadrian } else if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_HT20(chan)) { 2915250008Sadrian if (AR_SREV_SCORPION(ah)){ 2916250008Sadrian if (ichan->channel <= 5350){ 2917250008Sadrian modes_txgaintable_index = 1; 2918250008Sadrian }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){ 2919250008Sadrian modes_txgaintable_index = 3; 2920250008Sadrian }else if (ichan->channel > 5600){ 2921250008Sadrian modes_txgaintable_index = 5; 2922250008Sadrian } 2923250008Sadrian } 2924250008Sadrian modes_index = 1; 2925250008Sadrian } else 2926250008Sadrian return HAL_EINVAL; 2927250008Sadrian } else if (IS_CHAN_2GHZ(ichan)) { 2928250008Sadrian if (IEEE80211_IS_CHAN_108G(chan)) { 2929250008Sadrian modes_index = 5; 2930250008Sadrian } else if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) { 2931250008Sadrian if (AR_SREV_SCORPION(ah)){ 2932250008Sadrian modes_txgaintable_index = 7; 2933250008Sadrian } 2934250008Sadrian modes_index = 3; 2935250008Sadrian } else if (IEEE80211_IS_CHAN_HT20(chan) || IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_PUREG(chan)) { 2936250008Sadrian if (AR_SREV_SCORPION(ah)){ 2937250008Sadrian modes_txgaintable_index = 8; 2938250008Sadrian } 2939250008Sadrian modes_index = 4; 2940250008Sadrian } else 2941250008Sadrian return HAL_EINVAL; 2942250008Sadrian } else 2943250008Sadrian return HAL_EINVAL; 2944250008Sadrian 2945250003Sadrian#if 0 2946250003Sadrian /* Set correct Baseband to analog shift setting to access analog chips. */ 2947250003Sadrian OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); 2948250003Sadrian#endif 2949250003Sadrian 2950250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2951250003Sadrian "ar9300_process_ini: " 2952250003Sadrian "Skipping OS-REG-WRITE(ah, AR-PHY(0), 0x00000007)\n"); 2953250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2954250003Sadrian "ar9300_process_ini: no ADDac programming\n"); 2955250003Sadrian 2956250003Sadrian 2957250003Sadrian /* 2958250003Sadrian * Osprey 2.0+ - new INI format. 2959250003Sadrian * Each subsystem has a pre, core, and post array. 2960250003Sadrian */ 2961250003Sadrian for (i = 0; i < ATH_INI_NUM_SPLIT; i++) { 2962250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_soc[i], modes_index); 2963250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_mac[i], modes_index); 2964250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_bb[i], modes_index); 2965250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_radio[i], modes_index); 2966250003Sadrian if ((i == ATH_INI_POST) && (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah))) { 2967250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_radio_post_sys2ant, modes_index); 2968250003Sadrian } 2969250003Sadrian 2970250003Sadrian } 2971250003Sadrian 2972250003Sadrian if (!(AR_SREV_SOC(ah))) { 2973250003Sadrian /* Doubler issue : Some board doesn't work well with MCS15. Turn off doubler after freq locking is complete*/ 2974250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== before reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); 2975250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2976250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2977250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== after reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); 2978250003Sadrian 2979250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2980250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2981250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2982250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2983250003Sadrian OS_DELAY(200); 2984250003Sadrian 2985250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== before reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); 2986250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 2987250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 2988250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 2989250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== after reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); 2990250003Sadrian 2991250003Sadrian OS_DELAY(1); 2992250003Sadrian 2993250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== before reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); 2994250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2995250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2996250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2997250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== after reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); 2998250003Sadrian 2999250003Sadrian OS_DELAY(200); 3000250003Sadrian 3001250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== before reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_SYNTH12, OS_REG_READ(ah, AR_PHY_65NM_CH0_SYNTH12)); 3002250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf); 3003250003Sadrian //OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_SYNTH12, 1<< 16); /* clr charge pump */ 3004250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== After reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_SYNTH12, OS_REG_READ(ah, AR_PHY_65NM_CH0_SYNTH12)); 3005250003Sadrian 3006250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 3007250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 3008250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 3009250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 3010250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 3011250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 3012250003Sadrian //ath_hal_printf(ah, "%s[%d] ==== after reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); 3013250003Sadrian } 3014250003Sadrian 3015250003Sadrian /* Write rxgain Array Parameters */ 3016250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain, 1, reg_writes); 3017250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain programming\n"); 3018250003Sadrian 3019250003Sadrian if (AR_SREV_SCORPION(ah)) { 3020250003Sadrian /* Write rxgain bounds Array */ 3021250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, modes_index, reg_writes); 3022250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain table bounds programming\n"); 3023250003Sadrian } 3024250003Sadrian /* UB124 xLNA settings */ 3025250003Sadrian if (AR_SREV_WASP(ah) && ar9300_rx_gain_index_get(ah) == 2) { 3026250003Sadrian#define REG_WRITE(_reg,_val) *((volatile u_int32_t *)(_reg)) = (_val); 3027250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 3028250003Sadrian u_int32_t val; 3029250003Sadrian /* B8040000: bit[0]=0, bit[3]=0; */ 3030250003Sadrian val = REG_READ(0xB8040000); 3031250003Sadrian val &= 0xfffffff6; 3032250003Sadrian REG_WRITE(0xB8040000, val); 3033250003Sadrian /* B804002c: bit[31:24]=0x2e; bit[7:0]=0x2f; */ 3034250003Sadrian val = REG_READ(0xB804002c); 3035250003Sadrian val &= 0x00ffff00; 3036250003Sadrian val |= 0x2e00002f; 3037250003Sadrian REG_WRITE(0xB804002c, val); 3038250003Sadrian /* B804006c: bit[1]=1; */ 3039250003Sadrian val = REG_READ(0xB804006c); 3040250003Sadrian val |= 0x2; 3041250003Sadrian REG_WRITE(0xB804006c, val); 3042250003Sadrian#undef REG_READ 3043250003Sadrian#undef REG_WRITE 3044250003Sadrian } 3045250003Sadrian 3046250003Sadrian 3047250003Sadrian /* Write txgain Array Parameters */ 3048250003Sadrian if (AR_SREV_SCORPION(ah)) { 3049250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_txgaintable_index, 3050250003Sadrian reg_writes); 3051250003Sadrian }else{ 3052250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_index, reg_writes); 3053250003Sadrian } 3054250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Tx Gain programming\n"); 3055250003Sadrian 3056250003Sadrian 3057250003Sadrian /* For 5GHz channels requiring Fast Clock, apply different modal values */ 3058250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { 3059250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 3060250003Sadrian "%s: Fast clock enabled, use special ini values\n", __func__); 3061250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_additional, modes_index, reg_writes); 3062250003Sadrian } 3063250003Sadrian 3064250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 3065250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 3066250003Sadrian "%s: use xtal ini for AH9300(ah)->clk_25mhz: %d\n", 3067250003Sadrian __func__, AH9300(ah)->clk_25mhz); 3068250003Sadrian REG_WRITE_ARRAY( 3069250003Sadrian &ahp->ah_ini_modes_additional, 1/*modes_index*/, reg_writes); 3070250003Sadrian } 3071250003Sadrian 3072250003Sadrian if (AR_SREV_WASP(ah) && (AH9300(ah)->clk_25mhz == 0)) { 3073250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Apply 40MHz ini settings\n", __func__); 3074250003Sadrian REG_WRITE_ARRAY( 3075250003Sadrian &ahp->ah_ini_modes_additional_40mhz, 1/*modesIndex*/, reg_writes); 3076250003Sadrian } 3077250003Sadrian 3078250008Sadrian /* Handle Japan Channel 14 channel spreading */ 3079250008Sadrian if (2484 == ichan->channel) { 3080250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_japan2484, 1); 3081250003Sadrian } 3082250003Sadrian 3083250003Sadrian#if 0 3084250003Sadrian if (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah)) { 3085250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_BTCOEX_MAX_TXPWR, 1); 3086250003Sadrian } 3087250003Sadrian#endif 3088250003Sadrian 3089250003Sadrian /* Override INI with chip specific configuration */ 3090250003Sadrian ar9300_override_ini(ah, chan); 3091250003Sadrian 3092250003Sadrian /* Setup 11n MAC/Phy mode registers */ 3093250003Sadrian ar9300_set_11n_regs(ah, chan, macmode); 3094250003Sadrian 3095250003Sadrian /* 3096250003Sadrian * Moved ar9300_init_chain_masks() here to ensure the swap bit is set before 3097250003Sadrian * the pdadc table is written. Swap must occur before any radio dependent 3098250003Sadrian * replicated register access. The pdadc curve addressing in particular 3099250003Sadrian * depends on the consistent setting of the swap bit. 3100250003Sadrian */ 3101250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask); 3102250003Sadrian 3103250003Sadrian /* 3104250003Sadrian * Setup the transmit power values. 3105250003Sadrian * 3106250003Sadrian * After the public to private hal channel mapping, ichan contains the 3107250003Sadrian * valid regulatory power value. 3108250003Sadrian * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan. 3109250003Sadrian */ 3110250008Sadrian status = ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan, 3111250003Sadrian ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), 3112250003Sadrian ath_hal_get_twice_max_regpower(ahpriv, ichan, chan), 3113250008Sadrian AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)); 3114250003Sadrian if (status != HAL_OK) { 3115250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 3116250003Sadrian "%s: error init'ing transmit power\n", __func__); 3117250003Sadrian return HAL_EIO; 3118250003Sadrian } 3119250003Sadrian 3120250003Sadrian 3121250003Sadrian return HAL_OK; 3122250003Sadrian#undef N 3123250003Sadrian} 3124250003Sadrian 3125250003Sadrian/* ar9300_is_cal_supp 3126250003Sadrian * Determine if calibration is supported by device and channel flags 3127250003Sadrian */ 3128250003Sadrianinline static HAL_BOOL 3129250008Sadrianar9300_is_cal_supp(struct ath_hal *ah, const struct ieee80211_channel *chan, 3130250003Sadrian HAL_CAL_TYPES cal_type) 3131250003Sadrian{ 3132250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3133250003Sadrian HAL_BOOL retval = AH_FALSE; 3134250003Sadrian 3135250003Sadrian switch (cal_type & ahp->ah_supp_cals) { 3136250003Sadrian case IQ_MISMATCH_CAL: 3137250003Sadrian /* Run IQ Mismatch for non-CCK only */ 3138250008Sadrian if (!IEEE80211_IS_CHAN_B(chan)) { 3139250003Sadrian retval = AH_TRUE; 3140250003Sadrian } 3141250003Sadrian break; 3142250003Sadrian case TEMP_COMP_CAL: 3143250003Sadrian retval = AH_TRUE; 3144250003Sadrian break; 3145250003Sadrian } 3146250003Sadrian 3147250003Sadrian return retval; 3148250003Sadrian} 3149250003Sadrian 3150250003Sadrian 3151250003Sadrian#if 0 3152250003Sadrian/* ar9285_pa_cal 3153250003Sadrian * PA Calibration for Kite 1.1 and later versions of Kite. 3154250003Sadrian * - from system's team. 3155250003Sadrian */ 3156250003Sadrianstatic inline void 3157250003Sadrianar9285_pa_cal(struct ath_hal *ah) 3158250003Sadrian{ 3159250003Sadrian u_int32_t reg_val; 3160250003Sadrian int i, lo_gn, offs_6_1, offs_0; 3161250003Sadrian u_int8_t reflo; 3162250003Sadrian u_int32_t phy_test2_reg_val, phy_adc_ctl_reg_val; 3163250003Sadrian u_int32_t an_top2_reg_val, phy_tst_dac_reg_val; 3164250003Sadrian 3165250003Sadrian 3166250003Sadrian /* Kite 1.1 WAR for Bug 35666 3167250003Sadrian * Increase the LDO value to 1.28V before accessing analog Reg */ 3168250003Sadrian if (AR_SREV_KITE_11(ah)) { 3169250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14) ); 3170250003Sadrian } 3171250003Sadrian an_top2_reg_val = OS_REG_READ(ah, AR9285_AN_TOP2); 3172250003Sadrian 3173250003Sadrian /* set pdv2i pdrxtxbb */ 3174250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1); 3175250003Sadrian reg_val |= ((0x1 << 5) | (0x1 << 7)); 3176250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val); 3177250003Sadrian 3178250003Sadrian /* clear pwddb */ 3179250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G7); 3180250003Sadrian reg_val &= 0xfffffffd; 3181250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G7, reg_val); 3182250003Sadrian 3183250003Sadrian /* clear enpacal */ 3184250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3185250003Sadrian reg_val &= 0xfffff7ff; 3186250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3187250003Sadrian 3188250003Sadrian /* set offcal */ 3189250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2); 3190250003Sadrian reg_val |= (0x1 << 12); 3191250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val); 3192250003Sadrian 3193250003Sadrian /* set pdpadrv1=pdpadrv2=pdpaout=1 */ 3194250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3195250003Sadrian reg_val |= (0x7 << 23); 3196250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3197250003Sadrian 3198250003Sadrian /* Read back reflo, increase it by 1 and write it. */ 3199250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3200250003Sadrian reflo = ((reg_val >> 26) & 0x7); 3201250003Sadrian 3202250003Sadrian if (reflo < 0x7) { 3203250003Sadrian reflo++; 3204250003Sadrian } 3205250003Sadrian reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26)); 3206250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3207250003Sadrian 3208250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3209250003Sadrian reflo = ((reg_val >> 26) & 0x7); 3210250003Sadrian 3211250003Sadrian /* use TX single carrier to transmit 3212250003Sadrian * dac const 3213250003Sadrian * reg. 15 3214250003Sadrian */ 3215250003Sadrian phy_tst_dac_reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST); 3216250003Sadrian OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, ((0x7ff << 11) | 0x7ff)); 3217250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST); 3218250003Sadrian 3219250003Sadrian /* source is dac const 3220250003Sadrian * reg. 2 3221250003Sadrian */ 3222250003Sadrian phy_test2_reg_val = OS_REG_READ(ah, AR_PHY_TEST2); 3223250003Sadrian OS_REG_WRITE(ah, AR_PHY_TEST2, ((0x1 << 7) | (0x1 << 1))); 3224250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_TEST2); 3225250003Sadrian 3226250003Sadrian /* set dac on 3227250003Sadrian * reg. 11 3228250003Sadrian */ 3229250003Sadrian phy_adc_ctl_reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL); 3230250003Sadrian OS_REG_WRITE(ah, AR_PHY_ADC_CTL, 0x80008000); 3231250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL); 3232250003Sadrian 3233250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP2, (0x1 << 27) | (0x1 << 17) | (0x1 << 16) | 3234250003Sadrian (0x1 << 14) | (0x1 << 12) | (0x1 << 11) | 3235250003Sadrian (0x1 << 7) | (0x1 << 5)); 3236250003Sadrian 3237250003Sadrian OS_DELAY(10); /* 10 usec */ 3238250003Sadrian 3239250003Sadrian /* clear off[6:0] */ 3240250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3241250003Sadrian reg_val &= 0xfc0fffff; 3242250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3243250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3244250003Sadrian reg_val &= 0xfdffffff; 3245250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3246250003Sadrian 3247250003Sadrian offs_6_1 = 0; 3248250003Sadrian for (i = 6; i > 0; i--) { 3249250003Sadrian /* sef off[$k]==1 */ 3250250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3251250003Sadrian reg_val &= 0xfc0fffff; 3252250003Sadrian reg_val = reg_val | (0x1 << (19 + i)) | ((offs_6_1) << 20); 3253250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3254250003Sadrian lo_gn = (OS_REG_READ(ah, AR9285_AN_RF2G9)) & 0x1; 3255250003Sadrian offs_6_1 = offs_6_1 | (lo_gn << (i - 1)); 3256250003Sadrian } 3257250003Sadrian 3258250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3259250003Sadrian reg_val &= 0xfc0fffff; 3260250003Sadrian reg_val = reg_val | ((offs_6_1 - 1) << 20); 3261250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3262250003Sadrian 3263250003Sadrian /* set off_0=1; */ 3264250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3265250003Sadrian reg_val &= 0xfdffffff; 3266250003Sadrian reg_val = reg_val | (0x1 << 25); 3267250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3268250003Sadrian 3269250003Sadrian lo_gn = OS_REG_READ(ah, AR9285_AN_RF2G9) & 0x1; 3270250003Sadrian offs_0 = lo_gn; 3271250003Sadrian 3272250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3273250003Sadrian reg_val &= 0xfdffffff; 3274250003Sadrian reg_val = reg_val | (offs_0 << 25); 3275250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3276250003Sadrian 3277250003Sadrian /* clear pdv2i */ 3278250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1); 3279250003Sadrian reg_val &= 0xffffff5f; 3280250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val); 3281250003Sadrian 3282250003Sadrian /* set enpacal */ 3283250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3284250003Sadrian reg_val |= (0x1 << 11); 3285250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3286250003Sadrian 3287250003Sadrian /* clear offcal */ 3288250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2); 3289250003Sadrian reg_val &= 0xffffefff; 3290250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val); 3291250003Sadrian 3292250003Sadrian /* set pdpadrv1=pdpadrv2=pdpaout=0 */ 3293250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3294250003Sadrian reg_val &= 0xfc7fffff; 3295250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3296250003Sadrian 3297250003Sadrian /* Read back reflo, decrease it by 1 and write it. */ 3298250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3299250003Sadrian reflo = (reg_val >> 26) & 0x7; 3300250003Sadrian if (reflo) { 3301250003Sadrian reflo--; 3302250003Sadrian } 3303250003Sadrian reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26)); 3304250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3305250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3306250003Sadrian reflo = (reg_val >> 26) & 0x7; 3307250003Sadrian 3308250003Sadrian /* write back registers */ 3309250003Sadrian OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, phy_tst_dac_reg_val); 3310250003Sadrian OS_REG_WRITE(ah, AR_PHY_TEST2, phy_test2_reg_val); 3311250003Sadrian OS_REG_WRITE(ah, AR_PHY_ADC_CTL, phy_adc_ctl_reg_val); 3312250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP2, an_top2_reg_val); 3313250003Sadrian 3314250003Sadrian /* Kite 1.1 WAR for Bug 35666 3315250003Sadrian * Decrease the LDO value back to 1.20V */ 3316250003Sadrian if (AR_SREV_KITE_11(ah)) { 3317250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); 3318250003Sadrian } 3319250003Sadrian} 3320250003Sadrian#endif 3321250003Sadrian 3322250003Sadrian/* ar9300_run_init_cals 3323250003Sadrian * Runs non-periodic calibrations 3324250003Sadrian */ 3325250003Sadrianinline static HAL_BOOL 3326250003Sadrianar9300_run_init_cals(struct ath_hal *ah, int init_cal_count) 3327250003Sadrian{ 3328250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3329250003Sadrian HAL_CHANNEL_INTERNAL ichan; /* bogus */ 3330250003Sadrian HAL_BOOL is_cal_done; 3331250003Sadrian HAL_CAL_LIST *curr_cal; 3332250008Sadrian const HAL_PERCAL_DATA *cal_data; 3333250003Sadrian int i; 3334250003Sadrian 3335250003Sadrian curr_cal = ahp->ah_cal_list_curr; 3336250003Sadrian if (curr_cal == AH_NULL) { 3337250003Sadrian return AH_FALSE; 3338250003Sadrian } 3339250008Sadrian cal_data = curr_cal->cal_data; 3340250008Sadrian ichan.calValid = 0; 3341250003Sadrian 3342250003Sadrian for (i = 0; i < init_cal_count; i++) { 3343250003Sadrian /* Reset this Cal */ 3344250003Sadrian ar9300_reset_calibration(ah, curr_cal); 3345250003Sadrian /* Poll for offset calibration complete */ 3346250003Sadrian if (!ath_hal_wait( 3347250008Sadrian ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL, 0)) 3348250003Sadrian { 3349250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3350250003Sadrian "%s: Cal %d failed to complete in 100ms.\n", 3351250003Sadrian __func__, curr_cal->cal_data->cal_type); 3352250003Sadrian /* Re-initialize list pointers for periodic cals */ 3353250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr 3354250003Sadrian = AH_NULL; 3355250003Sadrian return AH_FALSE; 3356250003Sadrian } 3357250003Sadrian /* Run this cal */ 3358250003Sadrian ar9300_per_calibration( 3359250003Sadrian ah, &ichan, ahp->ah_rx_chainmask, curr_cal, &is_cal_done); 3360250003Sadrian if (is_cal_done == AH_FALSE) { 3361250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3362250003Sadrian "%s: Not able to run Init Cal %d.\n", __func__, 3363250003Sadrian curr_cal->cal_data->cal_type); 3364250003Sadrian } 3365250003Sadrian if (curr_cal->cal_next) { 3366250003Sadrian curr_cal = curr_cal->cal_next; 3367250003Sadrian } 3368250003Sadrian } 3369250003Sadrian 3370250003Sadrian /* Re-initialize list pointers for periodic cals */ 3371250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; 3372250003Sadrian return AH_TRUE; 3373250003Sadrian} 3374250003Sadrian 3375250003Sadrian#if 0 3376250003Sadrianstatic void 3377250003Sadrianar9300_tx_carrier_leak_war(struct ath_hal *ah) 3378250003Sadrian{ 3379250003Sadrian unsigned long tx_gain_table_max; 3380250003Sadrian unsigned long reg_bb_cl_map_0_b0 = 0xffffffff; 3381250003Sadrian unsigned long reg_bb_cl_map_1_b0 = 0xffffffff; 3382250003Sadrian unsigned long reg_bb_cl_map_2_b0 = 0xffffffff; 3383250003Sadrian unsigned long reg_bb_cl_map_3_b0 = 0xffffffff; 3384250003Sadrian unsigned long tx_gain, cal_run = 0; 3385250003Sadrian unsigned long cal_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3386250003Sadrian unsigned long cal_gain_index[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3387250003Sadrian unsigned long new_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3388250003Sadrian int i, j; 3389250003Sadrian 3390250003Sadrian OS_MEMSET(new_gain, 0, sizeof(new_gain)); 3391250003Sadrian /*printf(" Running TxCarrierLeakWAR\n");*/ 3392250003Sadrian 3393250003Sadrian /* process tx gain table, we use cl_map_hw_gen=0. */ 3394250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_MAP_HW_GEN, 0); 3395250003Sadrian 3396250003Sadrian //the table we used is txbb_gc[2:0], 1dB[2:1]. 3397250003Sadrian tx_gain_table_max = OS_REG_READ_FIELD(ah, 3398250003Sadrian AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX); 3399250003Sadrian 3400250003Sadrian for (i = 0; i <= tx_gain_table_max; i++) { 3401250003Sadrian tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4); 3402250003Sadrian cal_gain[i] = (((tx_gain >> 5)& 0x7) << 2) | 3403250003Sadrian (((tx_gain >> 1) & 0x3) << 0); 3404250003Sadrian if (i == 0) { 3405250003Sadrian cal_gain_index[i] = cal_run; 3406250003Sadrian new_gain[i] = 1; 3407250003Sadrian cal_run++; 3408250003Sadrian } else { 3409250003Sadrian new_gain[i] = 1; 3410250003Sadrian for (j = 0; j < i; j++) { 3411250003Sadrian /* 3412250003Sadrian printf("i=%d, j=%d cal_gain[$i]=0x%04x\n", i, j, cal_gain[i]); 3413250003Sadrian */ 3414250003Sadrian if (new_gain[i]) { 3415250003Sadrian if ((cal_gain[i] != cal_gain[j])) { 3416250003Sadrian new_gain[i] = 1; 3417250003Sadrian } else { 3418250003Sadrian /* if old gain found, use old cal_run value. */ 3419250003Sadrian new_gain[i] = 0; 3420250003Sadrian cal_gain_index[i] = cal_gain_index[j]; 3421250003Sadrian } 3422250003Sadrian } 3423250003Sadrian } 3424250003Sadrian /* if new gain found, increase cal_run */ 3425250003Sadrian if (new_gain[i] == 1) { 3426250003Sadrian cal_gain_index[i] = cal_run; 3427250003Sadrian cal_run++; 3428250003Sadrian } 3429250003Sadrian } 3430250003Sadrian 3431250003Sadrian reg_bb_cl_map_0_b0 = (reg_bb_cl_map_0_b0 & ~(0x1 << i)) | 3432250003Sadrian ((cal_gain_index[i] >> 0 & 0x1) << i); 3433250003Sadrian reg_bb_cl_map_1_b0 = (reg_bb_cl_map_1_b0 & ~(0x1 << i)) | 3434250003Sadrian ((cal_gain_index[i] >> 1 & 0x1) << i); 3435250003Sadrian reg_bb_cl_map_2_b0 = (reg_bb_cl_map_2_b0 & ~(0x1 << i)) | 3436250003Sadrian ((cal_gain_index[i] >> 2 & 0x1) << i); 3437250003Sadrian reg_bb_cl_map_3_b0 = (reg_bb_cl_map_3_b0 & ~(0x1 << i)) | 3438250003Sadrian ((cal_gain_index[i] >> 3 & 0x1) << i); 3439250003Sadrian 3440250003Sadrian /* 3441250003Sadrian printf("i=%2d, cal_gain[$i]= 0x%04x, cal_run= %d, " 3442250003Sadrian "cal_gain_index[i]=%d, new_gain[i] = %d\n", 3443250003Sadrian i, cal_gain[i], cal_run, cal_gain_index[i], new_gain[i]); 3444250003Sadrian */ 3445250003Sadrian } 3446250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B0, reg_bb_cl_map_0_b0); 3447250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B0, reg_bb_cl_map_1_b0); 3448250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B0, reg_bb_cl_map_2_b0); 3449250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B0, reg_bb_cl_map_3_b0); 3450250003Sadrian if (AR_SREV_WASP(ah)) { 3451250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B1, reg_bb_cl_map_0_b0); 3452250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B1, reg_bb_cl_map_1_b0); 3453250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B1, reg_bb_cl_map_2_b0); 3454250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B1, reg_bb_cl_map_3_b0); 3455250003Sadrian } 3456250003Sadrian} 3457250003Sadrian#endif 3458250003Sadrian 3459250003Sadrian 3460250003Sadrianstatic inline void 3461250003Sadrianar9300_invalidate_saved_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 3462250003Sadrian{ 3463250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3464250003Sadrian if (AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse & 3465250003Sadrian ATH_CAL_REUSE_REDO_IN_FULL_RESET) 3466250003Sadrian { 3467250003Sadrian ichan->one_time_txiqcal_done = AH_FALSE; 3468250003Sadrian ichan->one_time_txclcal_done = AH_FALSE; 3469250003Sadrian } 3470250003Sadrian#endif 3471250003Sadrian} 3472250003Sadrian 3473250003Sadrianstatic inline HAL_BOOL 3474250003Sadrianar9300_restore_rtt_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 3475250003Sadrian{ 3476250003Sadrian HAL_BOOL restore_status = AH_FALSE; 3477250003Sadrian 3478250003Sadrian return restore_status; 3479250003Sadrian} 3480250003Sadrian 3481250003Sadrian/* ar9300_init_cal 3482250003Sadrian * Initialize Calibration infrastructure 3483250003Sadrian */ 3484250003Sadrianstatic inline HAL_BOOL 3485250008Sadrianar9300_init_cal_internal(struct ath_hal *ah, struct ieee80211_channel *chan, 3486250008Sadrian HAL_CHANNEL_INTERNAL *ichan, 3487250008Sadrian HAL_BOOL enable_rtt, HAL_BOOL do_rtt_cal, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr) 3488250003Sadrian{ 3489250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3490250003Sadrian HAL_BOOL txiqcal_success_flag = AH_FALSE; 3491250003Sadrian HAL_BOOL cal_done = AH_FALSE; 3492250003Sadrian int iqcal_idx = 0; 3493250003Sadrian HAL_BOOL do_sep_iq_cal = AH_FALSE; 3494250003Sadrian HAL_BOOL do_agc_cal = do_rtt_cal; 3495250003Sadrian HAL_BOOL is_cal_reusable = AH_TRUE; 3496250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3497250003Sadrian HAL_BOOL cal_reuse_enable = AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse & 3498250003Sadrian ATH_CAL_REUSE_ENABLE; 3499250003Sadrian HAL_BOOL clc_success = AH_FALSE; 3500250003Sadrian int32_t ch_idx, j, cl_tab_reg; 3501250003Sadrian u_int32_t BB_cl_tab_entry = MAX_BB_CL_TABLE_ENTRY; 3502250003Sadrian u_int32_t BB_cl_tab_b[AR9300_MAX_CHAINS] = { 3503250003Sadrian AR_PHY_CL_TAB_0, 3504250003Sadrian AR_PHY_CL_TAB_1, 3505250003Sadrian AR_PHY_CL_TAB_2 3506250003Sadrian }; 3507250003Sadrian#endif 3508250003Sadrian 3509250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 3510250003Sadrian /* Hornet: 1 x 1 */ 3511250003Sadrian ahp->ah_rx_cal_chainmask = 0x1; 3512250003Sadrian ahp->ah_tx_cal_chainmask = 0x1; 3513250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { 3514250003Sadrian /* Wasp/Jupiter: 2 x 2 */ 3515250003Sadrian ahp->ah_rx_cal_chainmask = 0x3; 3516250003Sadrian ahp->ah_tx_cal_chainmask = 0x3; 3517250003Sadrian } else { 3518250003Sadrian /* 3519250003Sadrian * Osprey needs to be configured for the correct chain mode 3520250003Sadrian * before running AGC/TxIQ cals. 3521250003Sadrian */ 3522250003Sadrian if (ahp->ah_enterprise_mode & AR_ENT_OTP_CHAIN2_DISABLE) { 3523250003Sadrian /* chain 2 disabled - 2 chain mode */ 3524250003Sadrian ahp->ah_rx_cal_chainmask = 0x3; 3525250003Sadrian ahp->ah_tx_cal_chainmask = 0x3; 3526250003Sadrian } else { 3527250003Sadrian ahp->ah_rx_cal_chainmask = 0x7; 3528250003Sadrian ahp->ah_tx_cal_chainmask = 0x7; 3529250003Sadrian } 3530250003Sadrian } 3531250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_cal_chainmask, ahp->ah_tx_cal_chainmask); 3532250003Sadrian 3533250003Sadrian 3534250003Sadrian if (ahp->tx_cl_cal_enable) { 3535250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3536250003Sadrian /* disable Carrie Leak or set do_agc_cal accordingly */ 3537250003Sadrian if (cal_reuse_enable && ichan->one_time_txclcal_done) 3538250003Sadrian { 3539250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 3540250003Sadrian } else 3541250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3542250003Sadrian { 3543250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 3544250003Sadrian do_agc_cal = AH_TRUE; 3545250003Sadrian } 3546250003Sadrian } 3547250003Sadrian 3548250003Sadrian /* Do Tx IQ Calibration here for osprey hornet and wasp */ 3549250003Sadrian /* XXX: For initial wasp bringup - check and enable this */ 3550250003Sadrian /* EV 74233: Tx IQ fails to complete for half/quarter rates */ 3551250008Sadrian if (!(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { 3552250003Sadrian if (ahp->tx_iq_cal_enable) { 3553250003Sadrian /* this should be eventually moved to INI file */ 3554250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah), 3555250003Sadrian AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); 3556250003Sadrian 3557250003Sadrian /* 3558250003Sadrian * For poseidon and later chips, 3559250003Sadrian * Tx IQ cal HW run will be a part of AGC calibration 3560250003Sadrian */ 3561250003Sadrian if (ahp->tx_iq_cal_during_agc_cal) { 3562250003Sadrian /* 3563250003Sadrian * txiqcal_success_flag always set to 1 to run 3564250003Sadrian * ar9300_tx_iq_cal_post_proc 3565250003Sadrian * if following AGC cal passes 3566250003Sadrian */ 3567250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3568250003Sadrian if (!cal_reuse_enable || !ichan->one_time_txiqcal_done) 3569250003Sadrian { 3570250003Sadrian txiqcal_success_flag = AH_TRUE; 3571250003Sadrian OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3572250003Sadrian OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) | 3573250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 3574250003Sadrian } else { 3575250003Sadrian OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3576250003Sadrian OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) & 3577250003Sadrian (~AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)); 3578250003Sadrian } 3579250003Sadrian#else 3580250003Sadrian if (OS_REG_READ_FIELD(ah, 3581250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0(ah), 3582250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)){ 3583250003Sadrian if (apply_last_iqcorr == AH_TRUE) { 3584250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3585250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 3586250003Sadrian txiqcal_success_flag = AH_FALSE; 3587250003Sadrian } else { 3588250003Sadrian txiqcal_success_flag = AH_TRUE; 3589250003Sadrian } 3590250003Sadrian }else{ 3591250003Sadrian txiqcal_success_flag = AH_FALSE; 3592250003Sadrian } 3593250003Sadrian#endif 3594250003Sadrian if (txiqcal_success_flag) { 3595250003Sadrian do_agc_cal = AH_TRUE; 3596250003Sadrian } 3597250003Sadrian } else 3598250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3599250003Sadrian if (!cal_reuse_enable || !ichan->one_time_txiqcal_done) 3600250003Sadrian#endif 3601250003Sadrian { 3602250003Sadrian do_sep_iq_cal = AH_TRUE; 3603250003Sadrian do_agc_cal = AH_TRUE; 3604250003Sadrian } 3605250003Sadrian } 3606250003Sadrian } 3607250003Sadrian 3608250003Sadrian#if ATH_SUPPORT_MCI 3609250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 3610250003Sadrian IS_CHAN_2GHZ(ichan) && 3611250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 3612250003Sadrian do_agc_cal && 3613250008Sadrian !(ah->ah_config.ath_hal_mci_config & 3614250003Sadrian ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 3615250003Sadrian { 3616250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 3617250003Sadrian 3618250003Sadrian /* Send CAL_REQ only when BT is AWAKE. */ 3619250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_REQ 0x%X\n", 3620250003Sadrian __func__, ahp->ah_mci_wlan_cal_seq); 3621250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_REQ); 3622250003Sadrian payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_seq++; 3623250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 3624250003Sadrian 3625250003Sadrian /* Wait BT_CAL_GRANT for 50ms */ 3626250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3627250003Sadrian "(MCI) %s: Wait for BT_CAL_GRANT\n", __func__); 3628250003Sadrian if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) 3629250003Sadrian { 3630250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3631250003Sadrian "(MCI) %s: Got BT_CAL_GRANT.\n", __func__); 3632250003Sadrian } 3633250003Sadrian else { 3634250003Sadrian is_cal_reusable = AH_FALSE; 3635250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3636250003Sadrian "(MCI) %s: BT is not responding.\n", __func__); 3637250003Sadrian } 3638250003Sadrian } 3639250003Sadrian#endif /* ATH_SUPPORT_MCI */ 3640250003Sadrian 3641250003Sadrian if (do_sep_iq_cal) 3642250003Sadrian { 3643250003Sadrian /* enable Tx IQ Calibration HW for osprey/hornet/wasp */ 3644250003Sadrian txiqcal_success_flag = ar9300_tx_iq_cal_hw_run(ah); 3645250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); 3646250003Sadrian OS_DELAY(5); 3647250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 3648250003Sadrian } 3649250003Sadrian#if 0 3650250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 3651250003Sadrian ar9300_tx_carrier_leak_war(ah); 3652250003Sadrian } 3653250003Sadrian#endif 3654250003Sadrian /* 3655250003Sadrian * Calibrate the AGC 3656250003Sadrian * 3657250003Sadrian * Tx IQ cal is a part of AGC cal for Jupiter/Poseidon, etc. 3658250003Sadrian * please enable the bit of txiqcal_control_0[31] in INI file 3659250003Sadrian * for Jupiter/Poseidon/etc. 3660250003Sadrian */ 3661250003Sadrian if(!AR_SREV_SCORPION(ah)) { 3662250003Sadrian if (do_agc_cal || !skip_if_none) { 3663250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3664250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3665250003Sadrian 3666250003Sadrian /* Poll for offset calibration complete */ 3667250003Sadrian cal_done = ath_hal_wait(ah, 3668250008Sadrian AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0); 3669250003Sadrian if (!cal_done) { 3670250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3671250003Sadrian "(FCS) CAL NOT DONE!!! - %d\n", ichan->channel); 3672250003Sadrian } 3673250003Sadrian } else { 3674250003Sadrian cal_done = AH_TRUE; 3675250003Sadrian } 3676250003Sadrian /* 3677250003Sadrian * Tx IQ cal post-processing in SW 3678250003Sadrian * This part of code should be common to all chips, 3679250003Sadrian * no chip specific code for Jupiter/Posdeion except for register names. 3680250003Sadrian */ 3681250003Sadrian if (txiqcal_success_flag) { 3682251098Sadrian ar9300_tx_iq_cal_post_proc(ah,ichan, 1, 1,is_cal_reusable, AH_FALSE); 3683250003Sadrian } 3684250003Sadrian } else { 3685250003Sadrian if (!txiqcal_success_flag) { 3686250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3687250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3688250008Sadrian if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 3689250008Sadrian 0)) { 3690250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3691250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3692250003Sadrian "noisy environment?\n", __func__); 3693250003Sadrian return AH_FALSE; 3694250003Sadrian } 3695250003Sadrian if (apply_last_iqcorr == AH_TRUE) { 3696250003Sadrian ar9300_tx_iq_cal_post_proc(ah, ichan, 0, 0, is_cal_reusable, AH_TRUE); 3697250003Sadrian } 3698250003Sadrian } else { 3699250003Sadrian for (iqcal_idx=0;iqcal_idx<MAXIQCAL;iqcal_idx++) { 3700250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3701250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3702250003Sadrian 3703250003Sadrian /* Poll for offset calibration complete */ 3704250003Sadrian if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, 3705250008Sadrian AR_PHY_AGC_CONTROL_CAL, 0)) { 3706250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3707250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3708250003Sadrian "noisy environment?\n", __func__); 3709250003Sadrian return AH_FALSE; 3710250003Sadrian } 3711250003Sadrian /* 3712250003Sadrian * Tx IQ cal post-processing in SW 3713250003Sadrian * This part of code should be common to all chips, 3714250003Sadrian * no chip specific code for Jupiter/Posdeion except for register names. 3715250003Sadrian */ 3716250003Sadrian ar9300_tx_iq_cal_post_proc(ah, ichan, iqcal_idx+1, MAXIQCAL, is_cal_reusable, AH_FALSE); 3717250003Sadrian } 3718250003Sadrian } 3719250003Sadrian } 3720250003Sadrian 3721250003Sadrian 3722250003Sadrian#if ATH_SUPPORT_MCI 3723250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 3724250003Sadrian IS_CHAN_2GHZ(ichan) && 3725250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 3726250003Sadrian do_agc_cal && 3727250008Sadrian !(ah->ah_config.ath_hal_mci_config & 3728250003Sadrian ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 3729250003Sadrian { 3730250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 3731250003Sadrian 3732250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_DONE 0x%X\n", 3733250003Sadrian __func__, ahp->ah_mci_wlan_cal_done); 3734250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); 3735250003Sadrian payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_done++; 3736250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 3737250003Sadrian } 3738250003Sadrian#endif /* ATH_SUPPORT_MCI */ 3739250003Sadrian 3740250003Sadrian 3741250003Sadrian if (!cal_done && !AR_SREV_SCORPION(ah) ) 3742250003Sadrian { 3743250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3744250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3745250003Sadrian "noisy environment?\n", __func__); 3746250003Sadrian return AH_FALSE; 3747250003Sadrian } 3748250003Sadrian 3749250003Sadrian#if 0 3750250003Sadrian /* Beacon stuck fix, refer to EV 120056 */ 3751250003Sadrian if(IS_CHAN_2GHZ(chan) && AR_SREV_SCORPION(ah)) 3752250003Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING5, OS_REG_READ(ah,AR_PHY_TIMING5) & ~AR_PHY_TIMING5_CYCPWR_THR1_ENABLE); 3753250003Sadrian#endif 3754250003Sadrian 3755250003Sadrian#if 0 3756250003Sadrian /* Do PA Calibration */ 3757250003Sadrian if (AR_SREV_KITE(ah) && AR_SREV_KITE_11_OR_LATER(ah)) { 3758250003Sadrian ar9285_pa_cal(ah); 3759250003Sadrian } 3760250003Sadrian#endif 3761250003Sadrian 3762250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3763250003Sadrian if (ichan->one_time_txiqcal_done) { 3764250003Sadrian ar9300_tx_iq_cal_apply(ah, ichan); 3765250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3766250003Sadrian "(FCS) TXIQCAL applied - %d\n", ichan->channel); 3767250003Sadrian } 3768250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3769250003Sadrian 3770250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3771250003Sadrian if (cal_reuse_enable && ahp->tx_cl_cal_enable) 3772250003Sadrian { 3773250003Sadrian clc_success = (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & 3774250003Sadrian AR_PHY_AGC_CONTROL_CLC_SUCCESS) ? 1 : 0; 3775250003Sadrian 3776250003Sadrian if (ichan->one_time_txclcal_done) 3777250003Sadrian { 3778250003Sadrian /* reapply CL cal results */ 3779250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 3780250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 3781250003Sadrian continue; 3782250003Sadrian } 3783250003Sadrian cl_tab_reg = BB_cl_tab_b[ch_idx]; 3784250003Sadrian for (j = 0; j < BB_cl_tab_entry; j++) { 3785250003Sadrian OS_REG_WRITE(ah, cl_tab_reg, ichan->tx_clcal[ch_idx][j]); 3786250003Sadrian cl_tab_reg += 4;; 3787250003Sadrian } 3788250003Sadrian } 3789250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3790250003Sadrian "(FCS) TX CL CAL applied - %d\n", ichan->channel); 3791250003Sadrian } 3792250003Sadrian else if (is_cal_reusable && clc_success) { 3793250003Sadrian /* save CL cal results */ 3794250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 3795250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 3796250003Sadrian continue; 3797250003Sadrian } 3798250003Sadrian cl_tab_reg = BB_cl_tab_b[ch_idx]; 3799250003Sadrian for (j = 0; j < BB_cl_tab_entry; j++) { 3800250003Sadrian ichan->tx_clcal[ch_idx][j] = OS_REG_READ(ah, cl_tab_reg); 3801250003Sadrian cl_tab_reg += 4; 3802250003Sadrian } 3803250003Sadrian } 3804250003Sadrian ichan->one_time_txclcal_done = AH_TRUE; 3805250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3806250003Sadrian "(FCS) TX CL CAL saved - %d\n", ichan->channel); 3807250003Sadrian } 3808250003Sadrian } 3809250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3810250003Sadrian 3811250003Sadrian /* Revert chainmasks to their original values before NF cal */ 3812250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask); 3813250003Sadrian 3814250003Sadrian#if !FIX_NOISE_FLOOR 3815250003Sadrian /* 3816250003Sadrian * Do NF calibration after DC offset and other CALs. 3817250003Sadrian * Per system engineers, noise floor value can sometimes be 20 dB 3818250003Sadrian * higher than normal value if DC offset and noise floor cal are 3819250003Sadrian * triggered at the same time. 3820250003Sadrian */ 3821250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3822250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); 3823250003Sadrian#endif 3824250003Sadrian 3825250003Sadrian /* Initialize list pointers */ 3826250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; 3827250003Sadrian 3828250003Sadrian /* 3829250003Sadrian * Enable IQ, ADC Gain, ADC DC Offset Cals 3830250003Sadrian */ 3831250003Sadrian /* Setup all non-periodic, init time only calibrations */ 3832250003Sadrian /* XXX: Init DC Offset not working yet */ 3833250003Sadrian#ifdef not_yet 3834250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, ADC_DC_INIT_CAL)) { 3835250003Sadrian INIT_CAL(&ahp->ah_adc_dc_cal_init_data); 3836250003Sadrian INSERT_CAL(ahp, &ahp->ah_adc_dc_cal_init_data); 3837250003Sadrian } 3838250003Sadrian 3839250003Sadrian /* Initialize current pointer to first element in list */ 3840250003Sadrian ahp->ah_cal_list_curr = ahp->ah_cal_list; 3841250003Sadrian 3842250003Sadrian if (ahp->ah_cal_list_curr) { 3843250003Sadrian if (ar9300_run_init_cals(ah, 0) == AH_FALSE) { 3844250003Sadrian return AH_FALSE; 3845250003Sadrian } 3846250003Sadrian } 3847250003Sadrian#endif 3848250003Sadrian /* end - Init time calibrations */ 3849250003Sadrian 3850278741Sadrian /* Do not do RX cal in case of offchan, or cal data already exists on same channel*/ 3851278741Sadrian if (ahp->ah_skip_rx_iq_cal) { 3852278741Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3853278741Sadrian "Skip RX IQ Cal\n"); 3854278741Sadrian return AH_TRUE; 3855278741Sadrian } 3856278741Sadrian 3857250003Sadrian /* If Cals are supported, add them to list via INIT/INSERT_CAL */ 3858250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, IQ_MISMATCH_CAL)) { 3859250003Sadrian INIT_CAL(&ahp->ah_iq_cal_data); 3860250003Sadrian INSERT_CAL(ahp, &ahp->ah_iq_cal_data); 3861250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3862250003Sadrian "%s: enabling IQ Calibration.\n", __func__); 3863250003Sadrian } 3864250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, TEMP_COMP_CAL)) { 3865250003Sadrian INIT_CAL(&ahp->ah_temp_comp_cal_data); 3866250003Sadrian INSERT_CAL(ahp, &ahp->ah_temp_comp_cal_data); 3867250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3868250003Sadrian "%s: enabling Temperature Compensation Calibration.\n", __func__); 3869250003Sadrian } 3870250003Sadrian 3871250003Sadrian /* Initialize current pointer to first element in list */ 3872250003Sadrian ahp->ah_cal_list_curr = ahp->ah_cal_list; 3873250003Sadrian 3874250003Sadrian /* Reset state within current cal */ 3875250003Sadrian if (ahp->ah_cal_list_curr) { 3876250003Sadrian ar9300_reset_calibration(ah, ahp->ah_cal_list_curr); 3877250003Sadrian } 3878250003Sadrian 3879250003Sadrian /* Mark all calibrations on this channel as being invalid */ 3880250008Sadrian ichan->calValid = 0; 3881250003Sadrian 3882250003Sadrian return AH_TRUE; 3883250003Sadrian} 3884250003Sadrian 3885250003Sadrianstatic inline HAL_BOOL 3886250008Sadrianar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr) 3887250003Sadrian{ 3888250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 3889250003Sadrian HAL_BOOL do_rtt_cal = AH_TRUE; 3890250003Sadrian HAL_BOOL enable_rtt = AH_FALSE; 3891250003Sadrian 3892250003Sadrian HALASSERT(ichan); 3893250003Sadrian 3894250003Sadrian return ar9300_init_cal_internal(ah, chan, ichan, enable_rtt, do_rtt_cal, skip_if_none, apply_last_iqcorr); 3895250003Sadrian} 3896250003Sadrian 3897250003Sadrian/* ar9300_reset_cal_valid 3898250003Sadrian * Entry point for upper layers to restart current cal. 3899250003Sadrian * Reset the calibration valid bit in channel. 3900250003Sadrian */ 3901250003Sadrianvoid 3902250008Sadrianar9300_reset_cal_valid(struct ath_hal *ah, const struct ieee80211_channel *chan, 3903250003Sadrian HAL_BOOL *is_cal_done, u_int32_t cal_type) 3904250003Sadrian{ 3905250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3906250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 3907250003Sadrian HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr; 3908250003Sadrian 3909250003Sadrian *is_cal_done = AH_TRUE; 3910250003Sadrian 3911250003Sadrian if (curr_cal == AH_NULL) { 3912250003Sadrian return; 3913250003Sadrian } 3914250003Sadrian if (ichan == AH_NULL) { 3915250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3916250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 3917250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 3918250003Sadrian return; 3919250003Sadrian } 3920250003Sadrian 3921250003Sadrian if (!(cal_type & IQ_MISMATCH_CAL)) { 3922250003Sadrian *is_cal_done = AH_FALSE; 3923250003Sadrian return; 3924250003Sadrian } 3925250003Sadrian 3926250003Sadrian /* Expected that this calibration has run before, post-reset. 3927250003Sadrian * Current state should be done 3928250003Sadrian */ 3929250003Sadrian if (curr_cal->cal_state != CAL_DONE) { 3930250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3931250003Sadrian "%s: Calibration state incorrect, %d\n", 3932250003Sadrian __func__, curr_cal->cal_state); 3933250003Sadrian return; 3934250003Sadrian } 3935250003Sadrian 3936250003Sadrian /* Verify Cal is supported on this channel */ 3937250003Sadrian if (ar9300_is_cal_supp(ah, chan, curr_cal->cal_data->cal_type) == AH_FALSE) { 3938250003Sadrian return; 3939250003Sadrian } 3940250003Sadrian 3941250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3942250003Sadrian "%s: Resetting Cal %d state for channel %u/0x%x\n", __func__, 3943250008Sadrian curr_cal->cal_data->cal_type, chan->ic_freq, chan->ic_flags); 3944250003Sadrian 3945250003Sadrian /* Disable cal validity in channel */ 3946250008Sadrian ichan->calValid &= ~curr_cal->cal_data->cal_type; 3947250003Sadrian curr_cal->cal_state = CAL_WAITING; 3948250003Sadrian /* Indicate to upper layers that we need polling */ 3949250003Sadrian *is_cal_done = AH_FALSE; 3950250003Sadrian} 3951250003Sadrian 3952250003Sadrianstatic inline void 3953250003Sadrianar9300_set_dma(struct ath_hal *ah) 3954250003Sadrian{ 3955250003Sadrian u_int32_t regval; 3956250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3957278741Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 3958278741Sadrian HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; 3959250003Sadrian 3960250003Sadrian#if 0 3961250003Sadrian /* 3962250003Sadrian * set AHB_MODE not to do cacheline prefetches 3963250003Sadrian */ 3964250003Sadrian regval = OS_REG_READ(ah, AR_AHB_MODE); 3965250003Sadrian OS_REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); 3966250003Sadrian#endif 3967250003Sadrian 3968250003Sadrian /* 3969250003Sadrian * let mac dma reads be in 128 byte chunks 3970250003Sadrian */ 3971250003Sadrian regval = OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; 3972250003Sadrian OS_REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); 3973250003Sadrian 3974250003Sadrian /* 3975250003Sadrian * Restore TX Trigger Level to its pre-reset value. 3976250003Sadrian * The initial value depends on whether aggregation is enabled, and is 3977250003Sadrian * adjusted whenever underruns are detected. 3978250003Sadrian */ 3979250003Sadrian /* 3980250003Sadrian OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, AH_PRIVATE(ah)->ah_tx_trig_level); 3981250003Sadrian */ 3982250003Sadrian /* 3983250003Sadrian * Osprey 1.0 bug (EV 61936). Don't change trigger level from .ini default. 3984250003Sadrian * Osprey 2.0 - hardware recommends using the default INI settings. 3985250003Sadrian */ 3986250003Sadrian#if 0 3987250003Sadrian OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, 0x3f); 3988250003Sadrian#endif 3989250003Sadrian /* 3990250003Sadrian * let mac dma writes be in 128 byte chunks 3991250003Sadrian */ 3992250003Sadrian regval = OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; 3993250003Sadrian OS_REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); 3994250003Sadrian 3995250003Sadrian /* 3996250003Sadrian * Setup receive FIFO threshold to hold off TX activities 3997250003Sadrian */ 3998250003Sadrian OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); 3999250003Sadrian 4000250003Sadrian /* 4001250003Sadrian * reduce the number of usable entries in PCU TXBUF to avoid 4002250003Sadrian * wrap around bugs. (bug 20428) 4003250003Sadrian */ 4004250003Sadrian 4005250003Sadrian if (AR_SREV_WASP(ah) && 4006250003Sadrian (AH_PRIVATE((ah))->ah_macRev > AR_SREV_REVISION_WASP_12)) { 4007250003Sadrian /* Wasp 1.3 fix for EV#85395 requires usable entries 4008250003Sadrian * to be set to 0x500 4009250003Sadrian */ 4010250003Sadrian OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, 0x500); 4011250003Sadrian } else { 4012250003Sadrian OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); 4013250003Sadrian } 4014250003Sadrian 4015250003Sadrian /* 4016250003Sadrian * Enable HPQ for UAPSD 4017250003Sadrian */ 4018278741Sadrian if (pCap->halHwUapsdTrig == AH_TRUE) { 4019278741Sadrian /* Only enable this if HAL capabilities says it is OK */ 4020278741Sadrian if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 4021278741Sadrian OS_REG_WRITE(ah, AR_HP_Q_CONTROL, 4022278741Sadrian AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN); 4023278741Sadrian } 4024278741Sadrian } else { 4025278741Sadrian /* use default value from ini file - which disable HPQ queue usage */ 4026250003Sadrian } 4027250003Sadrian 4028250003Sadrian /* 4029250003Sadrian * set the transmit status ring 4030250003Sadrian */ 4031250003Sadrian ar9300_reset_tx_status_ring(ah); 4032250003Sadrian 4033250003Sadrian /* 4034250003Sadrian * set rxbp threshold. Must be non-zero for RX_EOL to occur. 4035250003Sadrian * For Osprey 2.0+, keep the original thresholds 4036250003Sadrian * otherwise performance is lost due to excessive RX EOL interrupts. 4037250003Sadrian */ 4038250003Sadrian OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1); 4039250003Sadrian OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1); 4040250003Sadrian 4041250003Sadrian /* 4042250003Sadrian * set receive buffer size. 4043250003Sadrian */ 4044250003Sadrian if (ahp->rx_buf_size) { 4045250003Sadrian OS_REG_WRITE(ah, AR_DATABUF, ahp->rx_buf_size); 4046250003Sadrian } 4047250003Sadrian} 4048250003Sadrian 4049250003Sadrianstatic inline void 4050250008Sadrianar9300_init_bb(struct ath_hal *ah, struct ieee80211_channel *chan) 4051250003Sadrian{ 4052250003Sadrian u_int32_t synth_delay; 4053250003Sadrian 4054250003Sadrian /* 4055250003Sadrian * Wait for the frequency synth to settle (synth goes on 4056250003Sadrian * via AR_PHY_ACTIVE_EN). Read the phy active delay register. 4057250003Sadrian * Value is in 100ns increments. 4058250003Sadrian */ 4059250003Sadrian synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; 4060250008Sadrian if (IEEE80211_IS_CHAN_CCK(chan)) { 4061250003Sadrian synth_delay = (4 * synth_delay) / 22; 4062250003Sadrian } else { 4063250003Sadrian synth_delay /= 10; 4064250003Sadrian } 4065250003Sadrian 4066250003Sadrian /* Activate the PHY (includes baseband activate + synthesizer on) */ 4067250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 4068250003Sadrian 4069250003Sadrian /* 4070250003Sadrian * There is an issue if the AP starts the calibration before 4071250003Sadrian * the base band timeout completes. This could result in the 4072250003Sadrian * rx_clear AH_FALSE triggering. As a workaround we add delay an 4073250003Sadrian * extra BASE_ACTIVATE_DELAY usecs to ensure this condition 4074250003Sadrian * does not happen. 4075250003Sadrian */ 4076250003Sadrian OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY); 4077250003Sadrian} 4078250003Sadrian 4079250003Sadrianstatic inline void 4080250003Sadrianar9300_init_interrupt_masks(struct ath_hal *ah, HAL_OPMODE opmode) 4081250003Sadrian{ 4082250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4083250003Sadrian u_int32_t msi_cfg = 0; 4084250003Sadrian u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; 4085250003Sadrian 4086250003Sadrian /* 4087250003Sadrian * Setup interrupt handling. Note that ar9300_reset_tx_queue 4088250003Sadrian * manipulates the secondary IMR's as queues are enabled 4089250003Sadrian * and disabled. This is done with RMW ops to insure the 4090250003Sadrian * settings we make here are preserved. 4091250003Sadrian */ 4092250003Sadrian ahp->ah_mask_reg = 4093250003Sadrian AR_IMR_TXERR | AR_IMR_TXURN | 4094250003Sadrian AR_IMR_RXERR | AR_IMR_RXORN | 4095250003Sadrian AR_IMR_BCNMISC; 4096250003Sadrian 4097250003Sadrian if (ahp->ah_intr_mitigation_rx) { 4098250003Sadrian /* enable interrupt mitigation for rx */ 4099250003Sadrian ahp->ah_mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR | AR_IMR_RXOK_HP; 4100250003Sadrian msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR; 4101250003Sadrian } else { 4102250003Sadrian ahp->ah_mask_reg |= AR_IMR_RXOK_LP | AR_IMR_RXOK_HP; 4103250003Sadrian msi_cfg |= AR_INTCFG_MSI_RXOK; 4104250003Sadrian } 4105250003Sadrian if (ahp->ah_intr_mitigation_tx) { 4106250003Sadrian /* enable interrupt mitigation for tx */ 4107250003Sadrian ahp->ah_mask_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR; 4108250003Sadrian msi_cfg |= AR_INTCFG_MSI_TXINTM | AR_INTCFG_MSI_TXMINTR; 4109250003Sadrian } else { 4110250003Sadrian ahp->ah_mask_reg |= AR_IMR_TXOK; 4111250003Sadrian msi_cfg |= AR_INTCFG_MSI_TXOK; 4112250003Sadrian } 4113250003Sadrian if (opmode == HAL_M_HOSTAP) { 4114250003Sadrian ahp->ah_mask_reg |= AR_IMR_MIB; 4115250003Sadrian } 4116250003Sadrian 4117250003Sadrian OS_REG_WRITE(ah, AR_IMR, ahp->ah_mask_reg); 4118250003Sadrian OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); 4119250003Sadrian ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2); 4120250003Sadrian 4121250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 4122250003Sadrian /* Cache MSI register value */ 4123250003Sadrian ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI)); 4124250003Sadrian ahp->ah_msi_reg |= AR_PCIE_MSI_HW_DBI_WR_EN; 4125250003Sadrian if (AR_SREV_POSEIDON(ah)) { 4126250003Sadrian ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 4127250003Sadrian } else { 4128250003Sadrian ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR; 4129250003Sadrian } 4130250003Sadrian /* Program MSI configuration */ 4131250003Sadrian OS_REG_WRITE(ah, AR_INTCFG, msi_cfg); 4132250003Sadrian } 4133250003Sadrian 4134250003Sadrian /* 4135250003Sadrian * debug - enable to see all synchronous interrupts status 4136250003Sadrian */ 4137250003Sadrian /* Clear any pending sync cause interrupts */ 4138250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE), 0xFFFFFFFF); 4139250003Sadrian 4140250003Sadrian /* Allow host interface sync interrupt sources to set cause bit */ 4141250003Sadrian if (AR_SREV_POSEIDON(ah)) { 4142250003Sadrian sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; 4143250003Sadrian } 4144250003Sadrian else if (AR_SREV_WASP(ah)) { 4145250003Sadrian sync_en_def = AR9340_INTR_SYNC_DEFAULT; 4146250003Sadrian } 4147250003Sadrian OS_REG_WRITE(ah, 4148250003Sadrian AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), sync_en_def); 4149250003Sadrian 4150250003Sadrian /* _Disable_ host interface sync interrupt when cause bits set */ 4151250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 0); 4152250003Sadrian 4153250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0); 4154250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 0); 4155250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE), 0); 4156250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK), 0); 4157250003Sadrian} 4158250003Sadrian 4159250003Sadrianstatic inline void 4160250003Sadrianar9300_init_qos(struct ath_hal *ah) 4161250003Sadrian{ 4162250003Sadrian OS_REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); /* XXX magic */ 4163250003Sadrian OS_REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); /* XXX magic */ 4164250003Sadrian 4165250003Sadrian /* Turn on NOACK Support for QoS packets */ 4166250003Sadrian OS_REG_WRITE(ah, AR_QOS_NO_ACK, 4167250003Sadrian SM(2, AR_QOS_NO_ACK_TWO_BIT) | 4168250003Sadrian SM(5, AR_QOS_NO_ACK_BIT_OFF) | 4169250003Sadrian SM(0, AR_QOS_NO_ACK_BYTE_OFF)); 4170250003Sadrian 4171250003Sadrian /* 4172250003Sadrian * initialize TXOP for all TIDs 4173250003Sadrian */ 4174250003Sadrian OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); 4175250003Sadrian OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); 4176250003Sadrian OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); 4177250003Sadrian OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); 4178250003Sadrian OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); 4179250003Sadrian} 4180250003Sadrian 4181250003Sadrianstatic inline void 4182250003Sadrianar9300_init_user_settings(struct ath_hal *ah) 4183250003Sadrian{ 4184250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4185250003Sadrian 4186250003Sadrian /* Restore user-specified settings */ 4187250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 4188250003Sadrian "--AP %s ahp->ah_misc_mode 0x%x\n", __func__, ahp->ah_misc_mode); 4189250003Sadrian if (ahp->ah_misc_mode != 0) { 4190250003Sadrian OS_REG_WRITE(ah, 4191250003Sadrian AR_PCU_MISC, OS_REG_READ(ah, AR_PCU_MISC) | ahp->ah_misc_mode); 4192250003Sadrian } 4193250003Sadrian if (ahp->ah_get_plcp_hdr) { 4194250003Sadrian OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM); 4195250003Sadrian } 4196250003Sadrian if (ahp->ah_slot_time != (u_int) -1) { 4197250003Sadrian ar9300_set_slot_time(ah, ahp->ah_slot_time); 4198250003Sadrian } 4199250003Sadrian if (ahp->ah_ack_timeout != (u_int) -1) { 4200250003Sadrian ar9300_set_ack_timeout(ah, ahp->ah_ack_timeout); 4201250003Sadrian } 4202250003Sadrian if (AH_PRIVATE(ah)->ah_diagreg != 0) { 4203250003Sadrian OS_REG_SET_BIT(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 4204250003Sadrian } 4205250003Sadrian if (ahp->ah_beacon_rssi_threshold != 0) { 4206250003Sadrian ar9300_set_hw_beacon_rssi_threshold(ah, ahp->ah_beacon_rssi_threshold); 4207250003Sadrian } 4208250003Sadrian#ifdef ATH_SUPPORT_DFS 4209250003Sadrian if (ahp->ah_cac_quiet_enabled) { 4210250003Sadrian ar9300_cac_tx_quiet(ah, 1); 4211250003Sadrian } 4212250003Sadrian#endif /* ATH_SUPPORT_DFS */ 4213250003Sadrian} 4214250003Sadrian 4215250003Sadrianint 4216250003Sadrianar9300_get_spur_info(struct ath_hal * ah, int *enable, int len, u_int16_t *freq) 4217250003Sadrian{ 4218250008Sadrian// struct ath_hal_private *ap = AH_PRIVATE(ah); 4219250003Sadrian int i, j; 4220250003Sadrian 4221250003Sadrian for (i = 0; i < len; i++) { 4222250003Sadrian freq[i] = 0; 4223250003Sadrian } 4224250003Sadrian 4225250008Sadrian *enable = ah->ah_config.ath_hal_spur_mode; 4226250003Sadrian for (i = 0, j = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 4227250008Sadrian if (AH9300(ah)->ath_hal_spur_chans[i][0] != AR_NO_SPUR) { 4228250008Sadrian freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][0]; 4229250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 4230250008Sadrian "1. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][0]); 4231250003Sadrian } 4232250008Sadrian if (AH9300(ah)->ath_hal_spur_chans[i][1] != AR_NO_SPUR) { 4233250008Sadrian freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][1]; 4234250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 4235250008Sadrian "2. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][1]); 4236250003Sadrian } 4237250003Sadrian } 4238250003Sadrian 4239250003Sadrian return 0; 4240250003Sadrian} 4241250003Sadrian 4242250003Sadrian#define ATH_HAL_2GHZ_FREQ_MIN 20000 4243250003Sadrian#define ATH_HAL_2GHZ_FREQ_MAX 29999 4244250003Sadrian#define ATH_HAL_5GHZ_FREQ_MIN 50000 4245250003Sadrian#define ATH_HAL_5GHZ_FREQ_MAX 59999 4246250003Sadrian 4247250008Sadrian#if 0 4248250003Sadrianint 4249250003Sadrianar9300_set_spur_info(struct ath_hal * ah, int enable, int len, u_int16_t *freq) 4250250003Sadrian{ 4251250003Sadrian struct ath_hal_private *ap = AH_PRIVATE(ah); 4252250003Sadrian int i, j, k; 4253250003Sadrian 4254250003Sadrian ap->ah_config.ath_hal_spur_mode = enable; 4255250003Sadrian 4256250003Sadrian if (ap->ah_config.ath_hal_spur_mode == SPUR_ENABLE_IOCTL) { 4257250003Sadrian for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 4258250008Sadrian AH9300(ah)->ath_hal_spur_chans[i][0] = AR_NO_SPUR; 4259250008Sadrian AH9300(ah)->ath_hal_spur_chans[i][1] = AR_NO_SPUR; 4260250003Sadrian } 4261250003Sadrian for (i = 0, j = 0, k = 0; i < len; i++) { 4262250003Sadrian if (freq[i] > ATH_HAL_2GHZ_FREQ_MIN && 4263250003Sadrian freq[i] < ATH_HAL_2GHZ_FREQ_MAX) 4264250003Sadrian { 4265250003Sadrian /* 2GHz Spur */ 4266250003Sadrian if (j < AR_EEPROM_MODAL_SPURS) { 4267250008Sadrian AH9300(ah)->ath_hal_spur_chans[j++][1] = freq[i]; 4268250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "1 set spur %d\n", freq[i]); 4269250003Sadrian } 4270250003Sadrian } else if (freq[i] > ATH_HAL_5GHZ_FREQ_MIN && 4271250003Sadrian freq[i] < ATH_HAL_5GHZ_FREQ_MAX) 4272250003Sadrian { 4273250003Sadrian /* 5Ghz Spur */ 4274250003Sadrian if (k < AR_EEPROM_MODAL_SPURS) { 4275250008Sadrian AH9300(ah)->ath_hal_spur_chans[k++][0] = freq[i]; 4276250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "2 set spur %d\n", freq[i]); 4277250003Sadrian } 4278250003Sadrian } 4279250003Sadrian } 4280250003Sadrian } 4281250003Sadrian 4282250003Sadrian return 0; 4283250003Sadrian} 4284250008Sadrian#endif 4285250003Sadrian 4286250003Sadrian#define ar9300_check_op_mode(_opmode) \ 4287250003Sadrian ((_opmode == HAL_M_STA) || (_opmode == HAL_M_IBSS) ||\ 4288250003Sadrian (_opmode == HAL_M_HOSTAP) || (_opmode == HAL_M_MONITOR)) 4289250003Sadrian 4290250003Sadrian 4291250003Sadrian 4292250003Sadrian 4293250003Sadrian#ifndef ATH_NF_PER_CHAN 4294250003Sadrian/* 4295250003Sadrian* To fixed first reset noise floor value not correct issue 4296250003Sadrian* For ART need it to fixed low rate sens too low issue 4297250003Sadrian*/ 4298250003Sadrianstatic int 4299250003SadrianFirst_NFCal(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, 4300250008Sadrian int is_scan, struct ieee80211_channel *chan) 4301250003Sadrian{ 4302250003Sadrian HAL_NFCAL_HIST_FULL *nfh; 4303250003Sadrian int i, j, k; 4304250008Sadrian int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; 4305250003Sadrian int is_2g = 0; 4306250003Sadrian int nf_hist_len; 4307250003Sadrian int stats = 0; 4308250003Sadrian 4309250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 4310250003Sadrian#define IS(_c, _f) (((_c)->channel_flags & _f) || 0) 4311250003Sadrian 4312250003Sadrian 4313250003Sadrian if ((!is_scan) && 4314250008Sadrian chan->ic_freq == AH_PRIVATE(ah)->ah_curchan->ic_freq) 4315250003Sadrian { 4316250003Sadrian nfh = &AH_PRIVATE(ah)->nf_cal_hist; 4317250003Sadrian } else { 4318250003Sadrian nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 4319250003Sadrian } 4320250008Sadrian 4321250003Sadrian ar9300_start_nf_cal(ah); 4322250003Sadrian for (j = 0; j < 10000; j++) { 4323250003Sadrian if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){ 4324250003Sadrian break; 4325250003Sadrian } 4326250003Sadrian OS_DELAY(10); 4327250003Sadrian } 4328250003Sadrian if (j < 10000) { 4329250008Sadrian is_2g = IEEE80211_IS_CHAN_2GHZ(chan); 4330250003Sadrian ar9300_upload_noise_floor(ah, is_2g, nfarray); 4331250003Sadrian 4332250003Sadrian if (is_scan) { 4333250003Sadrian /* 4334250003Sadrian * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct 4335250003Sadrian * rather than a HAL_NFCAL_HIST_FULL struct. 4336250003Sadrian * As long as we only use the first history element of nf_cal_buffer 4337250008Sadrian * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use 4338250003Sadrian * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably. 4339250003Sadrian */ 4340250003Sadrian nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 4341250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; 4342250003Sadrian } else { 4343250003Sadrian nfh = &AH_PRIVATE(ah)->nf_cal_hist; 4344250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 4345250003Sadrian } 4346250003Sadrian 4347250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i ++) { 4348250003Sadrian for (k = 0; k < HAL_NF_CAL_HIST_LEN_FULL; k++) { 4349250003Sadrian nfh->nf_cal_buffer[k][i] = nfarray[i]; 4350250003Sadrian } 4351250003Sadrian nfh->base.priv_nf[i] = ar9300_limit_nf_range(ah, 4352250003Sadrian ar9300_get_nf_hist_mid(ah, nfh, i, nf_hist_len)); 4353250003Sadrian } 4354250003Sadrian 4355250003Sadrian 4356250003Sadrian //ar9300StoreNewNf(ah, ichan, is_scan); 4357250003Sadrian 4358250003Sadrian /* 4359250003Sadrian * See if the NF value from the old channel should be 4360250003Sadrian * retained when switching to a new channel. 4361250003Sadrian * TBD: this may need to be changed, as it wipes out the 4362250003Sadrian * purpose of saving NF values for each channel. 4363250003Sadrian */ 4364250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) 4365250003Sadrian { 4366250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) 4367250003Sadrian { 4368250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4369250003Sadrian AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ) 4370250003Sadrian { 4371250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4372250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4373250003Sadrian } 4374250003Sadrian } else { 4375250003Sadrian if (AR_SREV_AR9580(ah)) { 4376250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4377250003Sadrian AR_PHY_CCA_NOM_VAL_PEACOCK_5GHZ) 4378250003Sadrian { 4379250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4380250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4381250003Sadrian } 4382250003Sadrian } else { 4383250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4384250003Sadrian AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ) 4385250003Sadrian { 4386250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4387250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4388250003Sadrian } 4389250003Sadrian } 4390250003Sadrian } 4391250003Sadrian } 4392250003Sadrian /* 4393250003Sadrian * Copy the channel's NF buffer, which may have been modified 4394250003Sadrian * just above here, to the full NF history buffer. 4395250003Sadrian */ 4396250003Sadrian ar9300_reset_nf_hist_buff(ah, ichan); 4397250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 4398250003Sadrian ar9300_load_nf(ah, nf_buf); 4399250003Sadrian stats = 0; 4400250003Sadrian } else { 4401250003Sadrian stats = 1; 4402250003Sadrian } 4403250003Sadrian#undef IS 4404250003Sadrian return stats; 4405250003Sadrian} 4406250003Sadrian#endif 4407250003Sadrian 4408250003Sadrian 4409250003Sadrian/* 4410250003Sadrian * Places the device in and out of reset and then places sane 4411250003Sadrian * values in the registers based on EEPROM config, initialization 4412250003Sadrian * vectors (as determined by the mode), and station configuration 4413250003Sadrian * 4414250003Sadrian * b_channel_change is used to preserve DMA/PCU registers across 4415250003Sadrian * a HW Reset during channel change. 4416250003Sadrian */ 4417250003SadrianHAL_BOOL 4418250008Sadrianar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, 4419250003Sadrian HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask, 4420250003Sadrian HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change, 4421250003Sadrian HAL_STATUS *status, int is_scan) 4422250003Sadrian{ 4423250003Sadrian#define FAIL(_code) do { ecode = _code; goto bad; } while (0) 4424250003Sadrian u_int32_t save_led_state; 4425250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4426250003Sadrian struct ath_hal_private *ap = AH_PRIVATE(ah); 4427250003Sadrian HAL_CHANNEL_INTERNAL *ichan; 4428250008Sadrian //const struct ieee80211_channel *curchan = ap->ah_curchan; 4429250003Sadrian#if ATH_SUPPORT_MCI 4430250003Sadrian HAL_BOOL save_full_sleep = ahp->ah_chip_full_sleep; 4431250003Sadrian#endif 4432250003Sadrian u_int32_t save_def_antenna; 4433250003Sadrian u_int32_t mac_sta_id1; 4434250003Sadrian HAL_STATUS ecode; 4435250003Sadrian int i, rx_chainmask; 4436250003Sadrian int nf_hist_buff_reset = 0; 4437250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 4438250003Sadrian#ifdef ATH_FORCE_PPM 4439250003Sadrian u_int32_t save_force_val, tmp_reg; 4440250003Sadrian#endif 4441250003Sadrian HAL_BOOL stopped, cal_ret; 4442250003Sadrian HAL_BOOL apply_last_iqcorr = AH_FALSE; 4443250003Sadrian 4444278741Sadrian 4445250003Sadrian if (OS_REG_READ(ah, AR_IER) == AR_IER_ENABLE) { 4446250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "** Reset called with WLAN " 4447250003Sadrian "interrupt enabled %08x **\n", ar9300_get_interrupts(ah)); 4448250003Sadrian } 4449250003Sadrian 4450250003Sadrian /* 4451250003Sadrian * Set the status to "ok" by default to cover the cases 4452250003Sadrian * where we return AH_FALSE without going to "bad" 4453250003Sadrian */ 4454250003Sadrian HALASSERT(status); 4455250003Sadrian *status = HAL_OK; 4456250008Sadrian if ((ah->ah_config.ath_hal_sta_update_tx_pwr_enable)) { 4457250008Sadrian AH9300(ah)->green_tx_status = HAL_RSSI_TX_POWER_NONE; 4458250003Sadrian } 4459250003Sadrian 4460250003Sadrian#if ATH_SUPPORT_MCI 4461250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 4462250003Sadrian (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah))) 4463250003Sadrian { 4464250008Sadrian ar9300_mci_2g5g_changed(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4465250003Sadrian } 4466250003Sadrian#endif 4467250003Sadrian 4468250003Sadrian ahp->ah_ext_prot_spacing = extprotspacing; 4469250008Sadrian ahp->ah_tx_chainmask = txchainmask & ap->ah_caps.halTxChainMask; 4470250008Sadrian ahp->ah_rx_chainmask = rxchainmask & ap->ah_caps.halRxChainMask; 4471250008Sadrian ahp->ah_tx_cal_chainmask = ap->ah_caps.halTxChainMask; 4472250008Sadrian ahp->ah_rx_cal_chainmask = ap->ah_caps.halRxChainMask; 4473278741Sadrian 4474278741Sadrian /* 4475278741Sadrian * Keep the previous optinal txchainmask value 4476278741Sadrian */ 4477278741Sadrian 4478250003Sadrian HALASSERT(ar9300_check_op_mode(opmode)); 4479250003Sadrian 4480250003Sadrian OS_MARK(ah, AH_MARK_RESET, b_channel_change); 4481250003Sadrian 4482250003Sadrian /* 4483250003Sadrian * Map public channel to private. 4484250003Sadrian */ 4485250003Sadrian ichan = ar9300_check_chan(ah, chan); 4486250003Sadrian if (ichan == AH_NULL) { 4487250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 4488250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 4489250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 4490250003Sadrian FAIL(HAL_EINVAL); 4491250003Sadrian } 4492250003Sadrian 4493250003Sadrian ichan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */ 4494250008Sadrian#if 0 4495250003Sadrian chan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */ 4496250008Sadrian#endif 4497250003Sadrian 4498250003Sadrian if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) { 4499250003Sadrian /* Need to stop RX DMA before reset otherwise chip might hang */ 4500250003Sadrian stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */ 4501250003Sadrian ar9300_set_rx_filter(ah, 0); 4502250003Sadrian stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */ 4503250003Sadrian if (!stopped) { 4504250003Sadrian /* 4505250003Sadrian * During the transition from full sleep to reset, 4506250003Sadrian * recv DMA regs are not available to be read 4507250003Sadrian */ 4508250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 4509250003Sadrian "%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__); 4510250003Sadrian b_channel_change = AH_FALSE; 4511250003Sadrian } 4512250003Sadrian } else { 4513250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 4514250003Sadrian "%s[%d]: Chip is already in full sleep\n", __func__, __LINE__); 4515250003Sadrian } 4516250003Sadrian 4517250003Sadrian#if ATH_SUPPORT_MCI 4518250008Sadrian if ((AH_PRIVATE(ah)->ah_caps.halMciSupport) && 4519250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_CAL_START)) 4520250003Sadrian { 4521250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 4522250003Sadrian 4523250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4524250003Sadrian "(MCI) %s: Stop rx for BT cal.\n", __func__); 4525250003Sadrian ahp->ah_mci_bt_state = MCI_BT_CAL; 4526250003Sadrian 4527250003Sadrian /* 4528250003Sadrian * MCIFIX: disable mci interrupt here. This is to avoid SW_MSG_DONE or 4529250003Sadrian * RX_MSG bits to trigger MCI_INT and lead to mci_intr reentry. 4530250003Sadrian */ 4531250003Sadrian ar9300_mci_disable_interrupt(ah); 4532250003Sadrian 4533250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4534250003Sadrian "(MCI) %s: Send WLAN_CAL_GRANT\n", __func__); 4535250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); 4536250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 4537250003Sadrian 4538250003Sadrian /* Wait BT calibration to be completed for 25ms */ 4539250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4540250003Sadrian "(MCI) %s: BT is calibrating.\n", __func__); 4541250003Sadrian if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) { 4542250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4543250003Sadrian "(MCI) %s: Got BT_CAL_DONE.\n", __func__); 4544250003Sadrian } 4545250003Sadrian else { 4546250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4547250003Sadrian "(MCI) %s: ### BT cal takes too long. Force bt_state to be bt_awake.\n", 4548250003Sadrian __func__); 4549250003Sadrian } 4550250003Sadrian ahp->ah_mci_bt_state = MCI_BT_AWAKE; 4551250003Sadrian /* MCIFIX: enable mci interrupt here */ 4552250003Sadrian ar9300_mci_enable_interrupt(ah); 4553250003Sadrian 4554250003Sadrian return AH_TRUE; 4555250003Sadrian } 4556250003Sadrian#endif 4557250003Sadrian 4558250003Sadrian /* Bring out of sleep mode */ 4559250003Sadrian if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { 4560250003Sadrian *status = HAL_INV_PMODE; 4561250003Sadrian return AH_FALSE; 4562250003Sadrian } 4563250003Sadrian 4564250003Sadrian /* Check the Rx mitigation config again, it might have changed 4565250003Sadrian * during attach in ath_vap_attach. 4566250003Sadrian */ 4567250008Sadrian if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) { 4568250003Sadrian ahp->ah_intr_mitigation_rx = AH_TRUE; 4569250003Sadrian } else { 4570250003Sadrian ahp->ah_intr_mitigation_rx = AH_FALSE; 4571250003Sadrian } 4572250003Sadrian 4573250008Sadrian /* 4574250008Sadrian * XXX TODO FreeBSD: 4575250008Sadrian * 4576250008Sadrian * This is painful because we don't have a non-const channel pointer 4577250008Sadrian * at this stage. 4578250008Sadrian * 4579250008Sadrian * Make sure this gets fixed! 4580250008Sadrian */ 4581250008Sadrian#if 0 4582250003Sadrian /* Get the value from the previous NF cal and update history buffer */ 4583250003Sadrian if (curchan && (ahp->ah_chip_full_sleep != AH_TRUE)) { 4584278741Sadrian 4585278741Sadrian if(ahp->ah_chip_reset_done){ 4586278741Sadrian ahp->ah_chip_reset_done = 0; 4587278741Sadrian } else { 4588278741Sadrian /* 4589278741Sadrian * is_scan controls updating NF for home channel or off channel. 4590278741Sadrian * Home -> Off, update home channel 4591278741Sadrian * Off -> Home, update off channel 4592278741Sadrian * Home -> Home, uppdate home channel 4593278741Sadrian */ 4594278741Sadrian if (ap->ah_curchan->channel != chan->channel) 4595278741Sadrian ar9300_store_new_nf(ah, curchan, !is_scan); 4596278741Sadrian else 4597278741Sadrian ar9300_store_new_nf(ah, curchan, is_scan); 4598278741Sadrian } 4599250003Sadrian } 4600250008Sadrian#endif 4601250003Sadrian 4602250003Sadrian /* 4603250003Sadrian * Account for the effect of being in either the 2 GHz or 5 GHz band 4604250003Sadrian * on the nominal, max allowable, and min allowable noise floor values. 4605250003Sadrian */ 4606250008Sadrian AH9300(ah)->nfp = IS_CHAN_2GHZ(ichan) ? &ahp->nf_2GHz : &ahp->nf_5GHz; 4607250003Sadrian 4608250008Sadrian /* 4609278741Sadrian * XXX FreeBSD For now, don't apply the last IQ correction. 4610250008Sadrian * 4611250008Sadrian * This should be done when scorpion is enabled on FreeBSD; just be 4612250008Sadrian * sure to fix this channel match code so it uses net80211 flags 4613250008Sadrian * instead. 4614250008Sadrian */ 4615250008Sadrian#if 0 4616250003Sadrian if (AR_SREV_SCORPION(ah) && curchan && (chan->channel == curchan->channel) && 4617250003Sadrian ((chan->channel_flags & (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)) == 4618250003Sadrian (curchan->channel_flags & 4619250003Sadrian (CHANNEL_ALL | CHANNEL_HALF | CHANNEL_QUARTER)))) { 4620250003Sadrian apply_last_iqcorr = AH_TRUE; 4621250003Sadrian } 4622250008Sadrian#endif 4623250008Sadrian apply_last_iqcorr = AH_FALSE; 4624250008Sadrian 4625250003Sadrian 4626250003Sadrian#ifndef ATH_NF_PER_CHAN 4627250003Sadrian /* 4628250003Sadrian * If there's only one full-size home-channel NF history buffer 4629250003Sadrian * rather than a full-size NF history buffer per channel, decide 4630250003Sadrian * whether to (re)initialize the home-channel NF buffer. 4631250003Sadrian * If this is just a channel change for a scan, or if the channel 4632250003Sadrian * is not being changed, don't mess up the home channel NF history 4633250003Sadrian * buffer with NF values from this scanned channel. If we're 4634250003Sadrian * changing the home channel to a new channel, reset the home-channel 4635250003Sadrian * NF history buffer with the most accurate NF known for the new channel. 4636250003Sadrian */ 4637250003Sadrian if (!is_scan && (!ap->ah_curchan || 4638250008Sadrian ap->ah_curchan->ic_freq != chan->ic_freq)) // || 4639250008Sadrian// ap->ah_curchan->channel_flags != chan->channel_flags)) 4640250003Sadrian { 4641250003Sadrian nf_hist_buff_reset = 1; 4642250003Sadrian ar9300_reset_nf_hist_buff(ah, ichan); 4643250003Sadrian } 4644250003Sadrian#endif 4645250003Sadrian /* 4646278741Sadrian * In case of 4647278741Sadrian * - offchan scan, or 4648278741Sadrian * - same channel and RX IQ Cal already available 4649278741Sadrian * disable RX IQ Cal. 4650278741Sadrian */ 4651278741Sadrian if (is_scan) { 4652278741Sadrian ahp->ah_skip_rx_iq_cal = AH_TRUE; 4653278741Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 4654278741Sadrian "Skip RX IQ Cal due to scanning\n"); 4655278741Sadrian } else { 4656278741Sadrian#if 0 4657278741Sadrian /* XXX FreeBSD: always just do the RX IQ cal */ 4658278741Sadrian /* XXX I think it's just going to speed things up; I don't think it's to avoid chan bugs */ 4659278741Sadrian if (ahp->ah_rx_cal_complete && 4660278741Sadrian ahp->ah_rx_cal_chan == ichan->channel && 4661278741Sadrian ahp->ah_rx_cal_chan_flag == chan->channel_flags) { 4662278741Sadrian ahp->ah_skip_rx_iq_cal = AH_TRUE; 4663278741Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 4664278741Sadrian "Skip RX IQ Cal due to same channel with completed RX IQ Cal\n"); 4665278741Sadrian } else 4666278741Sadrian#endif 4667278741Sadrian ahp->ah_skip_rx_iq_cal = AH_FALSE; 4668278741Sadrian } 4669280829Sadrian 4670280829Sadrian /* FreeBSD: clear the channel survey data */ 4671280829Sadrian ath_hal_survey_clear(ah); 4672280829Sadrian 4673278741Sadrian /* 4674250003Sadrian * Fast channel change (Change synthesizer based on channel freq 4675250003Sadrian * without resetting chip) 4676250003Sadrian * Don't do it when 4677250003Sadrian * - Flag is not set 4678250003Sadrian * - Chip is just coming out of full sleep 4679250003Sadrian * - Channel to be set is same as current channel 4680250003Sadrian * - Channel flags are different, like when moving from 2GHz to 5GHz 4681250003Sadrian * channels 4682250003Sadrian * - Merlin: Switching in/out of fast clock enabled channels 4683250003Sadrian * (not currently coded, since fast clock is enabled 4684250003Sadrian * across the 5GHz band 4685250003Sadrian * and we already do a full reset when switching in/out 4686250003Sadrian * of 5GHz channels) 4687250003Sadrian */ 4688250008Sadrian#if 0 4689250003Sadrian if (b_channel_change && 4690250003Sadrian (ahp->ah_chip_full_sleep != AH_TRUE) && 4691250003Sadrian (AH_PRIVATE(ah)->ah_curchan != AH_NULL) && 4692250003Sadrian ((chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) && 4693250003Sadrian (((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & chan->channel_flags) == 4694250003Sadrian ((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & AH_PRIVATE(ah)->ah_curchan->channel_flags)))) 4695250003Sadrian { 4696250003Sadrian if (ar9300_channel_change(ah, chan, ichan, macmode)) { 4697250003Sadrian chan->channel_flags = ichan->channel_flags; 4698250003Sadrian chan->priv_flags = ichan->priv_flags; 4699250003Sadrian AH_PRIVATE(ah)->ah_curchan->ah_channel_time = 0; 4700250003Sadrian AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar9300_get_tsf64(ah); 4701250003Sadrian 4702250003Sadrian /* 4703250003Sadrian * Load the NF from history buffer of the current channel. 4704250003Sadrian * NF is slow time-variant, so it is OK to use a historical value. 4705250003Sadrian */ 4706250003Sadrian ar9300_get_nf_hist_base(ah, 4707250003Sadrian AH_PRIVATE(ah)->ah_curchan, is_scan, nf_buf); 4708250003Sadrian ar9300_load_nf(ah, nf_buf); 4709250003Sadrian 4710250003Sadrian /* start NF calibration, without updating BB NF register*/ 4711250003Sadrian ar9300_start_nf_cal(ah); 4712250003Sadrian 4713250003Sadrian /* 4714250003Sadrian * If channel_change completed and DMA was stopped 4715250003Sadrian * successfully - skip the rest of reset 4716250003Sadrian */ 4717250003Sadrian if (AH9300(ah)->ah_dma_stuck != AH_TRUE) { 4718250003Sadrian WAR_USB_DISABLE_PLL_LOCK_DETECT(ah); 4719250003Sadrian#if ATH_SUPPORT_MCI 4720250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) 4721250003Sadrian { 4722250003Sadrian ar9300_mci_2g5g_switch(ah, AH_TRUE); 4723250003Sadrian } 4724250003Sadrian#endif 4725250008Sadrian return HAL_OK; 4726250003Sadrian } 4727250003Sadrian } 4728250003Sadrian } 4729250008Sadrian#endif /* #if 0 */ 4730250003Sadrian 4731250003Sadrian#if ATH_SUPPORT_MCI 4732250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4733250003Sadrian ar9300_mci_disable_interrupt(ah); 4734250003Sadrian if (ahp->ah_mci_ready && !save_full_sleep) { 4735250003Sadrian ar9300_mci_mute_bt(ah); 4736250003Sadrian OS_DELAY(20); 4737250003Sadrian OS_REG_WRITE(ah, AR_BTCOEX_CTRL, 0); 4738250003Sadrian } 4739250003Sadrian 4740250003Sadrian ahp->ah_mci_bt_state = MCI_BT_SLEEP; 4741250003Sadrian ahp->ah_mci_ready = AH_FALSE; 4742250003Sadrian } 4743250003Sadrian#endif 4744250003Sadrian 4745250003Sadrian AH9300(ah)->ah_dma_stuck = AH_FALSE; 4746250003Sadrian#ifdef ATH_FORCE_PPM 4747250003Sadrian /* Preserve force ppm state */ 4748250003Sadrian save_force_val = 4749250003Sadrian OS_REG_READ(ah, AR_PHY_TIMING2) & 4750250003Sadrian (AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL); 4751250003Sadrian#endif 4752250003Sadrian /* 4753250003Sadrian * Preserve the antenna on a channel change 4754250003Sadrian */ 4755250003Sadrian save_def_antenna = OS_REG_READ(ah, AR_DEF_ANTENNA); 4756250003Sadrian if (0 == ahp->ah_smartantenna_enable ) 4757250003Sadrian { 4758250003Sadrian if (save_def_antenna == 0) { 4759250003Sadrian save_def_antenna = 1; 4760250003Sadrian } 4761250003Sadrian } 4762250003Sadrian 4763250003Sadrian /* Save hardware flag before chip reset clears the register */ 4764250003Sadrian mac_sta_id1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; 4765250003Sadrian 4766250003Sadrian /* Save led state from pci config register */ 4767250003Sadrian save_led_state = OS_REG_READ(ah, AR_CFG_LED) & 4768250003Sadrian (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | 4769250003Sadrian AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW); 4770250003Sadrian 4771250003Sadrian /* Mark PHY inactive prior to reset, to be undone in ar9300_init_bb () */ 4772250003Sadrian ar9300_mark_phy_inactive(ah); 4773250003Sadrian 4774250003Sadrian if (!ar9300_chip_reset(ah, chan)) { 4775250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: chip reset failed\n", __func__); 4776250003Sadrian FAIL(HAL_EIO); 4777250003Sadrian } 4778250003Sadrian 4779250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4780250003Sadrian 4781250003Sadrian 4782250003Sadrian /* Disable JTAG */ 4783250003Sadrian OS_REG_SET_BIT(ah, 4784250003Sadrian AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE); 4785250003Sadrian 4786250003Sadrian /* 4787250003Sadrian * Note that ar9300_init_chain_masks() is called from within 4788250003Sadrian * ar9300_process_ini() to ensure the swap bit is set before 4789250003Sadrian * the pdadc table is written. 4790250003Sadrian */ 4791250003Sadrian ecode = ar9300_process_ini(ah, chan, ichan, macmode); 4792250003Sadrian if (ecode != HAL_OK) { 4793250003Sadrian goto bad; 4794250003Sadrian } 4795250003Sadrian 4796250003Sadrian ahp->ah_immunity_on = AH_FALSE; 4797250003Sadrian 4798250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 4799250003Sadrian ahp->tx_iq_cal_enable = OS_REG_READ_FIELD(ah, 4800250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0(ah), 4801250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL) ? 4802250003Sadrian 1 : 0; 4803250003Sadrian } 4804250003Sadrian ahp->tx_cl_cal_enable = (OS_REG_READ(ah, AR_PHY_CL_CAL_CTL) & 4805250003Sadrian AR_PHY_CL_CAL_ENABLE) ? 1 : 0; 4806250003Sadrian 4807250003Sadrian /* For devices with full HW RIFS Rx support (Sowl/Howl/Merlin, etc), 4808250003Sadrian * restore register settings from prior to reset. 4809250003Sadrian */ 4810250003Sadrian if ((AH_PRIVATE(ah)->ah_curchan != AH_NULL) && 4811250003Sadrian (ar9300_get_capability(ah, HAL_CAP_LDPCWAR, 0, AH_NULL) == HAL_OK)) 4812250003Sadrian { 4813250003Sadrian /* Re-program RIFS Rx policy after reset */ 4814250003Sadrian ar9300_set_rifs_delay(ah, ahp->ah_rifs_enabled); 4815250003Sadrian } 4816250003Sadrian 4817250003Sadrian#if ATH_SUPPORT_MCI 4818250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4819250008Sadrian ar9300_mci_reset(ah, AH_FALSE, IS_CHAN_2GHZ(ichan), save_full_sleep); 4820250003Sadrian } 4821250003Sadrian#endif 4822250003Sadrian 4823250003Sadrian /* Initialize Management Frame Protection */ 4824250003Sadrian ar9300_init_mfp(ah); 4825250003Sadrian 4826250003Sadrian ahp->ah_immunity_vals[0] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4827250003Sadrian AR_PHY_SFCORR_LOW_M1_THRESH_LOW); 4828250003Sadrian ahp->ah_immunity_vals[1] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4829250003Sadrian AR_PHY_SFCORR_LOW_M2_THRESH_LOW); 4830250003Sadrian ahp->ah_immunity_vals[2] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4831250003Sadrian AR_PHY_SFCORR_M1_THRESH); 4832250003Sadrian ahp->ah_immunity_vals[3] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4833250003Sadrian AR_PHY_SFCORR_M2_THRESH); 4834250003Sadrian ahp->ah_immunity_vals[4] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4835250003Sadrian AR_PHY_SFCORR_M2COUNT_THR); 4836250003Sadrian ahp->ah_immunity_vals[5] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4837250003Sadrian AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW); 4838250003Sadrian 4839250003Sadrian /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ 4840250008Sadrian if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) { 4841250008Sadrian ar9300_set_delta_slope(ah, chan); 4842250003Sadrian } 4843250003Sadrian 4844250003Sadrian ar9300_spur_mitigate(ah, chan); 4845250008Sadrian if (!ar9300_eeprom_set_board_values(ah, chan)) { 4846250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4847250003Sadrian "%s: error setting board options\n", __func__); 4848250003Sadrian FAIL(HAL_EIO); 4849250003Sadrian } 4850250003Sadrian 4851250003Sadrian#ifdef ATH_HAL_WAR_REG16284_APH128 4852250003Sadrian /* temp work around, will be removed. */ 4853250003Sadrian if (AR_SREV_WASP(ah)) { 4854250003Sadrian OS_REG_WRITE(ah, 0x16284, 0x1553e000); 4855250003Sadrian } 4856250003Sadrian#endif 4857250003Sadrian 4858250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4859250003Sadrian 4860250003Sadrian OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); 4861250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) 4862250003Sadrian | mac_sta_id1 4863250003Sadrian | AR_STA_ID1_RTS_USE_DEF 4864250008Sadrian | (ah->ah_config.ath_hal_6mb_ack ? AR_STA_ID1_ACKCTS_6MB : 0) 4865250003Sadrian | ahp->ah_sta_id1_defaults 4866250003Sadrian ); 4867250003Sadrian ar9300_set_operating_mode(ah, opmode); 4868250003Sadrian 4869250003Sadrian /* Set Venice BSSID mask according to current state */ 4870250003Sadrian OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssid_mask)); 4871250003Sadrian OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssid_mask + 4)); 4872250003Sadrian 4873250003Sadrian /* Restore previous antenna */ 4874250003Sadrian OS_REG_WRITE(ah, AR_DEF_ANTENNA, save_def_antenna); 4875250003Sadrian#ifdef ATH_FORCE_PPM 4876250003Sadrian /* Restore force ppm state */ 4877250003Sadrian tmp_reg = OS_REG_READ(ah, AR_PHY_TIMING2) & 4878250003Sadrian ~(AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL); 4879250003Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING2, tmp_reg | save_force_val); 4880250003Sadrian#endif 4881250003Sadrian 4882250003Sadrian /* then our BSSID and assocID */ 4883250003Sadrian OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 4884250003Sadrian OS_REG_WRITE(ah, AR_BSS_ID1, 4885250003Sadrian LE_READ_2(ahp->ah_bssid + 4) | 4886250003Sadrian ((ahp->ah_assoc_id & 0x3fff) << AR_BSS_ID1_AID_S)); 4887250003Sadrian 4888250003Sadrian OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ 4889250003Sadrian 4890250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR); 4891250003Sadrian 4892250003Sadrian /* HW beacon processing */ 4893250008Sadrian /* 4894250008Sadrian * XXX what happens if I just leave filter_interval=0? 4895250008Sadrian * it stays disabled? 4896250008Sadrian */ 4897250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_BCN_WEIGHT, 4898250003Sadrian INIT_RSSI_BEACON_WEIGHT); 4899250003Sadrian OS_REG_SET_BIT(ah, AR_HWBCNPROC1, AR_HWBCNPROC1_CRC_ENABLE | 4900250003Sadrian AR_HWBCNPROC1_EXCLUDE_TIM_ELM); 4901250008Sadrian if (ah->ah_config.ath_hal_beacon_filter_interval) { 4902250003Sadrian OS_REG_RMW_FIELD(ah, AR_HWBCNPROC2, AR_HWBCNPROC2_FILTER_INTERVAL, 4903250008Sadrian ah->ah_config.ath_hal_beacon_filter_interval); 4904250003Sadrian OS_REG_SET_BIT(ah, AR_HWBCNPROC2, 4905250003Sadrian AR_HWBCNPROC2_FILTER_INTERVAL_ENABLE); 4906250003Sadrian } 4907250003Sadrian 4908250003Sadrian 4909250003Sadrian /* 4910250003Sadrian * Set Channel now modifies bank 6 parameters for FOWL workaround 4911250003Sadrian * to force rf_pwd_icsyndiv bias current as function of synth 4912250003Sadrian * frequency.Thus must be called after ar9300_process_ini() to ensure 4913250003Sadrian * analog register cache is valid. 4914250003Sadrian */ 4915250008Sadrian if (!ahp->ah_rf_hal.set_channel(ah, chan)) { 4916250003Sadrian FAIL(HAL_EIO); 4917250003Sadrian } 4918250003Sadrian 4919250003Sadrian 4920250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4921250003Sadrian 4922250003Sadrian /* Set 1:1 QCU to DCU mapping for all queues */ 4923250003Sadrian for (i = 0; i < AR_NUM_DCU; i++) { 4924250003Sadrian OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); 4925250003Sadrian } 4926250003Sadrian 4927250003Sadrian ahp->ah_intr_txqs = 0; 4928250008Sadrian for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) { 4929250003Sadrian ar9300_reset_tx_queue(ah, i); 4930250003Sadrian } 4931250003Sadrian 4932250003Sadrian ar9300_init_interrupt_masks(ah, opmode); 4933250003Sadrian 4934250003Sadrian /* Reset ier reference count to disabled */ 4935250008Sadrian// OS_ATOMIC_SET(&ahp->ah_ier_ref_count, 1); 4936250003Sadrian if (ath_hal_isrfkillenabled(ah)) { 4937250003Sadrian ar9300_enable_rf_kill(ah); 4938250003Sadrian } 4939250003Sadrian 4940250003Sadrian /* must be called AFTER ini is processed */ 4941250003Sadrian ar9300_ani_init_defaults(ah, macmode); 4942250003Sadrian 4943250003Sadrian ar9300_init_qos(ah); 4944250003Sadrian 4945250003Sadrian ar9300_init_user_settings(ah); 4946250003Sadrian 4947250003Sadrian 4948250003Sadrian AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ 4949250003Sadrian 4950250003Sadrian OS_MARK(ah, AH_MARK_RESET_DONE, 0); 4951250003Sadrian 4952250003Sadrian /* 4953250003Sadrian * disable seq number generation in hw 4954250003Sadrian */ 4955250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, 4956250003Sadrian OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); 4957250003Sadrian 4958250003Sadrian ar9300_set_dma(ah); 4959250003Sadrian 4960250003Sadrian /* 4961250003Sadrian * program OBS bus to see MAC interrupts 4962250003Sadrian */ 4963250003Sadrian#if ATH_SUPPORT_MCI 4964250008Sadrian if (!AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4965250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8); 4966250003Sadrian } 4967250003Sadrian#else 4968250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8); 4969250003Sadrian#endif 4970250003Sadrian 4971250003Sadrian 4972250003Sadrian /* enabling AR_GTTM_IGNORE_IDLE in GTTM register so that 4973250003Sadrian GTT timer will not increment if the channel idle indicates 4974250003Sadrian the air is busy or NAV is still counting down */ 4975250003Sadrian OS_REG_WRITE(ah, AR_GTTM, AR_GTTM_IGNORE_IDLE); 4976250003Sadrian 4977250003Sadrian /* 4978250003Sadrian * GTT debug mode setting 4979250003Sadrian */ 4980250003Sadrian /* 4981250003Sadrian OS_REG_WRITE(ah, 0x64, 0x00320000); 4982250003Sadrian OS_REG_WRITE(ah, 0x68, 7); 4983250003Sadrian OS_REG_WRITE(ah, 0x4080, 0xC); 4984250003Sadrian */ 4985250003Sadrian /* 4986250003Sadrian * Disable general interrupt mitigation by setting MIRT = 0x0 4987250003Sadrian * Rx and tx interrupt mitigation are conditionally enabled below. 4988250003Sadrian */ 4989250003Sadrian OS_REG_WRITE(ah, AR_MIRT, 0); 4990250003Sadrian if (ahp->ah_intr_mitigation_rx) { 4991250003Sadrian /* 4992250003Sadrian * Enable Interrupt Mitigation for Rx. 4993250003Sadrian * If no build-specific limits for the rx interrupt mitigation 4994250003Sadrian * timer have been specified, use conservative defaults. 4995250003Sadrian */ 4996250003Sadrian #ifndef AH_RIMT_VAL_LAST 4997250003Sadrian #define AH_RIMT_LAST_MICROSEC 500 4998250003Sadrian #endif 4999250003Sadrian #ifndef AH_RIMT_VAL_FIRST 5000250003Sadrian #define AH_RIMT_FIRST_MICROSEC 2000 5001250003Sadrian #endif 5002250003Sadrian#ifndef HOST_OFFLOAD 5003250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, AH_RIMT_LAST_MICROSEC); 5004250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, AH_RIMT_FIRST_MICROSEC); 5005250003Sadrian#else 5006250003Sadrian /* lower mitigation level to reduce latency for offload arch. */ 5007250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 5008250003Sadrian (AH_RIMT_LAST_MICROSEC >> 2)); 5009250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 5010250003Sadrian (AH_RIMT_FIRST_MICROSEC >> 2)); 5011250003Sadrian#endif 5012250003Sadrian } 5013250003Sadrian 5014250003Sadrian if (ahp->ah_intr_mitigation_tx) { 5015250003Sadrian /* 5016250003Sadrian * Enable Interrupt Mitigation for Tx. 5017250003Sadrian * If no build-specific limits for the tx interrupt mitigation 5018250003Sadrian * timer have been specified, use the values preferred for 5019250003Sadrian * the carrier group's products. 5020250003Sadrian */ 5021250003Sadrian #ifndef AH_TIMT_LAST 5022250003Sadrian #define AH_TIMT_LAST_MICROSEC 300 5023250003Sadrian #endif 5024250003Sadrian #ifndef AH_TIMT_FIRST 5025250003Sadrian #define AH_TIMT_FIRST_MICROSEC 750 5026250003Sadrian #endif 5027250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, AH_TIMT_LAST_MICROSEC); 5028250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, AH_TIMT_FIRST_MICROSEC); 5029250003Sadrian } 5030250003Sadrian 5031250003Sadrian rx_chainmask = ahp->ah_rx_chainmask; 5032250003Sadrian 5033250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 5034250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 5035250003Sadrian 5036250003Sadrian ar9300_init_bb(ah, chan); 5037250003Sadrian 5038250003Sadrian /* BB Step 7: Calibration */ 5039278741Sadrian /* 5040278741Sadrian * Only kick off calibration not on offchan. 5041278741Sadrian * If coming back from offchan, restore prevous Cal results 5042278741Sadrian * since chip reset will clear existings. 5043278741Sadrian */ 5044278741Sadrian if (!ahp->ah_skip_rx_iq_cal) { 5045278741Sadrian int i; 5046278741Sadrian /* clear existing RX cal data */ 5047278741Sadrian for (i=0; i<AR9300_MAX_CHAINS; i++) 5048278741Sadrian ahp->ah_rx_cal_corr[i] = 0; 5049278741Sadrian 5050278741Sadrian ahp->ah_rx_cal_complete = AH_FALSE; 5051278741Sadrian// ahp->ah_rx_cal_chan = chan->channel; 5052278741Sadrian// ahp->ah_rx_cal_chan_flag = ichan->channel_flags; 5053278741Sadrian ahp->ah_rx_cal_chan = 0; 5054278741Sadrian ahp->ah_rx_cal_chan_flag = 0; /* XXX FreeBSD */ 5055278741Sadrian } 5056250003Sadrian ar9300_invalidate_saved_cals(ah, ichan); 5057250003Sadrian cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); 5058250003Sadrian 5059250003Sadrian#if ATH_SUPPORT_MCI 5060250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { 5061250008Sadrian if (IS_CHAN_2GHZ(ichan) && 5062250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_SLEEP)) 5063250003Sadrian { 5064250003Sadrian if (ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || 5065250003Sadrian ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) 5066250003Sadrian { 5067250003Sadrian /* 5068250003Sadrian * BT is sleeping. Check if BT wakes up duing WLAN 5069250003Sadrian * calibration. If BT wakes up during WLAN calibration, need 5070250003Sadrian * to go through all message exchanges again and recal. 5071250003Sadrian */ 5072250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 5073250003Sadrian "(MCI) ### %s: BT wakes up during WLAN calibration.\n", 5074250003Sadrian __func__); 5075250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 5076250003Sadrian AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | 5077250003Sadrian AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); 5078250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) send REMOTE_RESET\n"); 5079250003Sadrian ar9300_mci_remote_reset(ah, AH_TRUE); 5080250003Sadrian ar9300_mci_send_sys_waking(ah, AH_TRUE); 5081250003Sadrian OS_DELAY(1); 5082250008Sadrian if (IS_CHAN_2GHZ(ichan)) { 5083250003Sadrian ar9300_mci_send_lna_transfer(ah, AH_TRUE); 5084250003Sadrian } 5085250003Sadrian ahp->ah_mci_bt_state = MCI_BT_AWAKE; 5086250003Sadrian 5087250003Sadrian /* Redo calibration */ 5088250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Re-calibrate.\n", 5089250003Sadrian __func__); 5090250003Sadrian ar9300_invalidate_saved_cals(ah, ichan); 5091250008Sadrian cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); 5092250003Sadrian } 5093250003Sadrian } 5094250003Sadrian ar9300_mci_enable_interrupt(ah); 5095250003Sadrian } 5096250003Sadrian#endif 5097250003Sadrian 5098250003Sadrian if (!cal_ret) { 5099250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Init Cal Failed\n", __func__); 5100250003Sadrian FAIL(HAL_ESELFTEST); 5101250003Sadrian } 5102250003Sadrian 5103250003Sadrian ar9300_init_txbf(ah); 5104250003Sadrian#if 0 5105250003Sadrian /* 5106250003Sadrian * WAR for owl 1.0 - restore chain mask for 2-chain cfgs after cal 5107250003Sadrian */ 5108250003Sadrian rx_chainmask = ahp->ah_rx_chainmask; 5109250003Sadrian if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { 5110250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 5111250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 5112250003Sadrian } 5113250003Sadrian#endif 5114250003Sadrian 5115250003Sadrian /* Restore previous led state */ 5116250003Sadrian OS_REG_WRITE(ah, AR_CFG_LED, save_led_state | AR_CFG_SCLK_32KHZ); 5117250003Sadrian 5118250008Sadrian#if ATH_BT_COEX 5119250003Sadrian if (ahp->ah_bt_coex_config_type != HAL_BT_COEX_CFG_NONE) { 5120250003Sadrian ar9300_init_bt_coex(ah); 5121250003Sadrian 5122250003Sadrian#if ATH_SUPPORT_MCI 5123250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { 5124250003Sadrian /* Check BT state again to make sure it's not changed. */ 5125250003Sadrian ar9300_mci_sync_bt_state(ah); 5126250003Sadrian ar9300_mci_2g5g_switch(ah, AH_TRUE); 5127250003Sadrian 5128250003Sadrian if ((ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 5129250003Sadrian (ahp->ah_mci_query_bt == AH_TRUE)) 5130250003Sadrian { 5131250003Sadrian ahp->ah_mci_need_flush_btinfo = AH_TRUE; 5132250003Sadrian } 5133250003Sadrian } 5134250003Sadrian#endif 5135250003Sadrian } 5136250003Sadrian#endif 5137250003Sadrian 5138250003Sadrian /* Start TSF2 for generic timer 8-15. */ 5139250003Sadrian ar9300_start_tsf2(ah); 5140250003Sadrian 5141250003Sadrian /* MIMO Power save setting */ 5142250003Sadrian if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) == HAL_OK) { 5143250003Sadrian ar9300_set_sm_power_mode(ah, ahp->ah_sm_power_mode); 5144250003Sadrian } 5145250003Sadrian 5146250003Sadrian /* 5147250003Sadrian * For big endian systems turn on swapping for descriptors 5148250003Sadrian */ 5149250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 5150250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 5151250003Sadrian OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB, 0); 5152250003Sadrian } else { 5153250003Sadrian ar9300_init_cfg_reg(ah); 5154250003Sadrian } 5155250003Sadrian#endif 5156250003Sadrian 5157250003Sadrian if ( AR_SREV_OSPREY(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 5158250003Sadrian OS_REG_RMW(ah, AR_CFG_LED, AR_CFG_LED_ASSOC_CTL, AR_CFG_LED_ASSOC_CTL); 5159250003Sadrian } 5160250003Sadrian 5161250003Sadrian#if !(defined(ART_BUILD)) && defined(ATH_SUPPORT_LED) 5162250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 5163250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 5164250003Sadrian#define ATH_GPIO_OUT_FUNCTION3 0xB8040038 5165250003Sadrian#define ATH_GPIO_OE 0xB8040000 5166250003Sadrian if ( AR_SREV_WASP(ah)) { 5167250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 5168250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x33 << 8) ); 5169250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) ))); 5170250003Sadrian } 5171250003Sadrian else { 5172250003Sadrian 5173250003Sadrian /* Disable 2G WLAN LED. During ath_open, reset function is called even before channel is set. 5174250003Sadrian So 2GHz is taken as default and it also blinks. Hence 5175250003Sadrian to avoid both from blinking, disable 2G led while in 5G mode */ 5176250003Sadrian 5177250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) | (1 << 13) )); 5178250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x33) ); 5179250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) ))); 5180250003Sadrian } 5181250003Sadrian 5182250003Sadrian } 5183250003Sadrian else if (AR_SREV_SCORPION(ah)) { 5184250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 5185250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x2F << 8) ); 5186250003Sadrian REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )) | (0x1 << 12))); 5187250003Sadrian } else if (IS_CHAN_5GHZ((AH_PRIVATE(ah)->ah_curchan))) { 5188250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x2F) ); 5189250003Sadrian REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )) | (0x1 << 13))); 5190250003Sadrian } 5191250003Sadrian } 5192250003Sadrian#undef REG_READ 5193250003Sadrian#undef REG_WRITE 5194250003Sadrian#endif 5195250003Sadrian 5196250008Sadrian /* XXX FreeBSD What's this? -adrian */ 5197250008Sadrian#if 0 5198250003Sadrian chan->channel_flags = ichan->channel_flags; 5199250003Sadrian chan->priv_flags = ichan->priv_flags; 5200250008Sadrian#endif 5201250003Sadrian 5202250003Sadrian#if FIX_NOISE_FLOOR 5203250008Sadrian /* XXX FreeBSD is ichan appropariate? It was curchan.. */ 5204250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 5205250003Sadrian ar9300_load_nf(ah, nf_buf); 5206250003Sadrian if (nf_hist_buff_reset == 1) 5207250003Sadrian { 5208250003Sadrian nf_hist_buff_reset = 0; 5209250003Sadrian #ifndef ATH_NF_PER_CHAN 5210250003Sadrian if (First_NFCal(ah, ichan, is_scan, chan)){ 5211278741Sadrian if (ahp->ah_skip_rx_iq_cal && !is_scan) { 5212278741Sadrian /* restore RX Cal result if existing */ 5213278741Sadrian ar9300_rx_iq_cal_restore(ah); 5214278741Sadrian ahp->ah_skip_rx_iq_cal = AH_FALSE; 5215278741Sadrian } 5216250003Sadrian } 5217250003Sadrian #endif /* ATH_NF_PER_CHAN */ 5218250003Sadrian } 5219250003Sadrian else{ 5220250003Sadrian ar9300_start_nf_cal(ah); 5221250003Sadrian } 5222250003Sadrian#endif 5223250003Sadrian 5224250003Sadrian#ifdef AH_SUPPORT_AR9300 5225250003Sadrian /* BB Panic Watchdog */ 5226250003Sadrian if (ar9300_get_capability(ah, HAL_CAP_BB_PANIC_WATCHDOG, 0, AH_NULL) == 5227250003Sadrian HAL_OK) 5228250003Sadrian { 5229250003Sadrian ar9300_config_bb_panic_watchdog(ah); 5230250003Sadrian } 5231250003Sadrian#endif 5232250003Sadrian 5233250003Sadrian /* While receiving unsupported rate frame receive state machine 5234250003Sadrian * gets into a state 0xb and if phy_restart happens when rx 5235250003Sadrian * state machine is in 0xb state, BB would go hang, if we 5236250003Sadrian * see 0xb state after first bb panic, make sure that we 5237250003Sadrian * disable the phy_restart. 5238250003Sadrian * 5239250003Sadrian * There may be multiple panics, make sure that we always do 5240250003Sadrian * this if we see this panic at least once. This is required 5241250003Sadrian * because reset seems to be writing from INI file. 5242250003Sadrian */ 5243250003Sadrian if ((ar9300_get_capability(ah, HAL_CAP_PHYRESTART_CLR_WAR, 0, AH_NULL) 5244250008Sadrian == HAL_OK) && (((MS((AH9300(ah)->ah_bb_panic_last_status), 5245250003Sadrian AR_PHY_BB_WD_RX_OFDM_SM)) == 0xb) || 5246250008Sadrian AH9300(ah)->ah_phyrestart_disabled) ) 5247250003Sadrian { 5248250003Sadrian ar9300_disable_phy_restart(ah, 1); 5249250003Sadrian } 5250250003Sadrian 5251250003Sadrian 5252250003Sadrian 5253250003Sadrian ahp->ah_radar1 = MS(OS_REG_READ(ah, AR_PHY_RADAR_1), 5254250003Sadrian AR_PHY_RADAR_1_CF_BIN_THRESH); 5255250003Sadrian ahp->ah_dc_offset = MS(OS_REG_READ(ah, AR_PHY_TIMING2), 5256250003Sadrian AR_PHY_TIMING2_DC_OFFSET); 5257250003Sadrian ahp->ah_disable_cck = MS(OS_REG_READ(ah, AR_PHY_MODE), 5258250003Sadrian AR_PHY_MODE_DISABLE_CCK); 5259250003Sadrian 5260250008Sadrian if (AH9300(ah)->ah_enable_keysearch_always) { 5261250003Sadrian ar9300_enable_keysearch_always(ah, 1); 5262250003Sadrian } 5263250003Sadrian 5264250003Sadrian#if ATH_LOW_POWER_ENABLE 5265250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val) 5266250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 5267250003Sadrian if (AR_SREV_OSPREY(ah)) { 5268250003Sadrian REG_WRITE(0xb4000080, REG_READ(0xb4000080) | 3); 5269250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 5270250003Sadrian OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), 5271250003Sadrian AR_PCIE_PM_CTRL_ENA); 5272250003Sadrian OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_SPARE), 0xffffffff); 5273250003Sadrian } 5274250003Sadrian#undef REG_READ 5275250003Sadrian#undef REG_WRITE 5276250003Sadrian#endif /* ATH_LOW_POWER_ENABLE */ 5277250003Sadrian 5278250003Sadrian WAR_USB_DISABLE_PLL_LOCK_DETECT(ah); 5279250003Sadrian 5280250003Sadrian /* H/W Green TX */ 5281250003Sadrian ar9300_control_signals_for_green_tx_mode(ah); 5282250003Sadrian /* Smart Antenna, only for 5GHz on Scropion */ 5283250008Sadrian if (IEEE80211_IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan)) && AR_SREV_SCORPION(ah)) { 5284250003Sadrian ahp->ah_smartantenna_enable = 0; 5285250003Sadrian } 5286250003Sadrian 5287250003Sadrian ar9300_set_smart_antenna(ah, ahp->ah_smartantenna_enable); 5288250003Sadrian 5289278741Sadrian if (ahp->ah_skip_rx_iq_cal && !is_scan) { 5290278741Sadrian /* restore RX Cal result if existing */ 5291278741Sadrian ar9300_rx_iq_cal_restore(ah); 5292278741Sadrian ahp->ah_skip_rx_iq_cal = AH_FALSE; 5293278741Sadrian } 5294250003Sadrian 5295278741Sadrian 5296250003Sadrian return AH_TRUE; 5297250003Sadrianbad: 5298250003Sadrian OS_MARK(ah, AH_MARK_RESET_DONE, ecode); 5299250003Sadrian *status = ecode; 5300250003Sadrian 5301278741Sadrian if (ahp->ah_skip_rx_iq_cal && !is_scan) { 5302278741Sadrian /* restore RX Cal result if existing */ 5303278741Sadrian ar9300_rx_iq_cal_restore(ah); 5304278741Sadrian ahp->ah_skip_rx_iq_cal = AH_FALSE; 5305278741Sadrian } 5306278741Sadrian 5307250003Sadrian return AH_FALSE; 5308250003Sadrian#undef FAIL 5309250003Sadrian} 5310250003Sadrian 5311250003Sadrianvoid 5312250003Sadrianar9300_green_ap_ps_on_off( struct ath_hal *ah, u_int16_t on_off) 5313250003Sadrian{ 5314250003Sadrian /* Set/reset the ps flag */ 5315250008Sadrian AH9300(ah)->green_ap_ps_on = !!on_off; 5316250003Sadrian} 5317250003Sadrian 5318250003Sadrian/* 5319250003Sadrian * This function returns 1, where it is possible to do 5320250003Sadrian * single-chain power save. 5321250003Sadrian */ 5322250003Sadrianu_int16_t 5323250003Sadrianar9300_is_single_ant_power_save_possible(struct ath_hal *ah) 5324250003Sadrian{ 5325250003Sadrian return AH_TRUE; 5326250003Sadrian} 5327250003Sadrian 5328250003Sadrian/* To avoid compilation warnings. Functions not used when EMULATION. */ 5329250003Sadrian/* 5330250003Sadrian * ar9300_find_mag_approx() 5331250003Sadrian */ 5332250003Sadrianstatic int32_t 5333250003Sadrianar9300_find_mag_approx(struct ath_hal *ah, int32_t in_re, int32_t in_im) 5334250003Sadrian{ 5335250003Sadrian int32_t abs_i = abs(in_re); 5336250003Sadrian int32_t abs_q = abs(in_im); 5337250003Sadrian int32_t max_abs, min_abs; 5338250003Sadrian 5339250003Sadrian if (abs_i > abs_q) { 5340250003Sadrian max_abs = abs_i; 5341250003Sadrian min_abs = abs_q; 5342250003Sadrian } else { 5343250003Sadrian max_abs = abs_q; 5344250003Sadrian min_abs = abs_i; 5345250003Sadrian } 5346250003Sadrian 5347250003Sadrian return (max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4)); 5348250003Sadrian} 5349250003Sadrian 5350250003Sadrian/* 5351250003Sadrian * ar9300_solve_iq_cal() 5352250003Sadrian * solve 4x4 linear equation used in loopback iq cal. 5353250003Sadrian */ 5354250003Sadrianstatic HAL_BOOL 5355250003Sadrianar9300_solve_iq_cal( 5356250003Sadrian struct ath_hal *ah, 5357250003Sadrian int32_t sin_2phi_1, 5358250003Sadrian int32_t cos_2phi_1, 5359250003Sadrian int32_t sin_2phi_2, 5360250003Sadrian int32_t cos_2phi_2, 5361250003Sadrian int32_t mag_a0_d0, 5362250003Sadrian int32_t phs_a0_d0, 5363250003Sadrian int32_t mag_a1_d0, 5364250003Sadrian int32_t phs_a1_d0, 5365250003Sadrian int32_t solved_eq[]) 5366250003Sadrian{ 5367250003Sadrian int32_t f1 = cos_2phi_1 - cos_2phi_2; 5368250003Sadrian int32_t f3 = sin_2phi_1 - sin_2phi_2; 5369250003Sadrian int32_t f2; 5370250003Sadrian int32_t mag_tx, phs_tx, mag_rx, phs_rx; 5371250003Sadrian const int32_t result_shift = 1 << 15; 5372250003Sadrian 5373250003Sadrian f2 = (((int64_t)f1 * (int64_t)f1) / result_shift) + (((int64_t)f3 * (int64_t)f3) / result_shift); 5374250003Sadrian 5375250003Sadrian if (0 == f2) { 5376250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d).\n", 5377250003Sadrian __func__, __LINE__); 5378250003Sadrian return AH_FALSE; 5379250003Sadrian } 5380250003Sadrian 5381250003Sadrian /* magnitude mismatch, tx */ 5382250003Sadrian mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0); 5383250003Sadrian /* phase mismatch, tx */ 5384250003Sadrian phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0); 5385250003Sadrian 5386250003Sadrian mag_tx = (mag_tx / f2); 5387250003Sadrian phs_tx = (phs_tx / f2); 5388250003Sadrian 5389250003Sadrian /* magnitude mismatch, rx */ 5390250003Sadrian mag_rx = 5391250003Sadrian mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / result_shift; 5392250003Sadrian /* phase mismatch, rx */ 5393250003Sadrian phs_rx = 5394250003Sadrian phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / result_shift; 5395250003Sadrian 5396250003Sadrian solved_eq[0] = mag_tx; 5397250003Sadrian solved_eq[1] = phs_tx; 5398250003Sadrian solved_eq[2] = mag_rx; 5399250003Sadrian solved_eq[3] = phs_rx; 5400250003Sadrian 5401250003Sadrian return AH_TRUE; 5402250003Sadrian} 5403250003Sadrian 5404250003Sadrian/* 5405250003Sadrian * ar9300_calc_iq_corr() 5406250003Sadrian */ 5407250003Sadrianstatic HAL_BOOL 5408250003Sadrianar9300_calc_iq_corr(struct ath_hal *ah, int32_t chain_idx, 5409250003Sadrian const int32_t iq_res[], int32_t iqc_coeff[]) 5410250003Sadrian{ 5411250003Sadrian int32_t i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0; 5412250003Sadrian int32_t i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1; 5413250003Sadrian int32_t i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0; 5414250003Sadrian int32_t i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1; 5415250003Sadrian int32_t mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1; 5416250003Sadrian int32_t phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1; 5417250003Sadrian int32_t sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2; 5418250003Sadrian int32_t mag_tx, phs_tx, mag_rx, phs_rx; 5419250003Sadrian int32_t solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx; 5420250003Sadrian int32_t q_q_coff, q_i_coff; 5421250003Sadrian const int32_t res_scale = 1 << 15; 5422250003Sadrian const int32_t delpt_shift = 1 << 8; 5423250003Sadrian int32_t mag1, mag2; 5424250003Sadrian 5425250003Sadrian i2_m_q2_a0_d0 = iq_res[0] & 0xfff; 5426250003Sadrian i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff; 5427250003Sadrian iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8); 5428250003Sadrian 5429250003Sadrian if (i2_m_q2_a0_d0 > 0x800) { 5430250003Sadrian i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1); 5431250003Sadrian } 5432250003Sadrian if (iq_corr_a0_d0 > 0x800) { 5433250003Sadrian iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1); 5434250003Sadrian } 5435250003Sadrian 5436250003Sadrian i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff; 5437250003Sadrian i2_p_q2_a0_d1 = (iq_res[2] & 0xfff); 5438250003Sadrian iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff; 5439250003Sadrian 5440250003Sadrian if (i2_m_q2_a0_d1 > 0x800) { 5441250003Sadrian i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); 5442250003Sadrian } 5443250003Sadrian if (iq_corr_a0_d1 > 0x800) { 5444250003Sadrian iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); 5445250003Sadrian } 5446250003Sadrian 5447250003Sadrian i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8); 5448250003Sadrian i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff; 5449250003Sadrian iq_corr_a1_d0 = iq_res[4] & 0xfff; 5450250003Sadrian 5451250003Sadrian if (i2_m_q2_a1_d0 > 0x800) { 5452250003Sadrian i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1); 5453250003Sadrian } 5454250003Sadrian if (iq_corr_a1_d0 > 0x800) { 5455250003Sadrian iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1); 5456250003Sadrian } 5457250003Sadrian 5458250003Sadrian i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff; 5459250003Sadrian i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8); 5460250003Sadrian iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff; 5461250003Sadrian 5462250003Sadrian if (i2_m_q2_a1_d1 > 0x800) { 5463250003Sadrian i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1); 5464250003Sadrian } 5465250003Sadrian if (iq_corr_a1_d1 > 0x800) { 5466250003Sadrian iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1); 5467250003Sadrian } 5468250003Sadrian 5469250003Sadrian if ((i2_p_q2_a0_d0 == 0) || 5470250003Sadrian (i2_p_q2_a0_d1 == 0) || 5471250003Sadrian (i2_p_q2_a1_d0 == 0) || 5472250003Sadrian (i2_p_q2_a1_d1 == 0)) { 5473250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5474250003Sadrian "%s: Divide by 0(%d):\na0_d0=%d\na0_d1=%d\na2_d0=%d\na1_d1=%d\n", 5475250003Sadrian __func__, __LINE__, 5476250003Sadrian i2_p_q2_a0_d0, i2_p_q2_a0_d1, i2_p_q2_a1_d0, i2_p_q2_a1_d1); 5477250003Sadrian return AH_FALSE; 5478250003Sadrian } 5479250003Sadrian 5480250003Sadrian if ((i2_p_q2_a0_d0 <= 1024) || (i2_p_q2_a0_d0 > 2047) || 5481250003Sadrian (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) || 5482250003Sadrian (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) || 5483250003Sadrian (i2_p_q2_a0_d0 <= iq_corr_a0_d0) || 5484250003Sadrian (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) || 5485250003Sadrian (i2_p_q2_a0_d1 <= iq_corr_a0_d1) || 5486250003Sadrian (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) || 5487250003Sadrian (i2_p_q2_a1_d0 <= iq_corr_a1_d0) || 5488250003Sadrian (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) || 5489250003Sadrian (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) { 5490250003Sadrian return AH_FALSE; 5491250003Sadrian } 5492250003Sadrian 5493250003Sadrian mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; 5494250003Sadrian phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; 5495250003Sadrian 5496250003Sadrian mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1; 5497250003Sadrian phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1; 5498250003Sadrian 5499250003Sadrian mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0; 5500250003Sadrian phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0; 5501250003Sadrian 5502250003Sadrian mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1; 5503250003Sadrian phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1; 5504250003Sadrian 5505250003Sadrian /* without analog phase shift */ 5506250003Sadrian sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT); 5507250003Sadrian /* without analog phase shift */ 5508250003Sadrian cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT); 5509250003Sadrian /* with analog phase shift */ 5510250003Sadrian sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT); 5511250003Sadrian /* with analog phase shift */ 5512250003Sadrian cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT); 5513250003Sadrian 5514250003Sadrian /* force sin^2 + cos^2 = 1; */ 5515250003Sadrian /* find magnitude by approximation */ 5516250003Sadrian mag1 = ar9300_find_mag_approx(ah, cos_2phi_1, sin_2phi_1); 5517250003Sadrian mag2 = ar9300_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); 5518250003Sadrian 5519250003Sadrian if ((mag1 == 0) || (mag2 == 0)) { 5520250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5521250003Sadrian "%s: Divide by 0(%d): mag1=%d, mag2=%d\n", 5522250003Sadrian __func__, __LINE__, mag1, mag2); 5523250003Sadrian return AH_FALSE; 5524250003Sadrian } 5525250003Sadrian 5526250003Sadrian /* normalization sin and cos by mag */ 5527250003Sadrian sin_2phi_1 = (sin_2phi_1 * res_scale / mag1); 5528250003Sadrian cos_2phi_1 = (cos_2phi_1 * res_scale / mag1); 5529250003Sadrian sin_2phi_2 = (sin_2phi_2 * res_scale / mag2); 5530250003Sadrian cos_2phi_2 = (cos_2phi_2 * res_scale / mag2); 5531250003Sadrian 5532250003Sadrian /* calculate IQ mismatch */ 5533250008Sadrian if (AH_FALSE == ar9300_solve_iq_cal(ah, 5534250003Sadrian sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2, mag_a0_d0, 5535250003Sadrian phs_a0_d0, mag_a1_d0, phs_a1_d0, solved_eq)) 5536250003Sadrian { 5537250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5538250003Sadrian "%s: Call to ar9300_solve_iq_cal failed.\n", __func__); 5539250003Sadrian return AH_FALSE; 5540250003Sadrian } 5541250003Sadrian 5542250003Sadrian mag_tx = solved_eq[0]; 5543250003Sadrian phs_tx = solved_eq[1]; 5544250003Sadrian mag_rx = solved_eq[2]; 5545250003Sadrian phs_rx = solved_eq[3]; 5546250003Sadrian 5547250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5548250003Sadrian "%s: chain %d: mag mismatch=%d phase mismatch=%d\n", 5549250003Sadrian __func__, chain_idx, mag_tx / res_scale, phs_tx / res_scale); 5550250003Sadrian 5551250003Sadrian if (res_scale == mag_tx) { 5552250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5553250003Sadrian "%s: Divide by 0(%d): mag_tx=%d, res_scale=%d\n", 5554250003Sadrian __func__, __LINE__, mag_tx, res_scale); 5555250003Sadrian return AH_FALSE; 5556250003Sadrian } 5557250003Sadrian 5558250003Sadrian /* calculate and quantize Tx IQ correction factor */ 5559250003Sadrian mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx); 5560250003Sadrian phs_corr_tx = -phs_tx; 5561250003Sadrian 5562250003Sadrian q_q_coff = (mag_corr_tx * 128 / res_scale); 5563250003Sadrian q_i_coff = (phs_corr_tx * 256 / res_scale); 5564250003Sadrian 5565250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5566250003Sadrian "%s: tx chain %d: mag corr=%d phase corr=%d\n", 5567250003Sadrian __func__, chain_idx, q_q_coff, q_i_coff); 5568250003Sadrian 5569250003Sadrian if (q_i_coff < -63) { 5570250003Sadrian q_i_coff = -63; 5571250003Sadrian } 5572250003Sadrian if (q_i_coff > 63) { 5573250003Sadrian q_i_coff = 63; 5574250003Sadrian } 5575250003Sadrian if (q_q_coff < -63) { 5576250003Sadrian q_q_coff = -63; 5577250003Sadrian } 5578250003Sadrian if (q_q_coff > 63) { 5579250003Sadrian q_q_coff = 63; 5580250003Sadrian } 5581250003Sadrian 5582250003Sadrian iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); 5583250003Sadrian 5584250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: tx chain %d: iq corr coeff=%x\n", 5585250003Sadrian __func__, chain_idx, iqc_coeff[0]); 5586250003Sadrian 5587250003Sadrian if (-mag_rx == res_scale) { 5588250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5589250003Sadrian "%s: Divide by 0(%d): mag_rx=%d, res_scale=%d\n", 5590250003Sadrian __func__, __LINE__, mag_rx, res_scale); 5591250003Sadrian return AH_FALSE; 5592250003Sadrian } 5593250003Sadrian 5594250003Sadrian /* calculate and quantize Rx IQ correction factors */ 5595250003Sadrian mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx); 5596250003Sadrian phs_corr_rx = -phs_rx; 5597250003Sadrian 5598250003Sadrian q_q_coff = (mag_corr_rx * 128 / res_scale); 5599250003Sadrian q_i_coff = (phs_corr_rx * 256 / res_scale); 5600250003Sadrian 5601250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5602250003Sadrian "%s: rx chain %d: mag corr=%d phase corr=%d\n", 5603250003Sadrian __func__, chain_idx, q_q_coff, q_i_coff); 5604250003Sadrian 5605250003Sadrian if (q_i_coff < -63) { 5606250003Sadrian q_i_coff = -63; 5607250003Sadrian } 5608250003Sadrian if (q_i_coff > 63) { 5609250003Sadrian q_i_coff = 63; 5610250003Sadrian } 5611250003Sadrian if (q_q_coff < -63) { 5612250003Sadrian q_q_coff = -63; 5613250003Sadrian } 5614250003Sadrian if (q_q_coff > 63) { 5615250003Sadrian q_q_coff = 63; 5616250003Sadrian } 5617250003Sadrian 5618250003Sadrian iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); 5619250003Sadrian 5620250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: rx chain %d: iq corr coeff=%x\n", 5621250003Sadrian __func__, chain_idx, iqc_coeff[1]); 5622250003Sadrian 5623250003Sadrian return AH_TRUE; 5624250003Sadrian} 5625250003Sadrian 5626250003Sadrian#define MAX_MAG_DELTA 11 //maximum magnitude mismatch delta across gains 5627250003Sadrian#define MAX_PHS_DELTA 10 //maximum phase mismatch delta across gains 5628250003Sadrian#define ABS(x) ((x) >= 0 ? (x) : (-(x))) 5629250003Sadrian 5630250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5631250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5632250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5633250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5634250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5635250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5636250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5637250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5638250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5639250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5640250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5641250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5642250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5643250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5644250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5645250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5646250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5647250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5648250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5649250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5650250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5651250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5652250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5653250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5654250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5655250003Sadrian }; 5656250003Sadrian 5657250003Sadrianstatic void 5658250003Sadrianar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, u_int32_t num_chains, 5659250008Sadrian struct coeff_t *coeff, HAL_BOOL is_cal_reusable) 5660250003Sadrian{ 5661250003Sadrian int nmeasurement, ch_idx, im; 5662250003Sadrian int32_t magnitude, phase; 5663250003Sadrian int32_t magnitude_max, phase_max; 5664250003Sadrian int32_t magnitude_min, phase_min; 5665250003Sadrian 5666250003Sadrian int32_t magnitude_max_idx, phase_max_idx; 5667250003Sadrian int32_t magnitude_min_idx, phase_min_idx; 5668250003Sadrian 5669250003Sadrian int32_t magnitude_avg, phase_avg; 5670250003Sadrian int32_t outlier_mag_idx = 0; 5671250003Sadrian int32_t outlier_phs_idx = 0; 5672250003Sadrian 5673250003Sadrian 5674250003Sadrian if (AR_SREV_POSEIDON(ah)) { 5675250003Sadrian HALASSERT(num_chains == 0x1); 5676250003Sadrian 5677250003Sadrian tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5678250003Sadrian tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5679250003Sadrian tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5680250003Sadrian tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5681250003Sadrian tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5682250003Sadrian tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5683250003Sadrian tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5684250003Sadrian tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5685250003Sadrian } 5686250003Sadrian 5687250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5688250003Sadrian nmeasurement = OS_REG_READ_FIELD(ah, 5689250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); 5690250003Sadrian if (nmeasurement > MAX_MEASUREMENT) { 5691250003Sadrian nmeasurement = MAX_MEASUREMENT; 5692250003Sadrian } 5693250003Sadrian 5694250003Sadrian if (!AR_SREV_SCORPION(ah)) { 5695250003Sadrian /* 5696250003Sadrian * reset max/min variable to min/max values so that 5697250003Sadrian * we always start with 1st calibrated gain value 5698250003Sadrian */ 5699250003Sadrian magnitude_max = -64; 5700250003Sadrian phase_max = -64; 5701250003Sadrian magnitude_min = 63; 5702250003Sadrian phase_min = 63; 5703250003Sadrian magnitude_avg = 0; 5704250003Sadrian phase_avg = 0; 5705250003Sadrian magnitude_max_idx = 0; 5706250003Sadrian magnitude_min_idx = 0; 5707250003Sadrian phase_max_idx = 0; 5708250003Sadrian phase_min_idx = 0; 5709250003Sadrian 5710250003Sadrian /* detect outlier only if nmeasurement > 1 */ 5711250003Sadrian if (nmeasurement > 1) { 5712250003Sadrian /* printf("----------- start outlier detection -----------\n"); */ 5713250003Sadrian /* 5714250003Sadrian * find max/min and phase/mag mismatch across all calibrated gains 5715250003Sadrian */ 5716250003Sadrian for (im = 0; im < nmeasurement; im++) { 5717250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5718250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5719250003Sadrian 5720250003Sadrian magnitude_avg = magnitude_avg + magnitude; 5721250003Sadrian phase_avg = phase_avg + phase; 5722250003Sadrian if (magnitude > magnitude_max) { 5723250003Sadrian magnitude_max = magnitude; 5724250003Sadrian magnitude_max_idx = im; 5725250003Sadrian } 5726250003Sadrian if (magnitude < magnitude_min) { 5727250003Sadrian magnitude_min = magnitude; 5728250003Sadrian magnitude_min_idx = im; 5729250003Sadrian } 5730250003Sadrian if (phase > phase_max) { 5731250003Sadrian phase_max = phase; 5732250003Sadrian phase_max_idx = im; 5733250003Sadrian } 5734250003Sadrian if (phase < phase_min) { 5735250003Sadrian phase_min = phase; 5736250003Sadrian phase_min_idx = im; 5737250003Sadrian } 5738250003Sadrian } 5739250003Sadrian /* find average (exclude max abs value) */ 5740250003Sadrian for (im = 0; im < nmeasurement; im++) { 5741250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5742250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5743250003Sadrian if ((ABS(magnitude) < ABS(magnitude_max)) || 5744250003Sadrian (ABS(magnitude) < ABS(magnitude_min))) 5745250003Sadrian { 5746250003Sadrian magnitude_avg = magnitude_avg + magnitude; 5747250003Sadrian } 5748250003Sadrian if ((ABS(phase) < ABS(phase_max)) || 5749250003Sadrian (ABS(phase) < ABS(phase_min))) 5750250003Sadrian { 5751250003Sadrian phase_avg = phase_avg + phase; 5752250003Sadrian } 5753250003Sadrian } 5754250003Sadrian magnitude_avg = magnitude_avg / (nmeasurement - 1); 5755250003Sadrian phase_avg = phase_avg / (nmeasurement - 1); 5756250003Sadrian 5757250003Sadrian /* detect magnitude outlier */ 5758250003Sadrian if (ABS(magnitude_max - magnitude_min) > MAX_MAG_DELTA) { 5759250003Sadrian if (ABS(magnitude_max - magnitude_avg) > 5760250003Sadrian ABS(magnitude_min - magnitude_avg)) 5761250003Sadrian { 5762250003Sadrian /* max is outlier, force to avg */ 5763250003Sadrian outlier_mag_idx = magnitude_max_idx; 5764250003Sadrian } else { 5765250003Sadrian /* min is outlier, force to avg */ 5766250003Sadrian outlier_mag_idx = magnitude_min_idx; 5767250003Sadrian } 5768250003Sadrian coeff->mag_coeff[ch_idx][outlier_mag_idx][0] = magnitude_avg; 5769250003Sadrian coeff->phs_coeff[ch_idx][outlier_mag_idx][0] = phase_avg; 5770250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5771250003Sadrian "[ch%d][outlier mag gain%d]:: " 5772250003Sadrian "mag_avg = %d (/128), phase_avg = %d (/256)\n", 5773250003Sadrian ch_idx, outlier_mag_idx, magnitude_avg, phase_avg); 5774250003Sadrian } 5775250003Sadrian /* detect phase outlier */ 5776250003Sadrian if (ABS(phase_max - phase_min) > MAX_PHS_DELTA) { 5777250003Sadrian if (ABS(phase_max-phase_avg) > ABS(phase_min - phase_avg)) { 5778250003Sadrian /* max is outlier, force to avg */ 5779250003Sadrian outlier_phs_idx = phase_max_idx; 5780250003Sadrian } else{ 5781250003Sadrian /* min is outlier, force to avg */ 5782250003Sadrian outlier_phs_idx = phase_min_idx; 5783250003Sadrian } 5784250003Sadrian coeff->mag_coeff[ch_idx][outlier_phs_idx][0] = magnitude_avg; 5785250003Sadrian coeff->phs_coeff[ch_idx][outlier_phs_idx][0] = phase_avg; 5786250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5787250003Sadrian "[ch%d][outlier phs gain%d]:: " 5788250003Sadrian "mag_avg = %d (/128), phase_avg = %d (/256)\n", 5789250003Sadrian ch_idx, outlier_phs_idx, magnitude_avg, phase_avg); 5790250003Sadrian } 5791250003Sadrian } 5792250003Sadrian } 5793250003Sadrian 5794250003Sadrian /*printf("------------ after outlier detection -------------\n");*/ 5795250003Sadrian for (im = 0; im < nmeasurement; im++) { 5796250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5797250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5798250003Sadrian 5799250003Sadrian #if 0 5800250003Sadrian printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n", 5801250003Sadrian ch_idx, im, magnitude, phase); 5802250003Sadrian #endif 5803250003Sadrian 5804250003Sadrian coeff->iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7); 5805250003Sadrian 5806250003Sadrian if ((im % 2) == 0) { 5807250003Sadrian OS_REG_RMW_FIELD(ah, 5808250003Sadrian tx_corr_coeff[im][ch_idx], 5809250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 5810250003Sadrian coeff->iqc_coeff[0]); 5811250003Sadrian } else { 5812250003Sadrian OS_REG_RMW_FIELD(ah, 5813250003Sadrian tx_corr_coeff[im][ch_idx], 5814250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 5815250003Sadrian coeff->iqc_coeff[0]); 5816250003Sadrian } 5817250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5818250003Sadrian ichan->tx_corr_coeff[im][ch_idx] = coeff->iqc_coeff[0]; 5819250003Sadrian#endif 5820250003Sadrian } 5821250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5822250003Sadrian ichan->num_measures[ch_idx] = nmeasurement; 5823250003Sadrian#endif 5824250003Sadrian } 5825250003Sadrian 5826250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 5827250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 5828250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 5829250003Sadrian AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 5830250003Sadrian 5831250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5832250003Sadrian if (is_cal_reusable) { 5833250003Sadrian ichan->one_time_txiqcal_done = AH_TRUE; 5834250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 5835250003Sadrian "(FCS) TXIQCAL saved - %d\n", ichan->channel); 5836250003Sadrian } 5837250003Sadrian#endif 5838250003Sadrian} 5839250003Sadrian 5840250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5841250003Sadrianstatic void 5842250003Sadrianar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 5843250003Sadrian{ 5844250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 5845250003Sadrian int nmeasurement, ch_idx, im; 5846250003Sadrian 5847250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5848250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5849250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5850250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5851250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5852250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5853250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5854250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5855250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5856250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5857250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5858250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5859250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5860250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5861250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5862250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5863250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5864250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5865250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5866250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5867250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5868250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5869250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5870250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5871250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5872250003Sadrian }; 5873250003Sadrian 5874250003Sadrian if (AR_SREV_POSEIDON(ah)) { 5875250003Sadrian HALASSERT(ahp->ah_tx_cal_chainmask == 0x1); 5876250003Sadrian 5877250003Sadrian tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5878250003Sadrian tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5879250003Sadrian tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5880250003Sadrian tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5881250003Sadrian tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5882250003Sadrian tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5883250003Sadrian tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5884250003Sadrian tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5885250003Sadrian } 5886250003Sadrian 5887250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 5888250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 5889250003Sadrian continue; 5890250003Sadrian } 5891250003Sadrian nmeasurement = ichan->num_measures[ch_idx]; 5892250003Sadrian 5893250003Sadrian for (im = 0; im < nmeasurement; im++) { 5894250003Sadrian if ((im % 2) == 0) { 5895250003Sadrian OS_REG_RMW_FIELD(ah, 5896250003Sadrian tx_corr_coeff[im][ch_idx], 5897250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 5898250003Sadrian ichan->tx_corr_coeff[im][ch_idx]); 5899250003Sadrian } else { 5900250003Sadrian OS_REG_RMW_FIELD(ah, 5901250003Sadrian tx_corr_coeff[im][ch_idx], 5902250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 5903250003Sadrian ichan->tx_corr_coeff[im][ch_idx]); 5904250003Sadrian } 5905250003Sadrian } 5906250003Sadrian } 5907250003Sadrian 5908250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 5909250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 5910250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 5911250003Sadrian AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 5912250003Sadrian} 5913250003Sadrian#endif 5914250003Sadrian 5915250003Sadrian/* 5916250003Sadrian * ar9300_tx_iq_cal_hw_run is only needed for osprey/wasp/hornet 5917250003Sadrian * It is not needed for jupiter/poseidon. 5918250003Sadrian */ 5919250003SadrianHAL_BOOL 5920250003Sadrianar9300_tx_iq_cal_hw_run(struct ath_hal *ah) 5921250003Sadrian{ 5922250003Sadrian int is_tx_gain_forced; 5923250003Sadrian 5924250003Sadrian is_tx_gain_forced = OS_REG_READ_FIELD(ah, 5925250003Sadrian AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE); 5926250003Sadrian if (is_tx_gain_forced) { 5927250003Sadrian /*printf("Tx gain can not be forced during tx I/Q cal!\n");*/ 5928250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0); 5929250003Sadrian } 5930250003Sadrian 5931250003Sadrian /* enable tx IQ cal */ 5932250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah), 5933250003Sadrian AR_PHY_TX_IQCAL_START_DO_CAL, AR_PHY_TX_IQCAL_START_DO_CAL); 5934250003Sadrian 5935250003Sadrian if (!ath_hal_wait(ah, 5936250008Sadrian AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 0)) 5937250003Sadrian { 5938250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5939250003Sadrian "%s: Tx IQ Cal is never completed.\n", __func__); 5940250003Sadrian return AH_FALSE; 5941250003Sadrian } 5942250003Sadrian return AH_TRUE; 5943250003Sadrian} 5944250003Sadrian 5945250003Sadrianstatic void 5946250003Sadrianar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, 5947250003Sadrian int iqcal_idx, int max_iqcal,HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr) 5948250003Sadrian{ 5949250003Sadrian int nmeasurement=0, im, ix, iy, temp; 5950250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 5951250003Sadrian u_int32_t txiqcal_status[AR9300_MAX_CHAINS] = { 5952250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), 5953250003Sadrian AR_PHY_TX_IQCAL_STATUS_B1, 5954250003Sadrian AR_PHY_TX_IQCAL_STATUS_B2, 5955250003Sadrian }; 5956250003Sadrian const u_int32_t chan_info_tab[] = { 5957250003Sadrian AR_PHY_CHAN_INFO_TAB_0, 5958250003Sadrian AR_PHY_CHAN_INFO_TAB_1, 5959250003Sadrian AR_PHY_CHAN_INFO_TAB_2, 5960250003Sadrian }; 5961250003Sadrian int32_t iq_res[6]; 5962250003Sadrian int32_t ch_idx, j; 5963250003Sadrian u_int32_t num_chains = 0; 5964250003Sadrian static struct coeff_t coeff; 5965250003Sadrian txiqcal_status[0] = AR_PHY_TX_IQCAL_STATUS_B0(ah); 5966250003Sadrian 5967250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 5968250003Sadrian if (ahp->ah_tx_chainmask & (1 << ch_idx)) { 5969250003Sadrian num_chains++; 5970250003Sadrian } 5971250003Sadrian } 5972250003Sadrian 5973250003Sadrian if (apply_last_corr) { 5974250003Sadrian if (coeff.last_cal == AH_TRUE) { 5975250003Sadrian int32_t magnitude, phase; 5976250003Sadrian int ch_idx, im; 5977250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5978250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5979250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5980250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5981250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5982250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5983250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5984250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5985250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5986250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5987250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5988250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5989250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5990250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5991250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5992250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5993250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5994250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5995250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5996250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5997250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5998250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5999250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 6000250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 6001250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 6002250003Sadrian }; 6003250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 6004250003Sadrian for (im = 0; im < coeff.last_nmeasurement; im++) { 6005250003Sadrian magnitude = coeff.mag_coeff[ch_idx][im][0]; 6006250003Sadrian phase = coeff.phs_coeff[ch_idx][im][0]; 6007250003Sadrian 6008250003Sadrian#if 0 6009250003Sadrian printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n", 6010250003Sadrian ch_idx, im, magnitude, phase); 6011250003Sadrian#endif 6012250003Sadrian 6013250003Sadrian coeff.iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7); 6014250003Sadrian if ((im % 2) == 0) { 6015250003Sadrian OS_REG_RMW_FIELD(ah, 6016250003Sadrian tx_corr_coeff[im][ch_idx], 6017250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 6018250003Sadrian coeff.iqc_coeff[0]); 6019250003Sadrian } else { 6020250003Sadrian OS_REG_RMW_FIELD(ah, 6021250003Sadrian tx_corr_coeff[im][ch_idx], 6022250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 6023250003Sadrian coeff.iqc_coeff[0]); 6024250003Sadrian } 6025250003Sadrian } 6026250003Sadrian } 6027250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 6028250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 6029250003Sadrian } 6030250003Sadrian return; 6031250003Sadrian } 6032250003Sadrian 6033250003Sadrian 6034250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 6035250003Sadrian nmeasurement = OS_REG_READ_FIELD(ah, 6036250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); 6037250003Sadrian if (nmeasurement > MAX_MEASUREMENT) { 6038250003Sadrian nmeasurement = MAX_MEASUREMENT; 6039250003Sadrian } 6040250003Sadrian 6041250003Sadrian for (im = 0; im < nmeasurement; im++) { 6042250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 6043250003Sadrian "%s: Doing Tx IQ Cal for chain %d.\n", __func__, ch_idx); 6044250003Sadrian if (OS_REG_READ(ah, txiqcal_status[ch_idx]) & 6045250003Sadrian AR_PHY_TX_IQCAL_STATUS_FAILED) 6046250003Sadrian { 6047250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 6048250003Sadrian "%s: Tx IQ Cal failed for chain %d.\n", __func__, ch_idx); 6049250003Sadrian goto TX_IQ_CAL_FAILED_; 6050250003Sadrian } 6051250003Sadrian 6052250003Sadrian for (j = 0; j < 3; j++) { 6053250003Sadrian u_int32_t idx = 2 * j; 6054250003Sadrian /* 3 registers for each calibration result */ 6055250003Sadrian u_int32_t offset = 4 * (3 * im + j); 6056250003Sadrian 6057250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, 6058250003Sadrian AR_PHY_CHAN_INFO_TAB_S2_READ, 0); 6059250003Sadrian /* 32 bits */ 6060250003Sadrian iq_res[idx] = OS_REG_READ(ah, chan_info_tab[ch_idx] + offset); 6061250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, 6062250003Sadrian AR_PHY_CHAN_INFO_TAB_S2_READ, 1); 6063250003Sadrian /* 16 bits */ 6064250003Sadrian iq_res[idx + 1] = 0xffff & 6065250003Sadrian OS_REG_READ(ah, chan_info_tab[ch_idx] + offset); 6066250003Sadrian 6067250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 6068250003Sadrian "%s: IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", 6069250003Sadrian __func__, idx, iq_res[idx], idx + 1, iq_res[idx + 1]); 6070250003Sadrian } 6071250003Sadrian 6072250008Sadrian if (AH_FALSE == ar9300_calc_iq_corr( 6073250003Sadrian ah, ch_idx, iq_res, coeff.iqc_coeff)) 6074250003Sadrian { 6075250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 6076250003Sadrian "%s: Failed in calculation of IQ correction.\n", 6077250003Sadrian __func__); 6078250003Sadrian goto TX_IQ_CAL_FAILED_; 6079250003Sadrian } 6080250003Sadrian 6081250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1] = coeff.iqc_coeff[0] & 0x7f; 6082250003Sadrian coeff.mag_coeff[ch_idx][im][iqcal_idx-1] = (coeff.iqc_coeff[0] >> 7) & 0x7f; 6083250003Sadrian if (coeff.mag_coeff[ch_idx][im][iqcal_idx-1] > 63) { 6084250003Sadrian coeff.mag_coeff[ch_idx][im][iqcal_idx-1] -= 128; 6085250003Sadrian } 6086250003Sadrian if (coeff.phs_coeff[ch_idx][im][iqcal_idx-1] > 63) { 6087250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1] -= 128; 6088250003Sadrian } 6089250003Sadrian#if 0 6090250003Sadrian ath_hal_printf(ah, "IQCAL::[ch%d][gain%d]:: mag = %d phase = %d \n", 6091250003Sadrian ch_idx, im, coeff.mag_coeff[ch_idx][im][iqcal_idx-1], 6092250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1]); 6093250003Sadrian#endif 6094250003Sadrian } 6095250003Sadrian } 6096250003Sadrian //last iteration; calculate mag and phs 6097250003Sadrian if (iqcal_idx == max_iqcal) { 6098250003Sadrian if (max_iqcal>1) { 6099250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 6100250003Sadrian for (im = 0; im < nmeasurement; im++) { 6101250003Sadrian //sort mag and phs 6102250003Sadrian for( ix=0;ix<max_iqcal-1;ix++){ 6103250003Sadrian for( iy=ix+1;iy<=max_iqcal-1;iy++){ 6104250003Sadrian if(coeff.mag_coeff[ch_idx][im][iy] < 6105250003Sadrian coeff.mag_coeff[ch_idx][im][ix]) { 6106250003Sadrian //swap 6107250003Sadrian temp=coeff.mag_coeff[ch_idx][im][ix]; 6108250003Sadrian coeff.mag_coeff[ch_idx][im][ix] = coeff.mag_coeff[ch_idx][im][iy]; 6109250003Sadrian coeff.mag_coeff[ch_idx][im][iy] = temp; 6110250003Sadrian } 6111250003Sadrian if(coeff.phs_coeff[ch_idx][im][iy] < 6112250003Sadrian coeff.phs_coeff[ch_idx][im][ix]){ 6113250003Sadrian //swap 6114250003Sadrian temp=coeff.phs_coeff[ch_idx][im][ix]; 6115250003Sadrian coeff.phs_coeff[ch_idx][im][ix]=coeff.phs_coeff[ch_idx][im][iy]; 6116250003Sadrian coeff.phs_coeff[ch_idx][im][iy]=temp; 6117250003Sadrian } 6118250003Sadrian } 6119250003Sadrian } 6120250003Sadrian //select median; 3rd entry in the sorted array 6121250003Sadrian coeff.mag_coeff[ch_idx][im][0] = 6122250003Sadrian coeff.mag_coeff[ch_idx][im][max_iqcal/2]; 6123250003Sadrian coeff.phs_coeff[ch_idx][im][0] = 6124250003Sadrian coeff.phs_coeff[ch_idx][im][max_iqcal/2]; 6125250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 6126250003Sadrian "IQCAL: Median [ch%d][gain%d]:: mag = %d phase = %d \n", 6127250003Sadrian ch_idx, im,coeff.mag_coeff[ch_idx][im][0], 6128250003Sadrian coeff.phs_coeff[ch_idx][im][0]); 6129250003Sadrian } 6130250003Sadrian } 6131250003Sadrian } 6132250003Sadrian ar9300_tx_iq_cal_outlier_detection(ah,ichan, num_chains, &coeff,is_cal_reusable); 6133250003Sadrian } 6134250003Sadrian 6135250003Sadrian 6136250003Sadrian coeff.last_nmeasurement = nmeasurement; 6137250003Sadrian coeff.last_cal = AH_TRUE; 6138250003Sadrian 6139250003Sadrian return; 6140250003Sadrian 6141250003SadrianTX_IQ_CAL_FAILED_: 6142250003Sadrian /* no need to print this, it is AGC failure not chip stuck */ 6143250003Sadrian /*ath_hal_printf(ah, "Tx IQ Cal failed(%d)\n", line);*/ 6144250003Sadrian coeff.last_cal = AH_FALSE; 6145250003Sadrian return; 6146250003Sadrian} 6147250003Sadrian 6148250003Sadrian 6149250003Sadrian/* 6150250003Sadrian * ar9300_disable_phy_restart 6151250003Sadrian * 6152250003Sadrian * In some BBpanics, we can disable the phyrestart 6153250003Sadrian * disable_phy_restart 6154250003Sadrian * != 0, disable the phy restart in h/w 6155250003Sadrian * == 0, enable the phy restart in h/w 6156250003Sadrian */ 6157250003Sadrianvoid ar9300_disable_phy_restart(struct ath_hal *ah, int disable_phy_restart) 6158250003Sadrian{ 6159250003Sadrian u_int32_t val; 6160250003Sadrian 6161250003Sadrian val = OS_REG_READ(ah, AR_PHY_RESTART); 6162250003Sadrian if (disable_phy_restart) { 6163250003Sadrian val &= ~AR_PHY_RESTART_ENA; 6164250008Sadrian AH9300(ah)->ah_phyrestart_disabled = 1; 6165250003Sadrian } else { 6166250003Sadrian val |= AR_PHY_RESTART_ENA; 6167250008Sadrian AH9300(ah)->ah_phyrestart_disabled = 0; 6168250003Sadrian } 6169250003Sadrian OS_REG_WRITE(ah, AR_PHY_RESTART, val); 6170250003Sadrian 6171250003Sadrian val = OS_REG_READ(ah, AR_PHY_RESTART); 6172250003Sadrian} 6173250003Sadrian 6174250003SadrianHAL_BOOL 6175250003Sadrianar9300_interference_is_present(struct ath_hal *ah) 6176250003Sadrian{ 6177250003Sadrian int i; 6178250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6179250008Sadrian const struct ieee80211_channel *chan = ahpriv->ah_curchan; 6180250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 6181250003Sadrian 6182250008Sadrian if (ichan == NULL) { 6183250008Sadrian ath_hal_printf(ah, "%s: called with ichan=NULL\n", __func__); 6184250008Sadrian return AH_FALSE; 6185250008Sadrian } 6186250008Sadrian 6187250003Sadrian /* This function is called after a stuck beacon, if EACS is enabled. 6188250003Sadrian * If CW interference is severe, then HW goes into a loop of continuous 6189250003Sadrian * stuck beacons and resets. On reset the NF cal history is cleared. 6190250003Sadrian * So the median value of the history cannot be used - 6191250003Sadrian * hence check if any value (Chain 0/Primary Channel) 6192250003Sadrian * is outside the bounds. 6193250003Sadrian */ 6194250008Sadrian HAL_NFCAL_HIST_FULL *h = AH_HOME_CHAN_NFCAL_HIST(ah, ichan); 6195250003Sadrian for (i = 0; i < HAL_NF_CAL_HIST_LEN_FULL; i++) { 6196250003Sadrian if (h->nf_cal_buffer[i][0] > 6197250008Sadrian AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta) 6198250003Sadrian { 6199250003Sadrian return AH_TRUE; 6200250003Sadrian } 6201250003Sadrian 6202250003Sadrian } 6203250003Sadrian return AH_FALSE; 6204250003Sadrian} 6205250003Sadrian 6206250003Sadrian#if ATH_SUPPORT_CRDC 6207250003Sadrianvoid 6208250003Sadrianar9300_crdc_rx_notify(struct ath_hal *ah, struct ath_rx_status *rxs) 6209250003Sadrian{ 6210250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6211250003Sadrian int rssi_index; 6212250003Sadrian 6213250003Sadrian if ((!AR_SREV_WASP(ah)) || 6214250003Sadrian (!ahpriv->ah_config.ath_hal_crdc_enable)) { 6215250003Sadrian return; 6216250003Sadrian } 6217250003Sadrian 6218250003Sadrian if (rxs->rs_isaggr && rxs->rs_moreaggr) { 6219250003Sadrian return; 6220250003Sadrian } 6221250003Sadrian 6222250003Sadrian if ((rxs->rs_rssi_ctl0 >= HAL_RSSI_BAD) || 6223250003Sadrian (rxs->rs_rssi_ctl1 >= HAL_RSSI_BAD)) { 6224250003Sadrian return; 6225250003Sadrian } 6226250003Sadrian 6227250003Sadrian rssi_index = ah->ah_crdc_rssi_ptr % HAL_MAX_CRDC_RSSI_SAMPLE; 6228250003Sadrian 6229250003Sadrian ah->ah_crdc_rssi_sample[0][rssi_index] = rxs->rs_rssi_ctl0; 6230250003Sadrian ah->ah_crdc_rssi_sample[1][rssi_index] = rxs->rs_rssi_ctl1; 6231250003Sadrian 6232250003Sadrian ah->ah_crdc_rssi_ptr++; 6233250003Sadrian} 6234250003Sadrian 6235250003Sadrianstatic int 6236250003Sadrianar9300_crdc_avg_rssi(struct ath_hal *ah, int chain) 6237250003Sadrian{ 6238250003Sadrian int crdc_rssi_sum = 0; 6239250003Sadrian int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr, i; 6240250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6241250003Sadrian int crdc_window = ahpriv->ah_config.ath_hal_crdc_window; 6242250003Sadrian 6243250003Sadrian if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) { 6244250003Sadrian crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE; 6245250003Sadrian } 6246250003Sadrian 6247250003Sadrian for (i = 1; i <= crdc_window; i++) { 6248250003Sadrian crdc_rssi_sum += 6249250003Sadrian ah->ah_crdc_rssi_sample[chain] 6250250003Sadrian [(crdc_rssi_ptr - i) % HAL_MAX_CRDC_RSSI_SAMPLE]; 6251250003Sadrian } 6252250003Sadrian 6253250003Sadrian return crdc_rssi_sum / crdc_window; 6254250003Sadrian} 6255250003Sadrian 6256250003Sadrianstatic void 6257250003Sadrianar9300_crdc_activate(struct ath_hal *ah, int rssi_diff, int enable) 6258250003Sadrian{ 6259250003Sadrian int val, orig_val; 6260250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6261250003Sadrian int crdc_numerator = ahpriv->ah_config.ath_hal_crdc_numerator; 6262250003Sadrian int crdc_denominator = ahpriv->ah_config.ath_hal_crdc_denominator; 6263250003Sadrian int c = (rssi_diff * crdc_numerator) / crdc_denominator; 6264250003Sadrian 6265250003Sadrian val = orig_val = OS_REG_READ(ah, AR_PHY_MULTICHAIN_CTRL); 6266250003Sadrian val &= 0xffffff00; 6267250003Sadrian if (enable) { 6268250003Sadrian val |= 0x1; 6269250003Sadrian val |= ((c << 1) & 0xff); 6270250003Sadrian } 6271250003Sadrian OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_CTRL, val); 6272250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "diff: %02d comp: %02d reg: %08x %08x\n", 6273250003Sadrian rssi_diff, c, orig_val, val); 6274250003Sadrian} 6275250003Sadrian 6276250003Sadrian 6277250003Sadrianvoid ar9300_chain_rssi_diff_compensation(struct ath_hal *ah) 6278250003Sadrian{ 6279250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6280250003Sadrian int crdc_window = ahpriv->ah_config.ath_hal_crdc_window; 6281250003Sadrian int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr; 6282250003Sadrian int crdc_rssi_thresh = ahpriv->ah_config.ath_hal_crdc_rssithresh; 6283250003Sadrian int crdc_diff_thresh = ahpriv->ah_config.ath_hal_crdc_diffthresh; 6284250003Sadrian int avg_rssi[2], avg_rssi_diff; 6285250003Sadrian 6286250003Sadrian if ((!AR_SREV_WASP(ah)) || 6287250003Sadrian (!ahpriv->ah_config.ath_hal_crdc_enable)) { 6288250003Sadrian if (ah->ah_crdc_rssi_ptr) { 6289250003Sadrian ar9300_crdc_activate(ah, 0, 0); 6290250003Sadrian ah->ah_crdc_rssi_ptr = 0; 6291250003Sadrian } 6292250003Sadrian return; 6293250003Sadrian } 6294250003Sadrian 6295250003Sadrian if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) { 6296250003Sadrian crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE; 6297250003Sadrian } 6298250003Sadrian 6299250003Sadrian if (crdc_rssi_ptr < crdc_window) { 6300250003Sadrian return; 6301250003Sadrian } 6302250003Sadrian 6303250003Sadrian avg_rssi[0] = ar9300_crdc_avg_rssi(ah, 0); 6304250003Sadrian avg_rssi[1] = ar9300_crdc_avg_rssi(ah, 1); 6305250003Sadrian avg_rssi_diff = avg_rssi[1] - avg_rssi[0]; 6306250003Sadrian 6307250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "crdc: avg: %02d %02d ", 6308250003Sadrian avg_rssi[0], avg_rssi[1]); 6309250003Sadrian 6310250003Sadrian if ((avg_rssi[0] < crdc_rssi_thresh) && 6311250003Sadrian (avg_rssi[1] < crdc_rssi_thresh)) { 6312250003Sadrian ar9300_crdc_activate(ah, 0, 0); 6313250003Sadrian } else { 6314250003Sadrian if (ABS(avg_rssi_diff) >= crdc_diff_thresh) { 6315250003Sadrian ar9300_crdc_activate(ah, avg_rssi_diff, 1); 6316250003Sadrian } else { 6317250003Sadrian ar9300_crdc_activate(ah, 0, 1); 6318250003Sadrian } 6319250003Sadrian } 6320250003Sadrian} 6321250003Sadrian#endif 6322250003Sadrian 6323250003Sadrian#if ATH_ANT_DIV_COMB 6324250003SadrianHAL_BOOL 6325250008Sadrianar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, const struct ieee80211_channel *chan) 6326250003Sadrian{ 6327250003Sadrian u_int32_t value; 6328250003Sadrian u_int32_t regval; 6329250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 6330250003Sadrian HAL_CHANNEL_INTERNAL *ichan; 6331250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6332250003Sadrian HAL_CAPABILITIES *pcap = &ahpriv->ah_caps; 6333250003Sadrian 6334250003Sadrian if (AR_SREV_POSEIDON(ah)) { 6335250003Sadrian // Make sure this scheme is only used for WB225(Astra) 6336250003Sadrian ahp->ah_lna_div_use_bt_ant_enable = enable; 6337250003Sadrian 6338250003Sadrian ichan = ar9300_check_chan(ah, chan); 6339250003Sadrian if ( ichan == AH_NULL ) { 6340250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n", 6341250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 6342250003Sadrian return AH_FALSE; 6343250003Sadrian } 6344250003Sadrian 6345250003Sadrian if ( enable == TRUE ) { 6346250008Sadrian pcap->halAntDivCombSupport = TRUE; 6347250003Sadrian } else { 6348250008Sadrian pcap->halAntDivCombSupport = pcap->halAntDivCombSupportOrg; 6349250003Sadrian } 6350250003Sadrian 6351250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) 6352250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL_S (0) 6353250003Sadrian value = ar9300_ant_ctrl_common2_get(ah, IS_CHAN_2GHZ(ichan)); 6354250003Sadrian if ( enable == TRUE ) { 6355250003Sadrian value &= ~AR_SWITCH_TABLE_COM2_ALL; 6356250008Sadrian value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable; 6357250003Sadrian } 6358272292Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value); 6359250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); 6360250003Sadrian 6361250003Sadrian value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control); 6362250003Sadrian /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 6363250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 6364250003Sadrian regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */ 6365250003Sadrian regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S; 6366250003Sadrian /* enable_lnadiv */ 6367250003Sadrian regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK); 6368250003Sadrian regval |= ((value >> 6) & 0x1) << 6369250003Sadrian MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT; 6370250003Sadrian if ( enable == TRUE ) { 6371250003Sadrian regval |= ANT_DIV_ENABLE; 6372250003Sadrian } 6373250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 6374250003Sadrian 6375250003Sadrian /* enable fast_div */ 6376250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 6377250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 6378250003Sadrian regval |= ((value >> 7) & 0x1) << 6379250003Sadrian BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT; 6380250003Sadrian if ( enable == TRUE ) { 6381250003Sadrian regval |= FAST_DIV_ENABLE; 6382250003Sadrian } 6383250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 6384250003Sadrian 6385250003Sadrian if ( AR_SREV_POSEIDON_11_OR_LATER(ah) ) { 6386250008Sadrian if (pcap->halAntDivCombSupport) { 6387250003Sadrian /* If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning */ 6388250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 6389250003Sadrian /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 6390250003Sadrian regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | 6391250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | 6392250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK | 6393250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK)); 6394250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA1 << 6395250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 6396250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA2 << 6397250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 6398250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 6399250003Sadrian } 6400250003Sadrian } 6401250003Sadrian 6402250003Sadrian return AH_TRUE; 6403250003Sadrian } else { 6404250003Sadrian return AH_TRUE; 6405250003Sadrian } 6406280829Sadrian 6407280829Sadrian /* XXX TODO: Add AR9565 support? */ 6408250003Sadrian} 6409250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 6410