ar9300_reset.c revision 272292
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 35250003Sadrian/* Additional Time delay to wait after activiting the Base band */ 36250003Sadrian#define BASE_ACTIVATE_DELAY 100 /* usec */ 37250003Sadrian#define RTC_PLL_SETTLE_DELAY 100 /* usec */ 38250003Sadrian#define COEF_SCALE_S 24 39250003Sadrian#define HT40_CHANNEL_CENTER_SHIFT 10 /* MHz */ 40250003Sadrian 41250003Sadrian#define DELPT 32 42250003Sadrian 43250008Sadrian/* XXX Duplicates! (in ar9300desc.h) */ 44250008Sadrian#if 0 45250003Sadrianextern HAL_BOOL ar9300_reset_tx_queue(struct ath_hal *ah, u_int q); 46250003Sadrianextern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q); 47250008Sadrian#endif 48250003Sadrian 49250003Sadrian 50250003Sadrian#define MAX_MEASUREMENT 8 51250003Sadrian#define MAXIQCAL 3 52250003Sadrianstruct coeff_t { 53250003Sadrian int32_t mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; 54250003Sadrian int32_t phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; 55250003Sadrian int32_t iqc_coeff[2]; 56250003Sadrian int last_nmeasurement; 57250003Sadrian HAL_BOOL last_cal; 58250003Sadrian}; 59250003Sadrian 60250003Sadrianstatic HAL_BOOL ar9300_tx_iq_cal_hw_run(struct ath_hal *ah); 61250003Sadrianstatic void ar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, 62250003Sadrian int iqcal_idx, int max_iqcal, HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr); 63250003Sadrianstatic void ar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, 64250003Sadrian u_int32_t num_chains, struct coeff_t *coeff, HAL_BOOL is_cal_reusable); 65250003Sadrian#if ATH_SUPPORT_CAL_REUSE 66250003Sadrianstatic void ar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan); 67250003Sadrian#endif 68250003Sadrian 69250003Sadrian 70250003Sadrianstatic inline void ar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, int column); 71250008Sadrianstatic inline void ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan); 72250008Sadrianstatic inline HAL_BOOL ar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_corr); 73250003Sadrianstatic inline void ar9300_init_user_settings(struct ath_hal *ah); 74250003Sadrian 75250003Sadrian#ifdef HOST_OFFLOAD 76250003Sadrian/* 77250003Sadrian * For usb offload solution, some USB registers must be tuned 78250003Sadrian * to gain better stability/performance but these registers 79250003Sadrian * might be changed while doing wlan reset so do this here 80250003Sadrian */ 81250003Sadrian#define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah) \ 82250003Sadriando { \ 83250003Sadrian if (AR_SREV_HORNET(__ah) || AR_SREV_WASP(__ah)) { \ 84250003Sadrian volatile u_int32_t *usb_ctrl_r1 = (u_int32_t *) 0xb8116c84; \ 85250003Sadrian volatile u_int32_t *usb_ctrl_r2 = (u_int32_t *) 0xb8116c88; \ 86250003Sadrian *usb_ctrl_r1 = (*usb_ctrl_r1 & 0xffefffff); \ 87250003Sadrian *usb_ctrl_r2 = (*usb_ctrl_r2 & 0xfc1fffff) | (1 << 21) | (3 << 22); \ 88250003Sadrian } \ 89250003Sadrian} while (0) 90250003Sadrian#else 91250003Sadrian#define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah) 92250003Sadrian#endif 93250003Sadrian 94250003Sadrianstatic inline void 95250003Sadrianar9300_attach_hw_platform(struct ath_hal *ah) 96250003Sadrian{ 97250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 98250003Sadrian 99250003Sadrian ahp->ah_hwp = HAL_TRUE_CHIP; 100250003Sadrian return; 101250003Sadrian} 102250003Sadrian 103250003Sadrian/* Adjust various register settings based on half/quarter rate clock setting. 104250003Sadrian * This includes: +USEC, TX/RX latency, 105250003Sadrian * + IFS params: slot, eifs, misc etc. 106250003Sadrian * SIFS stays the same. 107250003Sadrian */ 108250003Sadrianstatic void 109250008Sadrianar9300_set_ifs_timing(struct ath_hal *ah, struct ieee80211_channel *chan) 110250003Sadrian{ 111250003Sadrian u_int32_t tx_lat, rx_lat, usec, slot, regval, eifs; 112250003Sadrian 113250003Sadrian regval = OS_REG_READ(ah, AR_USEC); 114250003Sadrian regval &= ~(AR_USEC_RX_LATENCY | AR_USEC_TX_LATENCY | AR_USEC_USEC); 115250008Sadrian if (IEEE80211_IS_CHAN_HALF(chan)) { /* half rates */ 116250003Sadrian slot = ar9300_mac_to_clks(ah, AR_SLOT_HALF); 117250003Sadrian eifs = ar9300_mac_to_clks(ah, AR_EIFS_HALF); 118250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */ 119250003Sadrian rx_lat = SM(AR_RX_LATENCY_HALF_FAST_CLOCK, AR_USEC_RX_LATENCY); 120250003Sadrian tx_lat = SM(AR_TX_LATENCY_HALF_FAST_CLOCK, AR_USEC_TX_LATENCY); 121250003Sadrian usec = SM(AR_USEC_HALF_FAST_CLOCK, AR_USEC_USEC); 122250003Sadrian } else { 123250003Sadrian rx_lat = SM(AR_RX_LATENCY_HALF, AR_USEC_RX_LATENCY); 124250003Sadrian tx_lat = SM(AR_TX_LATENCY_HALF, AR_USEC_TX_LATENCY); 125250003Sadrian usec = SM(AR_USEC_HALF, AR_USEC_USEC); 126250003Sadrian } 127250003Sadrian } else { /* quarter rate */ 128250003Sadrian slot = ar9300_mac_to_clks(ah, AR_SLOT_QUARTER); 129250003Sadrian eifs = ar9300_mac_to_clks(ah, AR_EIFS_QUARTER); 130250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */ 131250003Sadrian rx_lat = SM(AR_RX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_RX_LATENCY); 132250003Sadrian tx_lat = SM(AR_TX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_TX_LATENCY); 133250003Sadrian usec = SM(AR_USEC_QUARTER_FAST_CLOCK, AR_USEC_USEC); 134250003Sadrian } else { 135250003Sadrian rx_lat = SM(AR_RX_LATENCY_QUARTER, AR_USEC_RX_LATENCY); 136250003Sadrian tx_lat = SM(AR_TX_LATENCY_QUARTER, AR_USEC_TX_LATENCY); 137250003Sadrian usec = SM(AR_USEC_QUARTER, AR_USEC_USEC); 138250003Sadrian } 139250003Sadrian } 140250003Sadrian 141250003Sadrian OS_REG_WRITE(ah, AR_USEC, (usec | regval | tx_lat | rx_lat)); 142250003Sadrian OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 143250003Sadrian OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 144250003Sadrian} 145250003Sadrian 146250003Sadrian 147250003Sadrian/* 148250003Sadrian * This inline function configures the chip either 149250003Sadrian * to encrypt/decrypt management frames or pass thru 150250003Sadrian */ 151250003Sadrianstatic inline void 152250003Sadrianar9300_init_mfp(struct ath_hal * ah) 153250003Sadrian{ 154250003Sadrian u_int32_t mfpcap, mfp_qos; 155250003Sadrian 156250003Sadrian ath_hal_getcapability(ah, HAL_CAP_MFP, 0, &mfpcap); 157250003Sadrian 158250003Sadrian if (mfpcap == HAL_MFP_QOSDATA) { 159250003Sadrian /* Treat like legacy hardware. Do not touch the MFP registers. */ 160250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s forced to use QOSDATA\n", __func__); 161250003Sadrian return; 162250003Sadrian } 163250003Sadrian 164250003Sadrian /* MFP support (Sowl 1.0 or greater) */ 165250003Sadrian if (mfpcap == HAL_MFP_HW_CRYPTO) { 166250003Sadrian /* configure hardware MFP support */ 167250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s using HW crypto\n", __func__); 168250003Sadrian OS_REG_RMW_FIELD(ah, 169250003Sadrian AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, AR_AES_MUTE_MASK1_FC_MGMT_MFP); 170250003Sadrian OS_REG_RMW(ah, 171250003Sadrian AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE, 172250003Sadrian AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); 173250003Sadrian /* 174250003Sadrian * Mask used to construct AAD for CCMP-AES 175250003Sadrian * Cisco spec defined bits 0-3 as mask 176250003Sadrian * IEEE802.11w defined as bit 4. 177250003Sadrian */ 178250003Sadrian if (ath_hal_get_mfp_qos(ah)) { 179250003Sadrian mfp_qos = AR_MFP_QOS_MASK_IEEE; 180250003Sadrian } else { 181250003Sadrian mfp_qos = AR_MFP_QOS_MASK_CISCO; 182250003Sadrian } 183250003Sadrian OS_REG_RMW_FIELD(ah, 184250003Sadrian AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_QOS, mfp_qos); 185250003Sadrian } else if (mfpcap == HAL_MFP_PASSTHRU) { 186250003Sadrian /* Disable en/decrypt by hardware */ 187250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s using passthru\n", __func__); 188250003Sadrian OS_REG_RMW(ah, 189250003Sadrian AR_PCU_MISC_MODE2, 190250003Sadrian AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT, 191250003Sadrian AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); 192250003Sadrian } 193250003Sadrian} 194250003Sadrian 195250003Sadrianvoid 196250008Sadrianar9300_get_channel_centers(struct ath_hal *ah, const struct ieee80211_channel *chan, 197250003Sadrian CHAN_CENTERS *centers) 198250003Sadrian{ 199250003Sadrian int8_t extoff; 200250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 201250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 202250003Sadrian 203250008Sadrian if (!IEEE80211_IS_CHAN_HT40(chan)) { 204250003Sadrian centers->ctl_center = centers->ext_center = 205250008Sadrian centers->synth_center = ichan->channel; 206250003Sadrian return; 207250003Sadrian } 208250003Sadrian 209250008Sadrian HALASSERT(IEEE80211_IS_CHAN_HT40(chan)); 210250003Sadrian 211250003Sadrian /* 212250003Sadrian * In 20/40 phy mode, the center frequency is 213250003Sadrian * "between" the primary and extension channels. 214250003Sadrian */ 215250008Sadrian if (IEEE80211_IS_CHAN_HT40U(chan)) { 216250008Sadrian centers->synth_center = ichan->channel + HT40_CHANNEL_CENTER_SHIFT; 217250003Sadrian extoff = 1; 218250003Sadrian } else { 219250008Sadrian centers->synth_center = ichan->channel - HT40_CHANNEL_CENTER_SHIFT; 220250003Sadrian extoff = -1; 221250003Sadrian } 222250003Sadrian 223250003Sadrian centers->ctl_center = 224250003Sadrian centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); 225250003Sadrian centers->ext_center = 226250003Sadrian centers->synth_center + 227250003Sadrian (extoff * ((ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_20) ? 228250003Sadrian HT40_CHANNEL_CENTER_SHIFT : 15)); 229250003Sadrian} 230250003Sadrian 231250003Sadrian/* 232250003Sadrian * Read the noise-floor values from the HW. 233250003Sadrian * Specifically, read the minimum clear-channel assessment value for 234250003Sadrian * each chain, for both the control and extension channels. 235250003Sadrian * (The received power level during clear-channel periods is the 236250003Sadrian * noise floor.) 237250003Sadrian * These noise floor values computed by the HW will be stored in the 238250003Sadrian * NF history buffer. 239250003Sadrian * The HW sometimes produces bogus NF values. To avoid using these 240250003Sadrian * bogus values, the NF data is (a) range-limited, and (b) filtered. 241250003Sadrian * However, this data-processing is done when reading the NF values 242250003Sadrian * out of the history buffer. The history buffer stores the raw values. 243250003Sadrian * This allows the NF history buffer to be used to check for interference. 244250003Sadrian * A single high NF reading might be a bogus HW value, but if the NF 245250003Sadrian * readings are consistently high, it must be due to interference. 246250003Sadrian * This is the purpose of storing raw NF values in the history buffer, 247250003Sadrian * rather than processed values. By looking at a history of NF values 248250003Sadrian * that have not been range-limited, we can check if they are consistently 249250003Sadrian * high (due to interference). 250250003Sadrian */ 251250003Sadrian#define AH_NF_SIGN_EXTEND(nf) \ 252250003Sadrian ((nf) & 0x100) ? \ 253250003Sadrian 0 - (((nf) ^ 0x1ff) + 1) : \ 254250003Sadrian (nf) 255250003Sadrianvoid 256250003Sadrianar9300_upload_noise_floor(struct ath_hal *ah, int is_2g, 257250008Sadrian int16_t nfarray[HAL_NUM_NF_READINGS]) 258250003Sadrian{ 259250003Sadrian int16_t nf; 260250003Sadrian int chan, chain; 261250008Sadrian u_int32_t regs[HAL_NUM_NF_READINGS] = { 262250003Sadrian /* control channel */ 263250003Sadrian AR_PHY_CCA_0, /* chain 0 */ 264250003Sadrian AR_PHY_CCA_1, /* chain 1 */ 265250003Sadrian AR_PHY_CCA_2, /* chain 2 */ 266250003Sadrian /* extension channel */ 267250003Sadrian AR_PHY_EXT_CCA, /* chain 0 */ 268250003Sadrian AR_PHY_EXT_CCA_1, /* chain 1 */ 269250003Sadrian AR_PHY_EXT_CCA_2, /* chain 2 */ 270250003Sadrian }; 271250003Sadrian u_int8_t chainmask; 272250003Sadrian 273250003Sadrian /* 274250003Sadrian * Within a given channel (ctl vs. ext), the CH0, CH1, and CH2 275250003Sadrian * masks and shifts are the same, though they differ for the 276250003Sadrian * control vs. extension channels. 277250003Sadrian */ 278250003Sadrian u_int32_t masks[2] = { 279250003Sadrian AR_PHY_MINCCA_PWR, /* control channel */ 280250003Sadrian AR_PHY_EXT_MINCCA_PWR, /* extention channel */ 281250003Sadrian }; 282250003Sadrian u_int8_t shifts[2] = { 283250003Sadrian AR_PHY_MINCCA_PWR_S, /* control channel */ 284250003Sadrian AR_PHY_EXT_MINCCA_PWR_S, /* extention channel */ 285250003Sadrian }; 286250003Sadrian 287250003Sadrian /* 288250003Sadrian * Force NF calibration for all chains. 289250003Sadrian */ 290250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 291250003Sadrian chainmask = 0x01; 292250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { 293250003Sadrian chainmask = 0x03; 294250003Sadrian } else { 295250003Sadrian chainmask = 0x07; 296250003Sadrian } 297250003Sadrian 298250003Sadrian for (chan = 0; chan < 2 /*ctl,ext*/; chan++) { 299250003Sadrian for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { 300250003Sadrian int i; 301250003Sadrian 302250003Sadrian if (!((chainmask >> chain) & 0x1)) { 303250003Sadrian continue; 304250003Sadrian } 305250003Sadrian i = chan * AR9300_MAX_CHAINS + chain; 306250003Sadrian nf = (OS_REG_READ(ah, regs[i]) & masks[chan]) >> shifts[chan]; 307250003Sadrian nfarray[i] = AH_NF_SIGN_EXTEND(nf); 308250003Sadrian } 309250003Sadrian } 310250003Sadrian} 311250003Sadrian 312250003Sadrian/* ar9300_get_min_cca_pwr - 313250003Sadrian * Used by the scan function for a quick read of the noise floor. 314250003Sadrian * This is used to detect presence of CW interference such as video bridge. 315250003Sadrian * The noise floor is assumed to have been already started during reset 316250003Sadrian * called during channel change. The function checks if the noise floor 317250003Sadrian * reading is done. In case it has been done, it reads the noise floor value. 318250003Sadrian * If the noise floor calibration has not been finished, it assumes this is 319250003Sadrian * due to presence of CW interference an returns a high value for noise floor, 320250003Sadrian * derived from the CW interference threshold + margin fudge factor. 321250003Sadrian */ 322250003Sadrian#define BAD_SCAN_NF_MARGIN (30) 323250003Sadrianint16_t ar9300_get_min_cca_pwr(struct ath_hal *ah) 324250003Sadrian{ 325250003Sadrian int16_t nf; 326250008Sadrian// struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 327250003Sadrian 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 405250003Sadrian 406250003Sadrian/* 407250003Sadrian * Pick up the medium one in the noise floor buffer and update the 408250003Sadrian * corresponding range for valid noise floor values 409250003Sadrian */ 410250003Sadrianstatic int16_t 411250003Sadrianar9300_get_nf_hist_mid(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, int reading, 412250003Sadrian int hist_len) 413250003Sadrian{ 414250003Sadrian int16_t nfval; 415250003Sadrian int16_t sort[HAL_NF_CAL_HIST_LEN_FULL]; /* upper bound for hist_len */ 416250003Sadrian int i, j; 417250003Sadrian 418250003Sadrian for (i = 0; i < hist_len; i++) { 419250003Sadrian sort[i] = h->nf_cal_buffer[i][reading]; 420250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 421250003Sadrian "nf_cal_buffer[%d][%d] = %d\n", i, reading, (int)sort[i]); 422250003Sadrian } 423250003Sadrian for (i = 0; i < hist_len - 1; i++) { 424250003Sadrian for (j = 1; j < hist_len - i; j++) { 425250003Sadrian if (sort[j] > sort[j - 1]) { 426250003Sadrian nfval = sort[j]; 427250003Sadrian sort[j] = sort[j - 1]; 428250003Sadrian sort[j - 1] = nfval; 429250003Sadrian } 430250003Sadrian } 431250003Sadrian } 432250003Sadrian nfval = sort[(hist_len - 1) >> 1]; 433250003Sadrian 434250003Sadrian return nfval; 435250003Sadrian} 436250003Sadrian 437250003Sadrianstatic int16_t ar9300_limit_nf_range(struct ath_hal *ah, int16_t nf) 438250003Sadrian{ 439250008Sadrian if (nf < AH9300(ah)->nfp->min) { 440250008Sadrian return AH9300(ah)->nfp->nominal; 441250008Sadrian } else if (nf > AH9300(ah)->nfp->max) { 442250008Sadrian return AH9300(ah)->nfp->max; 443250003Sadrian } 444250003Sadrian return nf; 445250003Sadrian} 446250003Sadrian 447250003Sadrian#ifndef ATH_NF_PER_CHAN 448250003Sadrianinline static void 449250003Sadrianar9300_reset_nf_hist_buff(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 450250003Sadrian{ 451250003Sadrian HAL_CHAN_NFCAL_HIST *h = &ichan->nf_cal_hist; 452250003Sadrian HAL_NFCAL_HIST_FULL *home = &AH_PRIVATE(ah)->nf_cal_hist; 453250003Sadrian int i; 454250003Sadrian 455250003Sadrian /* 456250003Sadrian * Copy the value for the channel in question into the home-channel 457250003Sadrian * NF history buffer. The channel NF is probably a value filled in by 458250003Sadrian * a prior background channel scan, but if no scan has been done then 459250003Sadrian * it is the nominal noise floor filled in by ath_hal_init_NF_buffer 460250003Sadrian * for this chip and the channel's band. 461250003Sadrian * Replicate this channel NF into all entries of the home-channel NF 462250003Sadrian * history buffer. 463250003Sadrian * If the channel NF was filled in by a channel scan, it has not had 464250003Sadrian * bounds limits applied to it yet - do so now. It is important to 465250003Sadrian * apply bounds limits to the priv_nf value that gets loaded into the 466250003Sadrian * WLAN chip's min_cca_pwr register field. It is also necessary to 467250003Sadrian * apply bounds limits to the nf_cal_buffer[] elements. Since we are 468250003Sadrian * replicating a single NF reading into all nf_cal_buffer elements, 469250003Sadrian * if the single reading were above the CW_INT threshold, the CW_INT 470250003Sadrian * check in ar9300_get_nf would immediately conclude that CW interference 471250003Sadrian * is present, even though we're not supposed to set CW_INT unless 472250003Sadrian * NF values are _consistently_ above the CW_INT threshold. 473250003Sadrian * Applying the bounds limits to the nf_cal_buffer contents fixes this 474250003Sadrian * problem. 475250003Sadrian */ 476250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i ++) { 477250003Sadrian int j; 478250003Sadrian int16_t nf; 479250003Sadrian /* 480250003Sadrian * No need to set curr_index, since it already has a value in 481250003Sadrian * the range [0..HAL_NF_CAL_HIST_LEN_FULL), and all nf_cal_buffer 482250003Sadrian * values will be the same. 483250003Sadrian */ 484250003Sadrian nf = ar9300_limit_nf_range(ah, h->nf_cal_buffer[0][i]); 485250003Sadrian for (j = 0; j < HAL_NF_CAL_HIST_LEN_FULL; j++) { 486250003Sadrian home->nf_cal_buffer[j][i] = nf; 487250003Sadrian } 488250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.base.priv_nf[i] = nf; 489250003Sadrian } 490250003Sadrian} 491250003Sadrian#endif 492250003Sadrian 493250003Sadrian/* 494250003Sadrian * Update the noise floor buffer as a ring buffer 495250003Sadrian */ 496250003Sadrianstatic int16_t 497250003Sadrianar9300_update_nf_hist_buff(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, 498250003Sadrian int16_t *nfarray, int hist_len) 499250003Sadrian{ 500250003Sadrian int i, nr; 501250003Sadrian int16_t nf_no_lim_chain0; 502250003Sadrian 503250003Sadrian nf_no_lim_chain0 = ar9300_get_nf_hist_mid(ah, h, 0, hist_len); 504250003Sadrian 505250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] BEFORE\n", __func__, __LINE__); 506250003Sadrian for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) { 507250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 508250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 509250003Sadrian "nf_cal_buffer[%d][%d] = %d\n", 510250003Sadrian nr, i, (int)h->nf_cal_buffer[nr][i]); 511250003Sadrian } 512250003Sadrian } 513250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 514250003Sadrian h->nf_cal_buffer[h->base.curr_index][i] = nfarray[i]; 515250003Sadrian h->base.priv_nf[i] = ar9300_limit_nf_range( 516250003Sadrian ah, ar9300_get_nf_hist_mid(ah, h, i, hist_len)); 517250003Sadrian } 518250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] AFTER\n", __func__, __LINE__); 519250003Sadrian for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) { 520250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 521250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 522250003Sadrian "nf_cal_buffer[%d][%d] = %d\n", 523250003Sadrian nr, i, (int)h->nf_cal_buffer[nr][i]); 524250003Sadrian } 525250003Sadrian } 526250003Sadrian 527250003Sadrian if (++h->base.curr_index >= hist_len) { 528250003Sadrian h->base.curr_index = 0; 529250003Sadrian } 530250003Sadrian 531250003Sadrian return nf_no_lim_chain0; 532250003Sadrian} 533250003Sadrian 534250008Sadrian#ifdef UNUSED 535250003Sadrianstatic HAL_BOOL 536250003Sadrianget_noise_floor_thresh(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *chan, 537250003Sadrian int16_t *nft) 538250003Sadrian{ 539250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 540250003Sadrian 541250003Sadrian switch (chan->channel_flags & CHANNEL_ALL_NOTURBO) { 542250003Sadrian case CHANNEL_A: 543250003Sadrian case CHANNEL_A_HT20: 544250003Sadrian case CHANNEL_A_HT40PLUS: 545250003Sadrian case CHANNEL_A_HT40MINUS: 546250003Sadrian *nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_5); 547250003Sadrian break; 548250003Sadrian case CHANNEL_B: 549250003Sadrian case CHANNEL_G: 550250003Sadrian case CHANNEL_G_HT20: 551250003Sadrian case CHANNEL_G_HT40PLUS: 552250003Sadrian case CHANNEL_G_HT40MINUS: 553250003Sadrian *nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_2); 554250003Sadrian break; 555250003Sadrian default: 556250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel flags 0x%x\n", 557250003Sadrian __func__, chan->channel_flags); 558250003Sadrian return AH_FALSE; 559250003Sadrian } 560250003Sadrian return AH_TRUE; 561250003Sadrian} 562250003Sadrian#endif 563250003Sadrian 564250003Sadrian/* 565250003Sadrian * Read the NF and check it against the noise floor threshhold 566250003Sadrian */ 567250003Sadrian#define IS(_c, _f) (((_c)->channel_flags & _f) || 0) 568250003Sadrianstatic int 569250008Sadrianar9300_store_new_nf(struct ath_hal *ah, struct ieee80211_channel *chan, 570250008Sadrian int is_scan) 571250003Sadrian{ 572250008Sadrian// struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 573250003Sadrian int nf_hist_len; 574250003Sadrian int16_t nf_no_lim; 575250008Sadrian int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; 576250003Sadrian HAL_NFCAL_HIST_FULL *h; 577250003Sadrian int is_2g = 0; 578250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 579250008Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 580250003Sadrian 581250003Sadrian if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 582250003Sadrian u_int32_t tsf32, nf_cal_dur_tsf; 583250003Sadrian /* 584250003Sadrian * The reason the NF calibration did not complete may just be that 585250003Sadrian * not enough time has passed since the NF calibration was started, 586250003Sadrian * because under certain conditions (when first moving to a new 587250003Sadrian * channel) the NF calibration may be checked very repeatedly. 588250003Sadrian * Or, there may be CW interference keeping the NF calibration 589250003Sadrian * from completing. Check the delta time between when the NF 590250003Sadrian * calibration was started and now to see whether the NF calibration 591250003Sadrian * should have already completed (but hasn't, probably due to CW 592250003Sadrian * interference), or hasn't had enough time to finish yet. 593250003Sadrian */ 594250003Sadrian /* 595250003Sadrian * AH_NF_CAL_DUR_MAX_TSF - A conservative maximum time that the 596250003Sadrian * HW should need to finish a NF calibration. If the HW 597250003Sadrian * does not complete a NF calibration within this time period, 598250003Sadrian * there must be a problem - probably CW interference. 599250003Sadrian * AH_NF_CAL_PERIOD_MAX_TSF - A conservative maximum time between 600250003Sadrian * check of the HW's NF calibration being finished. 601250003Sadrian * If the difference between the current TSF and the TSF 602250003Sadrian * recorded when the NF calibration started is larger than this 603250003Sadrian * value, the TSF must have been reset. 604250003Sadrian * In general, we expect the TSF to only be reset during 605250003Sadrian * regular operation for STAs, not for APs. However, an 606250003Sadrian * AP's TSF could be reset when joining an IBSS. 607250003Sadrian * There's an outside chance that this could result in the 608250003Sadrian * CW_INT flag being erroneously set, if the TSF adjustment 609250003Sadrian * is smaller than AH_NF_CAL_PERIOD_MAX_TSF but larger than 610250003Sadrian * AH_NF_CAL_DUR_TSF. However, even if this does happen, 611250003Sadrian * it shouldn't matter, as the IBSS case shouldn't be 612250003Sadrian * concerned about CW_INT. 613250003Sadrian */ 614250003Sadrian /* AH_NF_CAL_DUR_TSF - 90 sec in usec units */ 615250003Sadrian #define AH_NF_CAL_DUR_TSF (90 * 1000 * 1000) 616250003Sadrian /* AH_NF_CAL_PERIOD_MAX_TSF - 180 sec in usec units */ 617250003Sadrian #define AH_NF_CAL_PERIOD_MAX_TSF (180 * 1000 * 1000) 618250003Sadrian /* wraparound handled by using unsigned values */ 619250003Sadrian tsf32 = ar9300_get_tsf32(ah); 620250003Sadrian nf_cal_dur_tsf = tsf32 - AH9300(ah)->nf_tsf32; 621250003Sadrian if (nf_cal_dur_tsf > AH_NF_CAL_PERIOD_MAX_TSF) { 622250003Sadrian /* 623250003Sadrian * The TSF must have gotten reset during the NF cal - 624250003Sadrian * just reset the NF TSF timestamp, so the next time 625250003Sadrian * this function is called, the timestamp comparison 626250003Sadrian * will be valid. 627250003Sadrian */ 628250003Sadrian AH9300(ah)->nf_tsf32 = tsf32; 629250003Sadrian } else if (nf_cal_dur_tsf > AH_NF_CAL_DUR_TSF) { 630250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 631250003Sadrian "%s: NF did not complete in calibration window\n", __func__); 632250003Sadrian /* the NF incompletion is probably due to CW interference */ 633250008Sadrian chan->ic_state |= IEEE80211_CHANSTATE_CWINT; 634250003Sadrian } 635250003Sadrian return 0; /* HW's NF measurement not finished */ 636250003Sadrian } 637250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 638250008Sadrian "%s[%d] chan %d\n", __func__, __LINE__, ichan->channel); 639250008Sadrian is_2g = !! IS_CHAN_2GHZ(ichan); 640250003Sadrian ar9300_upload_noise_floor(ah, is_2g, nfarray); 641250003Sadrian 642250003Sadrian /* Update the NF buffer for each chain masked by chainmask */ 643250003Sadrian#ifdef ATH_NF_PER_CHAN 644250008Sadrian h = &ichan->nf_cal_hist; 645250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 646250003Sadrian#else 647250003Sadrian if (is_scan) { 648250003Sadrian /* 649250003Sadrian * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct 650250003Sadrian * rather than a HAL_NFCAL_HIST_FULL struct. 651250003Sadrian * As long as we only use the first history element of nf_cal_buffer 652250008Sadrian * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use 653250003Sadrian * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably. 654250003Sadrian */ 655250008Sadrian h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 656250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; 657250003Sadrian } else { 658250003Sadrian h = &AH_PRIVATE(ah)->nf_cal_hist; 659250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 660250003Sadrian } 661250003Sadrian#endif 662250003Sadrian 663250003Sadrian /* 664250003Sadrian * nf_no_lim = median value from NF history buffer without bounds limits, 665250003Sadrian * priv_nf = median value from NF history buffer with bounds limits. 666250003Sadrian */ 667250003Sadrian nf_no_lim = ar9300_update_nf_hist_buff(ah, h, nfarray, nf_hist_len); 668250008Sadrian ichan->rawNoiseFloor = h->base.priv_nf[0]; 669250003Sadrian 670250003Sadrian /* check if there is interference */ 671250008Sadrian// ichan->channel_flags &= (~CHANNEL_CW_INT); 672250003Sadrian /* 673250003Sadrian * Use AR9300_EMULATION to check for emulation purpose as PCIE Device ID 674250003Sadrian * 0xABCD is recognized as valid Osprey as WAR in some EVs. 675250003Sadrian */ 676250008Sadrian if (nf_no_lim > ahp->nfp->nominal + ahp->nf_cw_int_delta) { 677250003Sadrian /* 678250003Sadrian * Since this CW interference check is being applied to the 679250003Sadrian * median element of the NF history buffer, this indicates that 680250003Sadrian * the CW interference is persistent. A single high NF reading 681250003Sadrian * will not show up in the median, and thus will not cause the 682250003Sadrian * CW_INT flag to be set. 683250003Sadrian */ 684250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 685250003Sadrian "%s: NF Cal: CW interferer detected through NF: %d\n", 686250003Sadrian __func__, nf_no_lim); 687250008Sadrian chan->ic_state |= IEEE80211_CHANSTATE_CWINT; 688250003Sadrian } 689250003Sadrian return 1; /* HW's NF measurement finished */ 690250003Sadrian} 691250003Sadrian#undef IS 692250003Sadrian 693250003Sadrianstatic inline void 694250003Sadrianar9300_get_delta_slope_values(struct ath_hal *ah, u_int32_t coef_scaled, 695250003Sadrian u_int32_t *coef_mantissa, u_int32_t *coef_exponent) 696250003Sadrian{ 697250003Sadrian u_int32_t coef_exp, coef_man; 698250003Sadrian 699250003Sadrian /* 700250003Sadrian * ALGO -> coef_exp = 14-floor(log2(coef)); 701250003Sadrian * floor(log2(x)) is the highest set bit position 702250003Sadrian */ 703250003Sadrian for (coef_exp = 31; coef_exp > 0; coef_exp--) { 704250003Sadrian if ((coef_scaled >> coef_exp) & 0x1) { 705250003Sadrian break; 706250003Sadrian } 707250003Sadrian } 708250003Sadrian /* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */ 709250003Sadrian HALASSERT(coef_exp); 710250003Sadrian coef_exp = 14 - (coef_exp - COEF_SCALE_S); 711250003Sadrian 712250003Sadrian 713250003Sadrian /* 714250003Sadrian * ALGO -> coef_man = floor(coef* 2^coef_exp+0.5); 715250003Sadrian * The coefficient is already shifted up for scaling 716250003Sadrian */ 717250003Sadrian coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); 718250003Sadrian 719250003Sadrian *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); 720250003Sadrian *coef_exponent = coef_exp - 16; 721250003Sadrian} 722250003Sadrian 723250003Sadrian#define MAX_ANALOG_START 319 /* XXX */ 724250003Sadrian 725250003Sadrian/* 726250003Sadrian * Delta slope coefficient computation. 727250003Sadrian * Required for OFDM operation. 728250003Sadrian */ 729250003Sadrianstatic void 730250008Sadrianar9300_set_delta_slope(struct ath_hal *ah, struct ieee80211_channel *chan) 731250003Sadrian{ 732250003Sadrian u_int32_t coef_scaled, ds_coef_exp, ds_coef_man; 733250003Sadrian u_int32_t fclk = COEFF; /* clock * 2.5 */ 734250003Sadrian 735250003Sadrian u_int32_t clock_mhz_scaled = 0x1000000 * fclk; 736250003Sadrian CHAN_CENTERS centers; 737250003Sadrian 738250003Sadrian /* 739250003Sadrian * half and quarter rate can divide the scaled clock by 2 or 4 740250003Sadrian * scale for selected channel bandwidth 741250003Sadrian */ 742250008Sadrian if (IEEE80211_IS_CHAN_HALF(chan)) { 743250003Sadrian clock_mhz_scaled = clock_mhz_scaled >> 1; 744250008Sadrian } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { 745250003Sadrian clock_mhz_scaled = clock_mhz_scaled >> 2; 746250003Sadrian } 747250003Sadrian 748250003Sadrian /* 749250003Sadrian * ALGO -> coef = 1e8/fcarrier*fclock/40; 750250003Sadrian * scaled coef to provide precision for this floating calculation 751250003Sadrian */ 752250003Sadrian ar9300_get_channel_centers(ah, chan, ¢ers); 753250003Sadrian coef_scaled = clock_mhz_scaled / centers.synth_center; 754250003Sadrian 755250003Sadrian ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); 756250003Sadrian 757250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_MAN, ds_coef_man); 758250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); 759250003Sadrian 760250003Sadrian /* 761250003Sadrian * For Short GI, 762250003Sadrian * scaled coeff is 9/10 that of normal coeff 763250003Sadrian */ 764250003Sadrian coef_scaled = (9 * coef_scaled) / 10; 765250003Sadrian 766250003Sadrian ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); 767250003Sadrian 768250003Sadrian /* for short gi */ 769250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_MAN, ds_coef_man); 770250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_EXP, ds_coef_exp); 771250003Sadrian} 772250003Sadrian 773250008Sadrian#define IS(_c, _f) (IEEE80211_IS_ ## _f(_c)) 774250003Sadrian 775250008Sadrian/* 776250008Sadrian * XXX FreeBSD: This should be turned into something generic in ath_hal! 777250008Sadrian */ 778250008SadrianHAL_CHANNEL_INTERNAL * 779250008Sadrianar9300_check_chan(struct ath_hal *ah, const struct ieee80211_channel *chan) 780250003Sadrian{ 781251735Sadrian 782251735Sadrian if (chan == NULL) { 783251735Sadrian return AH_NULL; 784251735Sadrian } 785251735Sadrian 786250008Sadrian if ((IS(chan, CHAN_2GHZ) ^ IS(chan, CHAN_5GHZ)) == 0) { 787250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 788250003Sadrian "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n", 789250008Sadrian __func__, chan->ic_freq , chan->ic_flags); 790250003Sadrian return AH_NULL; 791250003Sadrian } 792250003Sadrian 793250008Sadrian /* 794250008Sadrian * FreeBSD sets multiple flags, so this will fail. 795250008Sadrian */ 796250008Sadrian#if 0 797250008Sadrian if ((IS(chan, CHAN_OFDM) ^ IS(chan, CHAN_CCK) ^ IS(chan, CHAN_DYN) ^ 798250008Sadrian IS(chan, CHAN_HT20) ^ IS(chan, CHAN_HT40U) ^ 799250008Sadrian IS(chan, CHAN_HT40D)) == 0) 800250003Sadrian { 801250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 802250003Sadrian "%s: invalid channel %u/0x%x; not marked as " 803250008Sadrian "OFDM or CCK or DYN or HT20 or HT40PLUS or HT40MINUS\n", 804250008Sadrian __func__, chan->ic_freq , chan->ic_flags); 805250003Sadrian return AH_NULL; 806250003Sadrian } 807250008Sadrian#endif 808250003Sadrian 809250003Sadrian return (ath_hal_checkchannel(ah, chan)); 810250003Sadrian} 811250003Sadrian#undef IS 812250003Sadrian 813250003Sadrianstatic void 814250008Sadrianar9300_set_11n_regs(struct ath_hal *ah, struct ieee80211_channel *chan, 815250003Sadrian HAL_HT_MACMODE macmode) 816250003Sadrian{ 817250003Sadrian u_int32_t phymode; 818250008Sadrian// struct ath_hal_9300 *ahp = AH9300(ah); 819250003Sadrian u_int32_t enable_dac_fifo; 820250003Sadrian 821250003Sadrian /* XXX */ 822250003Sadrian enable_dac_fifo = 823250003Sadrian OS_REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO; 824250003Sadrian 825250003Sadrian /* Enable 11n HT, 20 MHz */ 826250003Sadrian phymode = 827250003Sadrian AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_SHORT_GI_40 828250003Sadrian | enable_dac_fifo; 829250003Sadrian /* Configure baseband for dynamic 20/40 operation */ 830250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 831250003Sadrian phymode |= AR_PHY_GC_DYN2040_EN; 832250003Sadrian /* Configure control (primary) channel at +-10MHz */ 833250008Sadrian if (IEEE80211_IS_CHAN_HT40U(chan)) { 834250003Sadrian phymode |= AR_PHY_GC_DYN2040_PRI_CH; 835250003Sadrian } 836250003Sadrian 837250008Sadrian#if 0 838250003Sadrian /* Configure 20/25 spacing */ 839250003Sadrian if (ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_25) { 840250003Sadrian phymode |= AR_PHY_GC_DYN2040_EXT_CH; 841250003Sadrian } 842250008Sadrian#endif 843250003Sadrian } 844250003Sadrian 845250003Sadrian /* make sure we preserve INI settings */ 846250003Sadrian phymode |= OS_REG_READ(ah, AR_PHY_GEN_CTRL); 847250003Sadrian 848250003Sadrian /* EV 62881/64991 - turn off Green Field detection for Maverick STA beta */ 849250003Sadrian phymode &= ~AR_PHY_GC_GF_DETECT_EN; 850250003Sadrian 851250003Sadrian OS_REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode); 852250003Sadrian 853250003Sadrian /* Set IFS timing for half/quarter rates */ 854250008Sadrian if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) { 855250003Sadrian u_int32_t modeselect = OS_REG_READ(ah, AR_PHY_MODE); 856250003Sadrian 857250008Sadrian if (IEEE80211_IS_CHAN_HALF(chan)) { 858250003Sadrian modeselect |= AR_PHY_MS_HALF_RATE; 859250008Sadrian } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { 860250003Sadrian modeselect |= AR_PHY_MS_QUARTER_RATE; 861250003Sadrian } 862250003Sadrian OS_REG_WRITE(ah, AR_PHY_MODE, modeselect); 863250003Sadrian 864250003Sadrian ar9300_set_ifs_timing(ah, chan); 865250003Sadrian OS_REG_RMW_FIELD( 866250003Sadrian ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 0x3); 867250003Sadrian } 868250003Sadrian 869250003Sadrian /* Configure MAC for 20/40 operation */ 870250003Sadrian ar9300_set_11n_mac2040(ah, macmode); 871250003Sadrian 872250003Sadrian /* global transmit timeout (25 TUs default)*/ 873250003Sadrian /* XXX - put this elsewhere??? */ 874250003Sadrian OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); 875250003Sadrian 876250003Sadrian /* carrier sense timeout */ 877250003Sadrian OS_REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); 878250003Sadrian} 879250003Sadrian 880250003Sadrian/* 881250003Sadrian * Spur mitigation for MRC CCK 882250003Sadrian */ 883250003Sadrianstatic void 884250008Sadrianar9300_spur_mitigate_mrc_cck(struct ath_hal *ah, struct ieee80211_channel *chan) 885250003Sadrian{ 886250003Sadrian int i; 887250003Sadrian /* spur_freq_for_osprey - hardcoded by Systems team for now. */ 888250003Sadrian u_int32_t spur_freq_for_osprey[4] = { 2420, 2440, 2464, 2480 }; 889250003Sadrian u_int32_t spur_freq_for_jupiter[2] = { 2440, 2464}; 890250003Sadrian int cur_bb_spur, negative = 0, cck_spur_freq; 891250003Sadrian u_int8_t* spur_fbin_ptr = NULL; 892250003Sadrian int synth_freq; 893250003Sadrian int range = 10; 894250003Sadrian int max_spurcounts = OSPREY_EEPROM_MODAL_SPURS; 895250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 896250003Sadrian 897250003Sadrian /* 898250003Sadrian * Need to verify range +/- 10 MHz in control channel, otherwise spur 899250003Sadrian * is out-of-band and can be ignored. 900250003Sadrian */ 901250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || 902250003Sadrian AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 903250003Sadrian spur_fbin_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1); 904250003Sadrian if (spur_fbin_ptr[0] == 0) { 905250003Sadrian return; /* No spur in the mode */ 906250003Sadrian } 907250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 908250003Sadrian range = 19; 909250003Sadrian if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) 910250003Sadrian == 0x0) 911250003Sadrian { 912250008Sadrian synth_freq = ichan->channel + 10; 913250003Sadrian } else { 914250008Sadrian synth_freq = ichan->channel - 10; 915250003Sadrian } 916250003Sadrian } else { 917250003Sadrian range = 10; 918250008Sadrian synth_freq = ichan->channel; 919250003Sadrian } 920250003Sadrian } else if(AR_SREV_JUPITER(ah)) { 921250003Sadrian range = 5; 922250003Sadrian max_spurcounts = 2; /* Hardcoded by Jupiter Systems team for now. */ 923250008Sadrian synth_freq = ichan->channel; 924250003Sadrian } else { 925250003Sadrian range = 10; 926250003Sadrian max_spurcounts = 4; /* Hardcoded by Osprey Systems team for now. */ 927250008Sadrian synth_freq = ichan->channel; 928250003Sadrian } 929250003Sadrian 930250003Sadrian for (i = 0; i < max_spurcounts; i++) { 931250003Sadrian negative = 0; 932250003Sadrian 933250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || 934250003Sadrian AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 935250003Sadrian cur_bb_spur = 936250003Sadrian FBIN2FREQ(spur_fbin_ptr[i], HAL_FREQ_BAND_2GHZ) - synth_freq; 937250003Sadrian } else if(AR_SREV_JUPITER(ah)) { 938250003Sadrian cur_bb_spur = spur_freq_for_jupiter[i] - synth_freq; 939250003Sadrian } else { 940250003Sadrian cur_bb_spur = spur_freq_for_osprey[i] - synth_freq; 941250003Sadrian } 942250003Sadrian 943250003Sadrian if (cur_bb_spur < 0) { 944250003Sadrian negative = 1; 945250003Sadrian cur_bb_spur = -cur_bb_spur; 946250003Sadrian } 947250003Sadrian if (cur_bb_spur < range) { 948250003Sadrian cck_spur_freq = (int)((cur_bb_spur << 19) / 11); 949250003Sadrian if (negative == 1) { 950250003Sadrian cck_spur_freq = -cck_spur_freq; 951250003Sadrian } 952250003Sadrian cck_spur_freq = cck_spur_freq & 0xfffff; 953250003Sadrian /*OS_REG_WRITE_field(ah, BB_agc_control.ycok_max, 0x7);*/ 954250003Sadrian OS_REG_RMW_FIELD(ah, 955250003Sadrian AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7); 956250003Sadrian /*OS_REG_WRITE_field(ah, BB_cck_spur_mit.spur_rssi_thr, 0x7f);*/ 957250003Sadrian OS_REG_RMW_FIELD(ah, 958250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f); 959250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.spur_filter_type, 0x2);*/ 960250003Sadrian OS_REG_RMW_FIELD(ah, 961250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE, 0x2); 962250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x1);*/ 963250003Sadrian OS_REG_RMW_FIELD(ah, 964250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x1); 965250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, cck_spur_freq);*/ 966250003Sadrian OS_REG_RMW_FIELD(ah, 967250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 968250003Sadrian cck_spur_freq); 969250003Sadrian return; 970250003Sadrian } 971250003Sadrian } 972250003Sadrian 973250003Sadrian /*OS_REG_WRITE(ah, BB_agc_control.ycok_max, 0x5);*/ 974250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5); 975250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x0);*/ 976250003Sadrian OS_REG_RMW_FIELD(ah, 977250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0); 978250003Sadrian /*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, 0x0);*/ 979250003Sadrian OS_REG_RMW_FIELD(ah, 980250003Sadrian AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0x0); 981250003Sadrian} 982250003Sadrian 983250003Sadrian/* Spur mitigation for OFDM */ 984250003Sadrianstatic void 985250008Sadrianar9300_spur_mitigate_ofdm(struct ath_hal *ah, struct ieee80211_channel *chan) 986250003Sadrian{ 987250003Sadrian int synth_freq; 988250003Sadrian int range = 10; 989250003Sadrian int freq_offset = 0; 990250003Sadrian int spur_freq_sd = 0; 991250003Sadrian int spur_subchannel_sd = 0; 992250003Sadrian int spur_delta_phase = 0; 993250003Sadrian int mask_index = 0; 994250003Sadrian int i; 995250003Sadrian int mode; 996250003Sadrian u_int8_t* spur_chans_ptr; 997250008Sadrian struct ath_hal_9300 *ahp; 998250008Sadrian ahp = AH9300(ah); 999250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 1000250003Sadrian 1001250008Sadrian if (IS_CHAN_5GHZ(ichan)) { 1002250003Sadrian spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 0); 1003250003Sadrian mode = 0; 1004250003Sadrian } else { 1005250003Sadrian spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1); 1006250003Sadrian mode = 1; 1007250003Sadrian } 1008250003Sadrian 1009250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 1010250003Sadrian range = 19; 1011250003Sadrian if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) 1012250003Sadrian == 0x0) 1013250003Sadrian { 1014250008Sadrian synth_freq = ichan->channel - 10; 1015250003Sadrian } else { 1016250008Sadrian synth_freq = ichan->channel + 10; 1017250003Sadrian } 1018250003Sadrian } else { 1019250003Sadrian range = 10; 1020250008Sadrian synth_freq = ichan->channel; 1021250003Sadrian } 1022250003Sadrian 1023250003Sadrian /* Clean all spur register fields */ 1024250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0); 1025250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, 0); 1026250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0); 1027250003Sadrian OS_REG_RMW_FIELD(ah, 1028250003Sadrian AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 0); 1029250003Sadrian OS_REG_RMW_FIELD(ah, 1030250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0); 1031250003Sadrian OS_REG_RMW_FIELD(ah, 1032250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0); 1033250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0); 1034250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 0); 1035250003Sadrian OS_REG_RMW_FIELD(ah, 1036250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 0); 1037250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0); 1038250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0); 1039250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0); 1040250003Sadrian OS_REG_RMW_FIELD(ah, 1041250003Sadrian AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0); 1042250003Sadrian OS_REG_RMW_FIELD(ah, 1043250003Sadrian AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0); 1044250003Sadrian OS_REG_RMW_FIELD(ah, 1045250003Sadrian AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0); 1046250003Sadrian OS_REG_RMW_FIELD(ah, 1047250003Sadrian AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0); 1048250003Sadrian OS_REG_RMW_FIELD(ah, 1049250003Sadrian AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0); 1050250003Sadrian OS_REG_RMW_FIELD(ah, 1051250003Sadrian AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0); 1052250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0); 1053250003Sadrian 1054250003Sadrian i = 0; 1055250003Sadrian while (spur_chans_ptr[i] && i < 5) { 1056250003Sadrian freq_offset = FBIN2FREQ(spur_chans_ptr[i], mode) - synth_freq; 1057250003Sadrian if (abs(freq_offset) < range) { 1058250003Sadrian /* 1059250003Sadrian printf( 1060250003Sadrian "Spur Mitigation for OFDM: Synth Frequency = %d, " 1061250003Sadrian "Spur Frequency = %d\n", 1062250003Sadrian synth_freq, FBIN2FREQ(spur_chans_ptr[i], mode)); 1063250003Sadrian */ 1064250008Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 1065250003Sadrian if (freq_offset < 0) { 1066250003Sadrian if (OS_REG_READ_FIELD( 1067250003Sadrian ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0) 1068250003Sadrian { 1069250003Sadrian spur_subchannel_sd = 1; 1070250003Sadrian } else { 1071250003Sadrian spur_subchannel_sd = 0; 1072250003Sadrian } 1073250003Sadrian spur_freq_sd = ((freq_offset + 10) << 9) / 11; 1074250003Sadrian } else { 1075250003Sadrian if (OS_REG_READ_FIELD(ah, 1076250003Sadrian AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0) 1077250003Sadrian { 1078250003Sadrian spur_subchannel_sd = 0; 1079250003Sadrian } else { 1080250003Sadrian spur_subchannel_sd = 1; 1081250003Sadrian } 1082250003Sadrian spur_freq_sd = ((freq_offset - 10) << 9) / 11; 1083250003Sadrian } 1084250003Sadrian spur_delta_phase = (freq_offset << 17) / 5; 1085250003Sadrian } else { 1086250003Sadrian spur_subchannel_sd = 0; 1087250003Sadrian spur_freq_sd = (freq_offset << 9) / 11; 1088250003Sadrian spur_delta_phase = (freq_offset << 18) / 5; 1089250003Sadrian } 1090250003Sadrian spur_freq_sd = spur_freq_sd & 0x3ff; 1091250003Sadrian spur_delta_phase = spur_delta_phase & 0xfffff; 1092250003Sadrian /* 1093250003Sadrian printf( 1094250003Sadrian "spur_subchannel_sd = %d, spur_freq_sd = 0x%x, " 1095250003Sadrian "spur_delta_phase = 0x%x\n", spur_subchannel_sd, 1096250003Sadrian spur_freq_sd, spur_delta_phase); 1097250003Sadrian */ 1098250003Sadrian 1099250003Sadrian /* OFDM Spur mitigation */ 1100250003Sadrian OS_REG_RMW_FIELD(ah, 1101250003Sadrian AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0x1); 1102250003Sadrian OS_REG_RMW_FIELD(ah, 1103250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd); 1104250003Sadrian OS_REG_RMW_FIELD(ah, 1105250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 1106250003Sadrian spur_delta_phase); 1107250003Sadrian OS_REG_RMW_FIELD(ah, 1108250003Sadrian AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 1109250003Sadrian spur_subchannel_sd); 1110250003Sadrian OS_REG_RMW_FIELD(ah, 1111250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0x1); 1112250003Sadrian OS_REG_RMW_FIELD(ah, 1113250003Sadrian AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 1114250003Sadrian 0x1); 1115250003Sadrian OS_REG_RMW_FIELD(ah, 1116250003Sadrian AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0x1); 1117250003Sadrian OS_REG_RMW_FIELD(ah, 1118250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34); 1119250003Sadrian OS_REG_RMW_FIELD(ah, 1120250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1); 1121250003Sadrian 1122250003Sadrian /* 1123250003Sadrian * Do not subtract spur power from noise floor for wasp. 1124250003Sadrian * This causes the maximum client test (on Veriwave) to fail 1125250003Sadrian * when run on spur channel (2464 MHz). 1126250003Sadrian * Refer to ev#82746 and ev#82744. 1127250003Sadrian */ 1128250003Sadrian if (!AR_SREV_WASP(ah) && (OS_REG_READ_FIELD(ah, AR_PHY_MODE, 1129250003Sadrian AR_PHY_MODE_DYNAMIC) == 0x1)) { 1130250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, 1131250003Sadrian AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1); 1132250003Sadrian } 1133250003Sadrian 1134250003Sadrian mask_index = (freq_offset << 4) / 5; 1135250003Sadrian if (mask_index < 0) { 1136250003Sadrian mask_index = mask_index - 1; 1137250003Sadrian } 1138250003Sadrian mask_index = mask_index & 0x7f; 1139250003Sadrian /*printf("Bin 0x%x\n", mask_index);*/ 1140250003Sadrian 1141250003Sadrian OS_REG_RMW_FIELD(ah, 1142250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0x1); 1143250003Sadrian OS_REG_RMW_FIELD(ah, 1144250003Sadrian AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0x1); 1145250003Sadrian OS_REG_RMW_FIELD(ah, 1146250003Sadrian AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1); 1147250003Sadrian OS_REG_RMW_FIELD(ah, 1148250003Sadrian AR_PHY_PILOT_SPUR_MASK, 1149250003Sadrian AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index); 1150250003Sadrian OS_REG_RMW_FIELD(ah, 1151250003Sadrian AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 1152250003Sadrian mask_index); 1153250003Sadrian OS_REG_RMW_FIELD(ah, 1154250003Sadrian AR_PHY_CHAN_SPUR_MASK, 1155250003Sadrian AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index); 1156250003Sadrian OS_REG_RMW_FIELD(ah, 1157250003Sadrian AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 1158250003Sadrian 0xc); 1159250003Sadrian OS_REG_RMW_FIELD(ah, 1160250003Sadrian AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 1161250003Sadrian 0xc); 1162250003Sadrian OS_REG_RMW_FIELD(ah, 1163250003Sadrian AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0); 1164250003Sadrian OS_REG_RMW_FIELD(ah, 1165250003Sadrian AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff); 1166250003Sadrian /* 1167250003Sadrian printf("BB_timing_control_4 = 0x%x\n", 1168250003Sadrian OS_REG_READ(ah, AR_PHY_TIMING4)); 1169250003Sadrian printf("BB_timing_control_11 = 0x%x\n", 1170250003Sadrian OS_REG_READ(ah, AR_PHY_TIMING11)); 1171250003Sadrian printf("BB_ext_chan_scorr_thr = 0x%x\n", 1172250003Sadrian OS_REG_READ(ah, AR_PHY_SFCORR_EXT)); 1173250003Sadrian printf("BB_spur_mask_controls = 0x%x\n", 1174250003Sadrian OS_REG_READ(ah, AR_PHY_SPUR_REG)); 1175250003Sadrian printf("BB_pilot_spur_mask = 0x%x\n", 1176250003Sadrian OS_REG_READ(ah, AR_PHY_PILOT_SPUR_MASK)); 1177250003Sadrian printf("BB_chan_spur_mask = 0x%x\n", 1178250003Sadrian OS_REG_READ(ah, AR_PHY_CHAN_SPUR_MASK)); 1179250003Sadrian printf("BB_vit_spur_mask_A = 0x%x\n", 1180250003Sadrian OS_REG_READ(ah, AR_PHY_SPUR_MASK_A)); 1181250003Sadrian */ 1182250003Sadrian break; 1183250003Sadrian } 1184250003Sadrian i++; 1185250003Sadrian } 1186250003Sadrian} 1187250003Sadrian 1188250003Sadrian 1189250003Sadrian/* 1190250003Sadrian * Convert to baseband spur frequency given input channel frequency 1191250003Sadrian * and compute register settings below. 1192250003Sadrian */ 1193250003Sadrianstatic void 1194250008Sadrianar9300_spur_mitigate(struct ath_hal *ah, struct ieee80211_channel *chan) 1195250003Sadrian{ 1196250003Sadrian ar9300_spur_mitigate_ofdm(ah, chan); 1197250003Sadrian ar9300_spur_mitigate_mrc_cck(ah, chan); 1198250003Sadrian} 1199250003Sadrian 1200250003Sadrian/************************************************************** 1201250003Sadrian * ar9300_channel_change 1202250003Sadrian * Assumes caller wants to change channel, and not reset. 1203250003Sadrian */ 1204250003Sadrianstatic inline HAL_BOOL 1205250008Sadrianar9300_channel_change(struct ath_hal *ah, struct ieee80211_channel *chan, 1206250003Sadrian HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode) 1207250003Sadrian{ 1208250003Sadrian 1209250003Sadrian u_int32_t synth_delay, qnum; 1210250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1211250003Sadrian 1212250003Sadrian /* TX must be stopped by now */ 1213250003Sadrian for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { 1214250003Sadrian if (ar9300_num_tx_pending(ah, qnum)) { 1215250003Sadrian HALDEBUG(ah, HAL_DEBUG_QUEUE, 1216250003Sadrian "%s: Transmit frames pending on queue %d\n", __func__, qnum); 1217250003Sadrian HALASSERT(0); 1218250003Sadrian return AH_FALSE; 1219250003Sadrian } 1220250003Sadrian } 1221250003Sadrian 1222250003Sadrian 1223250003Sadrian /* 1224250003Sadrian * Kill last Baseband Rx Frame - Request analog bus grant 1225250003Sadrian */ 1226250003Sadrian OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); 1227250003Sadrian if (!ath_hal_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, 1228250008Sadrian AR_PHY_RFBUS_GRANT_EN)) 1229250003Sadrian { 1230250008Sadrian HALDEBUG(ah, HAL_DEBUG_PHYIO, 1231250003Sadrian "%s: Could not kill baseband RX\n", __func__); 1232250003Sadrian return AH_FALSE; 1233250003Sadrian } 1234250003Sadrian 1235250003Sadrian 1236250003Sadrian /* Setup 11n MAC/Phy mode registers */ 1237250003Sadrian ar9300_set_11n_regs(ah, chan, macmode); 1238250003Sadrian 1239250003Sadrian /* 1240250003Sadrian * Change the synth 1241250003Sadrian */ 1242250008Sadrian if (!ahp->ah_rf_hal.set_channel(ah, chan)) { 1243250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: failed to set channel\n", __func__); 1244250003Sadrian return AH_FALSE; 1245250003Sadrian } 1246250003Sadrian 1247250003Sadrian /* 1248250003Sadrian * Some registers get reinitialized during ATH_INI_POST INI programming. 1249250003Sadrian */ 1250250003Sadrian ar9300_init_user_settings(ah); 1251250003Sadrian 1252250003Sadrian /* 1253250003Sadrian * Setup the transmit power values. 1254250003Sadrian * 1255250003Sadrian * After the public to private hal channel mapping, ichan contains the 1256250003Sadrian * valid regulatory power value. 1257250003Sadrian * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan. 1258250003Sadrian */ 1259250003Sadrian if (ar9300_eeprom_set_transmit_power( 1260250008Sadrian ah, &ahp->ah_eeprom, chan, ath_hal_getctl(ah, chan), 1261250003Sadrian ath_hal_getantennaallowed(ah, chan), 1262250003Sadrian ath_hal_get_twice_max_regpower(AH_PRIVATE(ah), ichan, chan), 1263250008Sadrian AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit)) != HAL_OK) 1264250003Sadrian { 1265250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 1266250003Sadrian "%s: error init'ing transmit power\n", __func__); 1267250003Sadrian return AH_FALSE; 1268250003Sadrian } 1269250003Sadrian 1270250003Sadrian /* 1271250003Sadrian * Release the RFBus Grant. 1272250003Sadrian */ 1273250003Sadrian OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); 1274250003Sadrian 1275250003Sadrian /* 1276250003Sadrian * Write spur immunity and delta slope for OFDM enabled modes (A, G, Turbo) 1277250003Sadrian */ 1278250008Sadrian if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) { 1279250008Sadrian ar9300_set_delta_slope(ah, chan); 1280250003Sadrian } else { 1281250003Sadrian /* Set to Ini default */ 1282250003Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING3, 0x9c0a9f6b); 1283250003Sadrian OS_REG_WRITE(ah, AR_PHY_SGI_DELTA, 0x00046384); 1284250003Sadrian } 1285250003Sadrian 1286250003Sadrian ar9300_spur_mitigate(ah, chan); 1287250003Sadrian 1288250003Sadrian 1289250003Sadrian /* 1290250003Sadrian * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN). 1291250003Sadrian * Read the phy active delay register. Value is in 100ns increments. 1292250003Sadrian */ 1293250003Sadrian synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; 1294250008Sadrian if (IEEE80211_IS_CHAN_CCK(chan)) { 1295250003Sadrian synth_delay = (4 * synth_delay) / 22; 1296250003Sadrian } else { 1297250003Sadrian synth_delay /= 10; 1298250003Sadrian } 1299250003Sadrian 1300250003Sadrian OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY); 1301250003Sadrian 1302250003Sadrian /* 1303250003Sadrian * Do calibration. 1304250003Sadrian */ 1305250003Sadrian 1306250003Sadrian return AH_TRUE; 1307250003Sadrian} 1308250003Sadrian 1309250003Sadrianvoid 1310250003Sadrianar9300_set_operating_mode(struct ath_hal *ah, int opmode) 1311250003Sadrian{ 1312250003Sadrian u_int32_t val; 1313250003Sadrian 1314250003Sadrian val = OS_REG_READ(ah, AR_STA_ID1); 1315250003Sadrian val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); 1316250003Sadrian switch (opmode) { 1317250003Sadrian case HAL_M_HOSTAP: 1318250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, 1319250003Sadrian val | AR_STA_ID1_STA_AP | AR_STA_ID1_KSRCH_MODE); 1320250003Sadrian OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); 1321250003Sadrian break; 1322250003Sadrian case HAL_M_IBSS: 1323250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, 1324250003Sadrian val | AR_STA_ID1_ADHOC | AR_STA_ID1_KSRCH_MODE); 1325250003Sadrian OS_REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); 1326250003Sadrian break; 1327250003Sadrian case HAL_M_STA: 1328250003Sadrian case HAL_M_MONITOR: 1329250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); 1330250003Sadrian break; 1331250003Sadrian } 1332250003Sadrian} 1333250003Sadrian 1334250003Sadrian/* XXX need the logic for Osprey */ 1335257855Sianvoid 1336250008Sadrianar9300_init_pll(struct ath_hal *ah, struct ieee80211_channel *chan) 1337250003Sadrian{ 1338250003Sadrian u_int32_t pll; 1339250003Sadrian u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz; 1340250008Sadrian HAL_CHANNEL_INTERNAL *ichan = NULL; 1341250003Sadrian 1342250008Sadrian if (chan) 1343250008Sadrian ichan = ath_hal_checkchannel(ah, chan); 1344250008Sadrian 1345250003Sadrian if (AR_SREV_HORNET(ah)) { 1346250003Sadrian if (clk_25mhz) { 1347250003Sadrian /* Hornet uses PLL_CONTROL_2. Xtal is 25MHz for Hornet. 1348250003Sadrian * REFDIV set to 0x1. 1349250003Sadrian * $xtal_freq = 25; 1350250003Sadrian * $PLL2_div = (704/$xtal_freq); # 176 * 4 = 704. 1351250003Sadrian * MAC and BB run at 176 MHz. 1352250003Sadrian * $PLL2_divint = int($PLL2_div); 1353250003Sadrian * $PLL2_divfrac = $PLL2_div - $PLL2_divint; 1354250003Sadrian * $PLL2_divfrac = int($PLL2_divfrac * 0x4000); # 2^14 1355250003Sadrian * $PLL2_Val = ($PLL2_divint & 0x3f) << 19 | (0x1) << 14 | 1356250003Sadrian * $PLL2_divfrac & 0x3fff; 1357250003Sadrian * Therefore, $PLL2_Val = 0xe04a3d 1358250003Sadrian */ 1359250003Sadrian#define DPLL2_KD_VAL 0x1D 1360250003Sadrian#define DPLL2_KI_VAL 0x06 1361250003Sadrian#define DPLL3_PHASE_SHIFT_VAL 0x1 1362250003Sadrian 1363250003Sadrian /* Rewrite DDR PLL2 and PLL3 */ 1364250003Sadrian /* program DDR PLL ki and kd value, ki=0x6, kd=0x1d */ 1365250003Sadrian OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x18e82f01); 1366250003Sadrian 1367250003Sadrian /* program DDR PLL phase_shift to 0x1 */ 1368250003Sadrian OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3, 1369250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); 1370250003Sadrian 1371250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); 1372250003Sadrian OS_DELAY(1000); 1373250003Sadrian 1374250003Sadrian /* program refdiv, nint, frac to RTC register */ 1375250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0xe04a3d); 1376250003Sadrian 1377250003Sadrian /* program BB PLL ki and kd value, ki=0x6, kd=0x1d */ 1378250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1379250003Sadrian AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL); 1380250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1381250003Sadrian AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL); 1382250003Sadrian 1383250003Sadrian /* program BB PLL phase_shift to 0x1 */ 1384250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, 1385250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); 1386250003Sadrian } else { /* 40MHz */ 1387250003Sadrian#undef DPLL2_KD_VAL 1388250003Sadrian#undef DPLL2_KI_VAL 1389250003Sadrian#define DPLL2_KD_VAL 0x3D 1390250003Sadrian#define DPLL2_KI_VAL 0x06 1391250003Sadrian /* Rewrite DDR PLL2 and PLL3 */ 1392250003Sadrian /* program DDR PLL ki and kd value, ki=0x6, kd=0x3d */ 1393250003Sadrian OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x19e82f01); 1394250003Sadrian 1395250003Sadrian /* program DDR PLL phase_shift to 0x1 */ 1396250003Sadrian OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3, 1397250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); 1398250003Sadrian 1399250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); 1400250003Sadrian OS_DELAY(1000); 1401250003Sadrian 1402250003Sadrian /* program refdiv, nint, frac to RTC register */ 1403250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); 1404250003Sadrian 1405250003Sadrian /* program BB PLL ki and kd value, ki=0x6, kd=0x3d */ 1406250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1407250003Sadrian AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL); 1408250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1409250003Sadrian AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL); 1410250003Sadrian 1411250003Sadrian /* program BB PLL phase_shift to 0x1 */ 1412250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, 1413250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); 1414250003Sadrian } 1415250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); 1416250003Sadrian OS_DELAY(1000); 1417250003Sadrian } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 1418250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_PLL_PWD, 0x1); 1419250003Sadrian 1420250003Sadrian /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */ 1421250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1422250003Sadrian AR_PHY_BB_DPLL2_KD, 0x40); 1423250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1424250003Sadrian AR_PHY_BB_DPLL2_KI, 0x4); 1425250003Sadrian 1426250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, 1427250003Sadrian AR_PHY_BB_DPLL1_REFDIV, 0x5); 1428250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, 1429250003Sadrian AR_PHY_BB_DPLL1_NINI, 0x58); 1430250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, 1431250003Sadrian AR_PHY_BB_DPLL1_NFRAC, 0x0); 1432250003Sadrian 1433250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1434250003Sadrian AR_PHY_BB_DPLL2_OUTDIV, 0x1); 1435250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1436250003Sadrian AR_PHY_BB_DPLL2_LOCAL_PLL, 0x1); 1437250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1438250003Sadrian AR_PHY_BB_DPLL2_EN_NEGTRIG, 0x1); 1439250003Sadrian 1440250003Sadrian /* program BB PLL phase_shift to 0x6 */ 1441250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, 1442250003Sadrian AR_PHY_BB_DPLL3_PHASE_SHIFT, 0x6); 1443250003Sadrian 1444250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, 1445250003Sadrian AR_PHY_BB_DPLL2_PLL_PWD, 0x0); 1446250003Sadrian OS_DELAY(1000); 1447250003Sadrian 1448250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); 1449250003Sadrian OS_DELAY(1000); 1450250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 1451250003Sadrian#define SRIF_PLL 1 1452250003Sadrian u_int32_t regdata, pll2_divint, pll2_divfrac; 1453250003Sadrian 1454250003Sadrian#ifndef SRIF_PLL 1455250003Sadrian u_int32_t pll2_clkmode; 1456250003Sadrian#endif 1457250003Sadrian 1458250003Sadrian#ifdef SRIF_PLL 1459250003Sadrian u_int32_t refdiv; 1460250003Sadrian#endif 1461250003Sadrian if (clk_25mhz) { 1462250003Sadrian#ifndef SRIF_PLL 1463250003Sadrian pll2_divint = 0x1c; 1464250003Sadrian pll2_divfrac = 0xa3d7; 1465250003Sadrian#else 1466250003Sadrian pll2_divint = 0x54; 1467250003Sadrian pll2_divfrac = 0x1eb85; 1468250003Sadrian refdiv = 3; 1469250003Sadrian#endif 1470250003Sadrian } else { 1471250003Sadrian#ifndef SRIF_PLL 1472250003Sadrian pll2_divint = 0x11; 1473250003Sadrian pll2_divfrac = 0x26666; 1474250003Sadrian#else 1475250003Sadrian if (AR_SREV_WASP(ah)) { 1476250003Sadrian pll2_divint = 88; 1477250003Sadrian pll2_divfrac = 0; 1478250003Sadrian refdiv = 5; 1479250003Sadrian } else { 1480250003Sadrian pll2_divint = 0x11; 1481250003Sadrian pll2_divfrac = 0x26666; 1482250003Sadrian refdiv = 1; 1483250003Sadrian } 1484250003Sadrian#endif 1485250003Sadrian } 1486250003Sadrian#ifndef SRIF_PLL 1487250003Sadrian pll2_clkmode = 0x3d; 1488250003Sadrian#endif 1489250003Sadrian /* PLL programming through SRIF Local Mode */ 1490250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); /* Bypass mode */ 1491250003Sadrian OS_DELAY(1000); 1492250003Sadrian do { 1493250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); 1494250003Sadrian regdata = regdata | (0x1 << 16); 1495250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 1 */ 1496250003Sadrian OS_DELAY(100); 1497250003Sadrian /* override int, frac, refdiv */ 1498250003Sadrian#ifndef SRIF_PLL 1499250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL, 1500250003Sadrian ((1 << 27) | (pll2_divint << 18) | pll2_divfrac)); 1501250003Sadrian#else 1502250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL, 1503250003Sadrian ((refdiv << 27) | (pll2_divint << 18) | pll2_divfrac)); 1504250003Sadrian#endif 1505250003Sadrian OS_DELAY(100); 1506250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); 1507250003Sadrian#ifndef SRIF_PLL 1508250003Sadrian regdata = (regdata & 0x80071fff) | 1509250003Sadrian (0x1 << 30) | (0x1 << 13) | (0x6 << 26) | (pll2_clkmode << 19); 1510250003Sadrian#else 1511250003Sadrian if (AR_SREV_WASP(ah)) { 1512250003Sadrian regdata = (regdata & 0x80071fff) | 1513250003Sadrian (0x1 << 30) | (0x1 << 13) | (0x4 << 26) | (0x18 << 19); 1514250003Sadrian } else { 1515250003Sadrian regdata = (regdata & 0x80071fff) | 1516250003Sadrian (0x3 << 30) | (0x1 << 13) | (0x4 << 26) | (0x60 << 19); 1517250003Sadrian } 1518250003Sadrian#endif 1519250003Sadrian /* Ki, Kd, Local PLL, Outdiv */ 1520250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); 1521250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); 1522250003Sadrian regdata = (regdata & 0xfffeffff); 1523250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 0 */ 1524250003Sadrian OS_DELAY(1000); 1525250003Sadrian if (AR_SREV_WASP(ah)) { 1526250003Sadrian /* clear do measure */ 1527250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); 1528250003Sadrian regdata &= ~(1 << 30); 1529250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); 1530250003Sadrian OS_DELAY(100); 1531250003Sadrian 1532250003Sadrian /* set do measure */ 1533250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); 1534250003Sadrian regdata |= (1 << 30); 1535250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); 1536250003Sadrian 1537250003Sadrian /* wait for measure done */ 1538250003Sadrian do { 1539250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL4); 1540250003Sadrian } while ((regdata & (1 << 3)) == 0); 1541250003Sadrian 1542250003Sadrian /* clear do measure */ 1543250003Sadrian regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); 1544250003Sadrian regdata &= ~(1 << 30); 1545250003Sadrian OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); 1546250003Sadrian 1547250003Sadrian /* get measure sqsum dvc */ 1548250003Sadrian regdata = (OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3) & 0x007FFFF8) >> 3; 1549250003Sadrian } else { 1550250003Sadrian break; 1551250003Sadrian } 1552250003Sadrian } while (regdata >= 0x40000); 1553250003Sadrian 1554250003Sadrian /* Remove from Bypass mode */ 1555250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); 1556250003Sadrian OS_DELAY(1000); 1557250003Sadrian } else { 1558250003Sadrian pll = SM(0x5, AR_RTC_PLL_REFDIV); 1559250003Sadrian 1560250003Sadrian /* Supposedly not needed on Osprey */ 1561250003Sadrian#if 0 1562250003Sadrian if (chan && IS_CHAN_HALF_RATE(chan)) { 1563250003Sadrian pll |= SM(0x1, AR_RTC_PLL_CLKSEL); 1564250003Sadrian } else if (chan && IS_CHAN_QUARTER_RATE(chan)) { 1565250003Sadrian pll |= SM(0x2, AR_RTC_PLL_CLKSEL); 1566250003Sadrian } 1567250003Sadrian#endif 1568250008Sadrian if (ichan && IS_CHAN_5GHZ(ichan)) { 1569250003Sadrian pll |= SM(0x28, AR_RTC_PLL_DIV); 1570250003Sadrian /* 1571250003Sadrian * When doing fast clock, set PLL to 0x142c 1572250003Sadrian */ 1573250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { 1574250003Sadrian pll = 0x142c; 1575250003Sadrian } 1576250003Sadrian } else { 1577250003Sadrian pll |= SM(0x2c, AR_RTC_PLL_DIV); 1578250003Sadrian } 1579250003Sadrian 1580250003Sadrian OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); 1581250003Sadrian } 1582250003Sadrian 1583250003Sadrian /* TODO: 1584250003Sadrian * For multi-band owl, switch between bands by reiniting the PLL. 1585250003Sadrian */ 1586250003Sadrian OS_DELAY(RTC_PLL_SETTLE_DELAY); 1587250003Sadrian 1588250003Sadrian OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, 1589250003Sadrian AR_RTC_FORCE_DERIVED_CLK | AR_RTC_PCIE_RST_PWDN_EN); 1590250003Sadrian 1591250003Sadrian if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 1592250003Sadrian if (clk_25mhz) { 1593250003Sadrian OS_REG_WRITE(ah, 1594250003Sadrian AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); /* 32KHz sleep clk */ 1595250003Sadrian OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); 1596250003Sadrian OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); 1597250003Sadrian } else { 1598250003Sadrian OS_REG_WRITE(ah, 1599250003Sadrian AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); /* 32KHz sleep clk */ 1600250003Sadrian OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); 1601250003Sadrian OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); 1602250003Sadrian } 1603250003Sadrian OS_DELAY(100); 1604250003Sadrian } 1605250003Sadrian} 1606250003Sadrian 1607250003Sadrianstatic inline HAL_BOOL 1608250003Sadrianar9300_set_reset(struct ath_hal *ah, int type) 1609250003Sadrian{ 1610250003Sadrian u_int32_t rst_flags; 1611250003Sadrian u_int32_t tmp_reg; 1612250003Sadrian 1613250003Sadrian HALASSERT(type == HAL_RESET_WARM || type == HAL_RESET_COLD); 1614250003Sadrian 1615250003Sadrian /* 1616250003Sadrian * RTC Force wake should be done before resetting the MAC. 1617250003Sadrian * MDK/ART does it that way. 1618250003Sadrian */ 1619250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); 1620250003Sadrian OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ 1621250003Sadrian OS_REG_WRITE(ah, 1622250003Sadrian AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); 1623250003Sadrian 1624250003Sadrian /* Reset AHB */ 1625250003Sadrian /* Bug26871 */ 1626250003Sadrian tmp_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)); 1627250003Sadrian if (AR_SREV_WASP(ah)) { 1628250003Sadrian if (tmp_reg & (AR9340_INTR_SYNC_LOCAL_TIMEOUT)) { 1629250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); 1630250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); 1631250003Sadrian } 1632250003Sadrian } else { 1633250003Sadrian if (tmp_reg & (AR9300_INTR_SYNC_LOCAL_TIMEOUT | AR9300_INTR_SYNC_RADM_CPL_TIMEOUT)) { 1634250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); 1635250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); 1636250003Sadrian } 1637250003Sadrian else { 1638250003Sadrian /* NO AR_RC_AHB in Osprey */ 1639250003Sadrian /*OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_AHB);*/ 1640250003Sadrian } 1641250003Sadrian } 1642250003Sadrian 1643250003Sadrian rst_flags = AR_RTC_RC_MAC_WARM; 1644250003Sadrian if (type == HAL_RESET_COLD) { 1645250003Sadrian rst_flags |= AR_RTC_RC_MAC_COLD; 1646250003Sadrian } 1647250003Sadrian 1648250003Sadrian#ifdef AH_SUPPORT_HORNET 1649250003Sadrian /* Hornet WAR: trigger SoC to reset WMAC if ... 1650250003Sadrian * (1) doing cold reset. Ref: EV 69254 1651250003Sadrian * (2) beacon pending. Ref: EV 70983 1652250003Sadrian */ 1653250003Sadrian if (AR_SREV_HORNET(ah) && 1654250003Sadrian (ar9300_num_tx_pending( 1655250008Sadrian ah, AH_PRIVATE(ah)->ah_caps.halTotalQueues - 1) != 0 || 1656250003Sadrian type == HAL_RESET_COLD)) 1657250003Sadrian { 1658250003Sadrian u_int32_t time_out; 1659250003Sadrian#define AR_SOC_RST_RESET 0xB806001C 1660250003Sadrian#define AR_SOC_BOOT_STRAP 0xB80600AC 1661250003Sadrian#define AR_SOC_WLAN_RST 0x00000800 /* WLAN reset */ 1662250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 1663250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 1664250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Hornet SoC reset WMAC.\n", __func__); 1665250003Sadrian 1666250003Sadrian REG_WRITE(AR_SOC_RST_RESET, 1667250003Sadrian REG_READ(AR_SOC_RST_RESET) | AR_SOC_WLAN_RST); 1668250003Sadrian REG_WRITE(AR_SOC_RST_RESET, 1669250003Sadrian REG_READ(AR_SOC_RST_RESET) & (~AR_SOC_WLAN_RST)); 1670250003Sadrian 1671250003Sadrian time_out = 0; 1672250003Sadrian 1673250003Sadrian while (1) { 1674250003Sadrian tmp_reg = REG_READ(AR_SOC_BOOT_STRAP); 1675250003Sadrian if ((tmp_reg & 0x10) == 0) { 1676250003Sadrian break; 1677250003Sadrian } 1678250003Sadrian if (time_out > 20) { 1679250003Sadrian break; 1680250003Sadrian } 1681250003Sadrian OS_DELAY(10000); 1682250003Sadrian time_out++; 1683250003Sadrian } 1684250003Sadrian 1685250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 1686250003Sadrian#undef REG_READ 1687250003Sadrian#undef REG_WRITE 1688250003Sadrian#undef AR_SOC_WLAN_RST 1689250003Sadrian#undef AR_SOC_RST_RESET 1690250003Sadrian#undef AR_SOC_BOOT_STRAP 1691250003Sadrian } 1692250003Sadrian#endif /* AH_SUPPORT_HORNET */ 1693250003Sadrian 1694250003Sadrian#ifdef AH_SUPPORT_SCORPION 1695250003Sadrian if (AR_SREV_SCORPION(ah)) { 1696250003Sadrian#define DDR_CTL_CONFIG_ADDRESS 0xb8000000 1697250003Sadrian#define DDR_CTL_CONFIG_OFFSET 0x0108 1698250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MSB 29 1699250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB 21 1700250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK 0x3fe00000 1701250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(x) (((x) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) >> DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) 1702250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_SET(x) (((x) << DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) 1703250003Sadrian#define MAC_DMA_CFG_ADDRESS 0xb8100000 1704250003Sadrian#define MAC_DMA_CFG_OFFSET 0x0014 1705250003Sadrian 1706250003Sadrian#define MAC_DMA_CFG_HALT_REQ_MSB 11 1707250003Sadrian#define MAC_DMA_CFG_HALT_REQ_LSB 11 1708250003Sadrian#define MAC_DMA_CFG_HALT_REQ_MASK 0x00000800 1709250003Sadrian#define MAC_DMA_CFG_HALT_REQ_GET(x) (((x) & MAC_DMA_CFG_HALT_REQ_MASK) >> MAC_DMA_CFG_HALT_REQ_LSB) 1710250003Sadrian#define MAC_DMA_CFG_HALT_REQ_SET(x) (((x) << MAC_DMA_CFG_HALT_REQ_LSB) & MAC_DMA_CFG_HALT_REQ_MASK) 1711250003Sadrian#define MAC_DMA_CFG_HALT_ACK_MSB 12 1712250003Sadrian#define MAC_DMA_CFG_HALT_ACK_LSB 12 1713250003Sadrian#define MAC_DMA_CFG_HALT_ACK_MASK 0x00001000 1714250003Sadrian#define MAC_DMA_CFG_HALT_ACK_GET(x) (((x) & MAC_DMA_CFG_HALT_ACK_MASK) >> MAC_DMA_CFG_HALT_ACK_LSB) 1715250003Sadrian#define MAC_DMA_CFG_HALT_ACK_SET(x) (((x) << MAC_DMA_CFG_HALT_ACK_LSB) & MAC_DMA_CFG_HALT_ACK_MASK) 1716250003Sadrian 1717250003Sadrian#define RST_RESET 0xB806001c 1718250003Sadrian#define RTC_RESET (1<<27) 1719250003Sadrian 1720250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 1721250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 1722250003Sadrian 1723250003Sadrian#define DDR_REG_READ(_ah, _reg) \ 1724250003Sadrian *((volatile u_int32_t *)( DDR_CTL_CONFIG_ADDRESS + (_reg))) 1725250003Sadrian#define DDR_REG_WRITE(_ah, _reg, _val) \ 1726250003Sadrian *((volatile u_int32_t *)(DDR_CTL_CONFIG_ADDRESS + (_reg))) = (_val) 1727250003Sadrian 1728250003Sadrian OS_REG_WRITE(ah,MAC_DMA_CFG_OFFSET, (OS_REG_READ(ah,MAC_DMA_CFG_OFFSET) & ~MAC_DMA_CFG_HALT_REQ_MASK) | 1729250003Sadrian MAC_DMA_CFG_HALT_REQ_SET(1)); 1730250003Sadrian 1731250003Sadrian { 1732250003Sadrian int count; 1733250003Sadrian u_int32_t data; 1734250003Sadrian 1735250003Sadrian count = 0; 1736250003Sadrian while (!MAC_DMA_CFG_HALT_ACK_GET(OS_REG_READ(ah, MAC_DMA_CFG_OFFSET) )) 1737250003Sadrian { 1738250003Sadrian count++; 1739250003Sadrian if (count > 10) { 1740250003Sadrian ath_hal_printf(ah, "Halt ACK timeout\n"); 1741250003Sadrian break; 1742250003Sadrian } 1743250003Sadrian OS_DELAY(10); 1744250003Sadrian } 1745250003Sadrian 1746250003Sadrian data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET); 1747250003Sadrian ath_hal_printf(ah, "check DDR Activity - HIGH\n"); 1748250003Sadrian 1749250003Sadrian count = 0; 1750250003Sadrian while (DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(data)) { 1751250003Sadrian // AVE_DEBUG(0,"DDR Activity - HIGH\n"); 1752250003Sadrian ath_hal_printf(ah, "DDR Activity - HIGH\n"); 1753250003Sadrian count++; 1754250003Sadrian OS_DELAY(10); 1755250003Sadrian data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET); 1756250003Sadrian if (count > 10) { 1757250003Sadrian ath_hal_printf(ah, "DDR Activity timeout\n"); 1758250003Sadrian break; 1759250003Sadrian } 1760250003Sadrian } 1761250003Sadrian } 1762250003Sadrian 1763250003Sadrian 1764250003Sadrian { 1765250003Sadrian //Force RTC reset 1766250003Sadrian REG_WRITE(RST_RESET, (REG_READ(RST_RESET) | RTC_RESET)); 1767250003Sadrian OS_DELAY(10); 1768250003Sadrian REG_WRITE(RST_RESET, (REG_READ(RST_RESET) & ~RTC_RESET)); 1769250003Sadrian OS_DELAY(10); 1770250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 0); 1771250003Sadrian OS_DELAY(10); 1772250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 1773250003Sadrian OS_DELAY(10); 1774250003Sadrian ath_hal_printf(ah,"%s: Scorpion SoC RTC reset done.\n", __func__); 1775250003Sadrian } 1776250003Sadrian#undef REG_READ 1777250003Sadrian#undef REG_WRITE 1778250003Sadrian } 1779250003Sadrian#endif /* AH_SUPPORT_SCORPION */ 1780250003Sadrian 1781250003Sadrian /* 1782250003Sadrian * Set Mac(BB,Phy) Warm Reset 1783250003Sadrian */ 1784250003Sadrian OS_REG_WRITE(ah, AR_RTC_RC, rst_flags); 1785250003Sadrian 1786250003Sadrian OS_DELAY(50); /* XXX 50 usec */ 1787250003Sadrian 1788250003Sadrian /* 1789250003Sadrian * Clear resets and force wakeup 1790250003Sadrian */ 1791250003Sadrian OS_REG_WRITE(ah, AR_RTC_RC, 0); 1792250008Sadrian if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) { 1793250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1794250003Sadrian "%s: RTC stuck in MAC reset\n", __FUNCTION__); 1795250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1796250003Sadrian "%s: AR_RTC_RC = 0x%x\n", __func__, OS_REG_READ(ah, AR_RTC_RC)); 1797250003Sadrian return AH_FALSE; 1798250003Sadrian } 1799250003Sadrian 1800250003Sadrian /* Clear AHB reset */ 1801250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0); 1802250003Sadrian 1803250003Sadrian ar9300_attach_hw_platform(ah); 1804250003Sadrian 1805250003Sadrian return AH_TRUE; 1806250003Sadrian} 1807250003Sadrian 1808250003Sadrianstatic inline HAL_BOOL 1809250003Sadrianar9300_set_reset_power_on(struct ath_hal *ah) 1810250003Sadrian{ 1811250003Sadrian /* Force wake */ 1812250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); 1813250003Sadrian OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ 1814250003Sadrian OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, 1815250003Sadrian AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); 1816250003Sadrian /* 1817250003Sadrian * RTC reset and clear. Some delay in between is needed 1818250003Sadrian * to give the chip time to settle. 1819250003Sadrian */ 1820250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 0); 1821250003Sadrian OS_DELAY(2); 1822250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 1823250003Sadrian 1824250003Sadrian /* 1825250003Sadrian * Poll till RTC is ON 1826250003Sadrian */ 1827250003Sadrian if (!ath_hal_wait(ah, 1828250003Sadrian AR_RTC_STATUS, AR_RTC_STATUS_M, 1829250008Sadrian AR_RTC_STATUS_ON)) 1830250003Sadrian { 1831250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 1832250008Sadrian "%s: RTC not waking up for %d\n", __FUNCTION__, 1000); 1833250003Sadrian return AH_FALSE; 1834250003Sadrian } 1835250003Sadrian 1836250003Sadrian /* 1837250003Sadrian * Read Revisions from Chip right after RTC is on for the first time. 1838250003Sadrian * This helps us detect the chip type early and initialize it accordingly. 1839250003Sadrian */ 1840250003Sadrian ar9300_read_revisions(ah); 1841250003Sadrian 1842250003Sadrian /* 1843250003Sadrian * Warm reset if we aren't really powering on, 1844250003Sadrian * just restarting the driver. 1845250003Sadrian */ 1846250003Sadrian return ar9300_set_reset(ah, HAL_RESET_WARM); 1847250003Sadrian} 1848250003Sadrian 1849250003Sadrian/* 1850250003Sadrian * Write the given reset bit mask into the reset register 1851250003Sadrian */ 1852250003SadrianHAL_BOOL 1853250003Sadrianar9300_set_reset_reg(struct ath_hal *ah, u_int32_t type) 1854250003Sadrian{ 1855250003Sadrian HAL_BOOL ret = AH_FALSE; 1856250003Sadrian 1857250003Sadrian /* 1858250003Sadrian * Set force wake 1859250003Sadrian */ 1860250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); 1861250003Sadrian OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ 1862250003Sadrian OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, 1863250003Sadrian AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); 1864250003Sadrian 1865250003Sadrian switch (type) { 1866250003Sadrian case HAL_RESET_POWER_ON: 1867250003Sadrian ret = ar9300_set_reset_power_on(ah); 1868250003Sadrian break; 1869250003Sadrian case HAL_RESET_WARM: 1870250003Sadrian case HAL_RESET_COLD: 1871250003Sadrian ret = ar9300_set_reset(ah, type); 1872250003Sadrian break; 1873250003Sadrian default: 1874250003Sadrian break; 1875250003Sadrian } 1876250003Sadrian 1877250003Sadrian#if ATH_SUPPORT_MCI 1878250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { 1879250003Sadrian OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); 1880250003Sadrian } 1881250003Sadrian#endif 1882250003Sadrian 1883250003Sadrian return ret; 1884250003Sadrian} 1885250003Sadrian 1886250003Sadrian/* 1887250003Sadrian * Places the PHY and Radio chips into reset. A full reset 1888250003Sadrian * must be called to leave this state. The PCI/MAC/PCU are 1889250003Sadrian * not placed into reset as we must receive interrupt to 1890250003Sadrian * re-enable the hardware. 1891250003Sadrian */ 1892250003SadrianHAL_BOOL 1893250003Sadrianar9300_phy_disable(struct ath_hal *ah) 1894250003Sadrian{ 1895250003Sadrian if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) { 1896250003Sadrian return AH_FALSE; 1897250003Sadrian } 1898250003Sadrian 1899250003Sadrian#ifdef ATH_SUPPORT_LED 1900250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 1901250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 1902250003Sadrian#define ATH_GPIO_OE 0xB8040000 1903250003Sadrian#define ATH_GPIO_OUT 0xB8040008 /* GPIO Ouput Value reg.*/ 1904250003Sadrian if (AR_SREV_WASP(ah)) { 1905250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 1906250003Sadrian REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13))); 1907250003Sadrian } 1908250003Sadrian else { 1909250003Sadrian REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12))); 1910250003Sadrian } 1911250003Sadrian } 1912250003Sadrian else if (AR_SREV_SCORPION(ah)) { 1913250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 1914250003Sadrian REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13))); 1915250003Sadrian } 1916250003Sadrian else { 1917250003Sadrian REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12))); 1918250003Sadrian } 1919250003Sadrian /* Turn off JMPST led */ 1920250003Sadrian REG_WRITE(ATH_GPIO_OUT, (REG_READ(ATH_GPIO_OUT) | (0x1 << 15))); 1921250003Sadrian } 1922250003Sadrian#undef REG_READ 1923250003Sadrian#undef REG_WRITE 1924250003Sadrian#endif 1925250003Sadrian 1926250003Sadrian if ( AR_SREV_OSPREY(ah) ) { 1927250003Sadrian OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1), 0x0, 0x1f); 1928250003Sadrian } 1929250003Sadrian 1930250003Sadrian 1931250003Sadrian ar9300_init_pll(ah, AH_NULL); 1932250003Sadrian 1933250003Sadrian return AH_TRUE; 1934250003Sadrian} 1935250003Sadrian 1936250003Sadrian/* 1937250003Sadrian * Places all of hardware into reset 1938250003Sadrian */ 1939250003SadrianHAL_BOOL 1940250003Sadrianar9300_disable(struct ath_hal *ah) 1941250003Sadrian{ 1942250003Sadrian if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { 1943250003Sadrian return AH_FALSE; 1944250003Sadrian } 1945250003Sadrian if (!ar9300_set_reset_reg(ah, HAL_RESET_COLD)) { 1946250003Sadrian return AH_FALSE; 1947250003Sadrian } 1948250003Sadrian 1949250003Sadrian ar9300_init_pll(ah, AH_NULL); 1950250003Sadrian 1951250003Sadrian return AH_TRUE; 1952250003Sadrian} 1953250003Sadrian 1954250003Sadrian/* 1955250003Sadrian * TODO: Only write the PLL if we're changing to or from CCK mode 1956250003Sadrian * 1957250003Sadrian * WARNING: The order of the PLL and mode registers must be correct. 1958250003Sadrian */ 1959250003Sadrianstatic inline void 1960250008Sadrianar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan) 1961250003Sadrian{ 1962250003Sadrian u_int32_t rf_mode = 0; 1963250003Sadrian 1964250003Sadrian if (chan == AH_NULL) { 1965250003Sadrian return; 1966250003Sadrian } 1967250003Sadrian switch (AH9300(ah)->ah_hwp) { 1968250003Sadrian case HAL_TRUE_CHIP: 1969250008Sadrian rf_mode |= (IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_G(chan)) ? 1970250003Sadrian AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; 1971250003Sadrian break; 1972250003Sadrian default: 1973250003Sadrian HALASSERT(0); 1974250003Sadrian break; 1975250003Sadrian } 1976250003Sadrian /* Phy mode bits for 5GHz channels requiring Fast Clock */ 1977250003Sadrian if ( IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { 1978250003Sadrian rf_mode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); 1979250003Sadrian } 1980250003Sadrian OS_REG_WRITE(ah, AR_PHY_MODE, rf_mode); 1981250003Sadrian} 1982250003Sadrian 1983250003Sadrian/* 1984250003Sadrian * Places the hardware into reset and then pulls it out of reset 1985250003Sadrian */ 1986250003SadrianHAL_BOOL 1987250008Sadrianar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan) 1988250003Sadrian{ 1989250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1990269748Sadrian int type = HAL_RESET_WARM; 1991250003Sadrian 1992250008Sadrian OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0); 1993250008Sadrian 1994250003Sadrian /* 1995250003Sadrian * Warm reset is optimistic. 1996269748Sadrian * 1997269748Sadrian * If the TX/RX DMA engines aren't shut down (eg, they're 1998269748Sadrian * wedged) then we're better off doing a full cold reset 1999269748Sadrian * to try and shake that condition. 2000250003Sadrian */ 2001269748Sadrian if (ahp->ah_chip_full_sleep || 2002269748Sadrian (ah->ah_config.ah_force_full_reset == 1) || 2003269748Sadrian OS_REG_READ(ah, AR_Q_TXE) || 2004269748Sadrian (OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) { 2005269748Sadrian type = HAL_RESET_COLD; 2006269748Sadrian } 2007269748Sadrian 2008269748Sadrian if (!ar9300_set_reset_reg(ah, type)) { 2009250003Sadrian return AH_FALSE; 2010250003Sadrian } 2011250003Sadrian 2012250003Sadrian /* Bring out of sleep mode (AGAIN) */ 2013250003Sadrian if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { 2014250003Sadrian return AH_FALSE; 2015250003Sadrian } 2016250003Sadrian 2017250003Sadrian ahp->ah_chip_full_sleep = AH_FALSE; 2018250003Sadrian 2019250003Sadrian if (AR_SREV_HORNET(ah)) { 2020250003Sadrian ar9300_internal_regulator_apply(ah); 2021250003Sadrian } 2022250003Sadrian 2023250003Sadrian ar9300_init_pll(ah, chan); 2024250003Sadrian 2025250003Sadrian /* 2026250003Sadrian * Perform warm reset before the mode/PLL/turbo registers 2027250003Sadrian * are changed in order to deactivate the radio. Mode changes 2028250003Sadrian * with an active radio can result in corrupted shifts to the 2029250003Sadrian * radio device. 2030250003Sadrian */ 2031250003Sadrian ar9300_set_rf_mode(ah, chan); 2032250003Sadrian 2033250003Sadrian return AH_TRUE; 2034250003Sadrian} 2035250003Sadrian 2036250003Sadrian/* ar9300_setup_calibration 2037250003Sadrian * Setup HW to collect samples used for current cal 2038250003Sadrian */ 2039250003Sadrianinline static void 2040250003Sadrianar9300_setup_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal) 2041250003Sadrian{ 2042250003Sadrian /* Select calibration to run */ 2043250003Sadrian switch (curr_cal->cal_data->cal_type) { 2044250003Sadrian case IQ_MISMATCH_CAL: 2045250003Sadrian /* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ 2046250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, 2047250003Sadrian AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, 2048250003Sadrian curr_cal->cal_data->cal_count_max); 2049250003Sadrian OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 2050250003Sadrian 2051250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2052250003Sadrian "%s: starting IQ Mismatch Calibration\n", __func__); 2053250003Sadrian 2054250003Sadrian /* Kick-off cal */ 2055250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); 2056250003Sadrian 2057250003Sadrian break; 2058250003Sadrian case TEMP_COMP_CAL: 2059250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || 2060250003Sadrian AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 2061250003Sadrian OS_REG_RMW_FIELD(ah, 2062250003Sadrian AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2063250003Sadrian OS_REG_RMW_FIELD(ah, 2064250003Sadrian AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); 2065250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 2066250003Sadrian OS_REG_RMW_FIELD(ah, 2067250003Sadrian AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2068250003Sadrian OS_REG_RMW_FIELD(ah, 2069250003Sadrian AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_START, 1); 2070250003Sadrian } else { 2071250003Sadrian OS_REG_RMW_FIELD(ah, 2072250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2073250003Sadrian OS_REG_RMW_FIELD(ah, 2074250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); 2075250003Sadrian } 2076250003Sadrian 2077250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2078250003Sadrian "%s: starting Temperature Compensation Calibration\n", __func__); 2079250003Sadrian break; 2080250003Sadrian default: 2081250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 2082250003Sadrian "%s called with incorrect calibration type.\n", __func__); 2083250003Sadrian } 2084250003Sadrian} 2085250003Sadrian 2086250003Sadrian/* ar9300_reset_calibration 2087250003Sadrian * Initialize shared data structures and prepare a cal to be run. 2088250003Sadrian */ 2089250003Sadrianinline static void 2090250003Sadrianar9300_reset_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal) 2091250003Sadrian{ 2092250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2093250003Sadrian int i; 2094250003Sadrian 2095250003Sadrian /* Setup HW for new calibration */ 2096250003Sadrian ar9300_setup_calibration(ah, curr_cal); 2097250003Sadrian 2098250003Sadrian /* Change SW state to RUNNING for this calibration */ 2099250003Sadrian curr_cal->cal_state = CAL_RUNNING; 2100250003Sadrian 2101250003Sadrian /* Reset data structures shared between different calibrations */ 2102250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 2103250003Sadrian ahp->ah_meas0.sign[i] = 0; 2104250003Sadrian ahp->ah_meas1.sign[i] = 0; 2105250003Sadrian ahp->ah_meas2.sign[i] = 0; 2106250003Sadrian ahp->ah_meas3.sign[i] = 0; 2107250003Sadrian } 2108250003Sadrian 2109250003Sadrian ahp->ah_cal_samples = 0; 2110250003Sadrian} 2111250003Sadrian 2112250003Sadrian#ifdef XXX_UNUSED_FUNCTION 2113250003Sadrian/* 2114250003Sadrian * Find out which of the RX chains are enabled 2115250003Sadrian */ 2116250003Sadrianstatic u_int32_t 2117250003Sadrianar9300_get_rx_chain_mask(struct ath_hal *ah) 2118250003Sadrian{ 2119250003Sadrian u_int32_t ret_val = OS_REG_READ(ah, AR_PHY_RX_CHAINMASK); 2120250003Sadrian /* The bits [2:0] indicate the rx chain mask and are to be 2121250003Sadrian * interpreted as follows: 2122250003Sadrian * 00x => Only chain 0 is enabled 2123250003Sadrian * 01x => Chain 1 and 0 enabled 2124250003Sadrian * 1xx => Chain 2,1 and 0 enabled 2125250003Sadrian */ 2126250003Sadrian return (ret_val & 0x7); 2127250003Sadrian} 2128250003Sadrian#endif 2129250003Sadrian 2130250003Sadrianstatic void 2131250003Sadrianar9300_get_nf_hist_base(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, 2132250003Sadrian int is_scan, int16_t nf[]) 2133250003Sadrian{ 2134250003Sadrian HAL_NFCAL_BASE *h_base; 2135250003Sadrian 2136250003Sadrian#ifdef ATH_NF_PER_CHAN 2137250003Sadrian h_base = &chan->nf_cal_hist.base; 2138250003Sadrian#else 2139250003Sadrian if (is_scan) { 2140250003Sadrian /* 2141250003Sadrian * The channel we are currently on is not the home channel, 2142250003Sadrian * so we shouldn't use the home channel NF buffer's values on 2143250003Sadrian * this channel. Instead, use the NF single value already 2144250003Sadrian * read for this channel. (Or, if we haven't read the NF for 2145250003Sadrian * this channel yet, the SW default for this chip/band will 2146250003Sadrian * be used.) 2147250003Sadrian */ 2148250003Sadrian h_base = &chan->nf_cal_hist.base; 2149250003Sadrian } else { 2150250003Sadrian /* use the home channel NF info */ 2151250003Sadrian h_base = &AH_PRIVATE(ah)->nf_cal_hist.base; 2152250003Sadrian } 2153250003Sadrian#endif 2154250003Sadrian OS_MEMCPY(nf, h_base->priv_nf, sizeof(h_base->priv_nf)); 2155250003Sadrian} 2156250003Sadrian 2157250003SadrianHAL_BOOL 2158250003Sadrianar9300_load_nf(struct ath_hal *ah, int16_t nf[]) 2159250003Sadrian{ 2160250003Sadrian int i, j; 2161250003Sadrian int32_t val; 2162250003Sadrian /* XXX where are EXT regs defined */ 2163250003Sadrian const u_int32_t ar9300_cca_regs[] = { 2164250003Sadrian AR_PHY_CCA_0, 2165250003Sadrian AR_PHY_CCA_1, 2166250003Sadrian AR_PHY_CCA_2, 2167250003Sadrian AR_PHY_EXT_CCA, 2168250003Sadrian AR_PHY_EXT_CCA_1, 2169250003Sadrian AR_PHY_EXT_CCA_2, 2170250003Sadrian }; 2171250003Sadrian u_int8_t chainmask; 2172250003Sadrian 2173250003Sadrian /* 2174250003Sadrian * Force NF calibration for all chains, otherwise Vista station 2175250003Sadrian * would conduct a bad performance 2176250003Sadrian */ 2177250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 2178250003Sadrian chainmask = 0x9; 2179250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { 2180250003Sadrian chainmask = 0x1b; 2181250003Sadrian } else { 2182250003Sadrian chainmask = 0x3F; 2183250003Sadrian } 2184250003Sadrian 2185250003Sadrian /* 2186250003Sadrian * Write filtered NF values into max_cca_pwr register parameter 2187250003Sadrian * so we can load below. 2188250003Sadrian */ 2189250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 2190250003Sadrian if (chainmask & (1 << i)) { 2191250003Sadrian val = OS_REG_READ(ah, ar9300_cca_regs[i]); 2192250003Sadrian val &= 0xFFFFFE00; 2193250003Sadrian val |= (((u_int32_t)(nf[i]) << 1) & 0x1ff); 2194250003Sadrian OS_REG_WRITE(ah, ar9300_cca_regs[i], val); 2195250003Sadrian } 2196250003Sadrian } 2197250003Sadrian 2198250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s: load %d %d %d %d %d %d\n", 2199250008Sadrian __func__, 2200250008Sadrian nf[0], nf[1], nf[2], 2201250008Sadrian nf[3], nf[4], nf[5]); 2202250008Sadrian 2203250003Sadrian /* 2204250003Sadrian * Load software filtered NF value into baseband internal min_cca_pwr 2205250003Sadrian * variable. 2206250003Sadrian */ 2207250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); 2208250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 2209250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 2210250003Sadrian 2211250003Sadrian /* Wait for load to complete, should be fast, a few 10s of us. */ 2212250003Sadrian /* Changed the max delay 250us back to 10000us, since 250us often 2213250003Sadrian * results in NF load timeout and causes deaf condition 2214250003Sadrian * during stress testing 12/12/2009 2215250003Sadrian */ 2216250003Sadrian for (j = 0; j < 10000; j++) { 2217250003Sadrian if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){ 2218250003Sadrian break; 2219250003Sadrian } 2220250003Sadrian OS_DELAY(10); 2221250003Sadrian } 2222250003Sadrian if (j == 10000) { 2223250003Sadrian /* 2224250003Sadrian * We timed out waiting for the noisefloor to load, probably 2225250003Sadrian * due to an in-progress rx. Simply return here and allow 2226250003Sadrian * the load plenty of time to complete before the next 2227250003Sadrian * calibration interval. We need to avoid trying to load -50 2228250003Sadrian * (which happens below) while the previous load is still in 2229250003Sadrian * progress as this can cause rx deafness (see EV 66368,62830). 2230250003Sadrian * Instead by returning here, the baseband nf cal will 2231250003Sadrian * just be capped by our present noisefloor until the next 2232250003Sadrian * calibration timer. 2233250003Sadrian */ 2234250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 2235250003Sadrian "%s: *** TIMEOUT while waiting for nf to load: " 2236250003Sadrian "AR_PHY_AGC_CONTROL=0x%x ***\n", 2237250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); 2238250003Sadrian return AH_FALSE; 2239250003Sadrian } 2240250003Sadrian 2241250003Sadrian /* 2242250003Sadrian * Restore max_cca_power register parameter again so that we're not capped 2243250003Sadrian * by the median we just loaded. This will be initial (and max) value 2244250003Sadrian * of next noise floor calibration the baseband does. 2245250003Sadrian */ 2246250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 2247250003Sadrian if (chainmask & (1 << i)) { 2248250003Sadrian val = OS_REG_READ(ah, ar9300_cca_regs[i]); 2249250003Sadrian val &= 0xFFFFFE00; 2250250003Sadrian val |= (((u_int32_t)(-50) << 1) & 0x1ff); 2251250003Sadrian OS_REG_WRITE(ah, ar9300_cca_regs[i], val); 2252250003Sadrian } 2253250003Sadrian } 2254250003Sadrian return AH_TRUE; 2255250003Sadrian} 2256250003Sadrian 2257250003Sadrian/* ar9300_per_calibration 2258250003Sadrian * Generic calibration routine. 2259250003Sadrian * Recalibrate the lower PHY chips to account for temperature/environment 2260250003Sadrian * changes. 2261250003Sadrian */ 2262250003Sadrianinline static void 2263250003Sadrianar9300_per_calibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, 2264250003Sadrian u_int8_t rxchainmask, HAL_CAL_LIST *curr_cal, HAL_BOOL *is_cal_done) 2265250003Sadrian{ 2266250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2267250003Sadrian 2268250003Sadrian /* Cal is assumed not done until explicitly set below */ 2269250003Sadrian *is_cal_done = AH_FALSE; 2270250003Sadrian 2271250003Sadrian /* Calibration in progress. */ 2272250003Sadrian if (curr_cal->cal_state == CAL_RUNNING) { 2273250003Sadrian /* Check to see if it has finished. */ 2274250003Sadrian if (!(OS_REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { 2275250003Sadrian int i, num_chains = 0; 2276250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 2277250003Sadrian if (rxchainmask & (1 << i)) { 2278250003Sadrian num_chains++; 2279250003Sadrian } 2280250003Sadrian } 2281250003Sadrian 2282250003Sadrian /* 2283250003Sadrian * Accumulate cal measures for active chains 2284250003Sadrian */ 2285250003Sadrian curr_cal->cal_data->cal_collect(ah, num_chains); 2286250003Sadrian 2287250003Sadrian ahp->ah_cal_samples++; 2288250003Sadrian 2289250003Sadrian if (ahp->ah_cal_samples >= curr_cal->cal_data->cal_num_samples) { 2290250003Sadrian /* 2291250003Sadrian * Process accumulated data 2292250003Sadrian */ 2293250003Sadrian curr_cal->cal_data->cal_post_proc(ah, num_chains); 2294250003Sadrian 2295250003Sadrian /* Calibration has finished. */ 2296250008Sadrian ichan->calValid |= curr_cal->cal_data->cal_type; 2297250003Sadrian curr_cal->cal_state = CAL_DONE; 2298250003Sadrian *is_cal_done = AH_TRUE; 2299250003Sadrian } else { 2300250003Sadrian /* Set-up collection of another sub-sample until we 2301250003Sadrian * get desired number 2302250003Sadrian */ 2303250003Sadrian ar9300_setup_calibration(ah, curr_cal); 2304250003Sadrian } 2305250003Sadrian } 2306250008Sadrian } else if (!(ichan->calValid & curr_cal->cal_data->cal_type)) { 2307250003Sadrian /* If current cal is marked invalid in channel, kick it off */ 2308250003Sadrian ar9300_reset_calibration(ah, curr_cal); 2309250003Sadrian } 2310250003Sadrian} 2311250003Sadrian 2312250003Sadrianstatic void 2313250003Sadrianar9300_start_nf_cal(struct ath_hal *ah) 2314250003Sadrian{ 2315250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); 2316250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 2317250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 2318250003Sadrian AH9300(ah)->nf_tsf32 = ar9300_get_tsf32(ah); 2319250003Sadrian} 2320250003Sadrian 2321250003Sadrian/* ar9300_calibration 2322250003Sadrian * Wrapper for a more generic Calibration routine. Primarily to abstract to 2323250003Sadrian * upper layers whether there is 1 or more calibrations to be run. 2324250003Sadrian */ 2325250003SadrianHAL_BOOL 2326250008Sadrianar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask, 2327250003Sadrian HAL_BOOL do_nf_cal, HAL_BOOL *is_cal_done, int is_scan, 2328250003Sadrian u_int32_t *sched_cals) 2329250003Sadrian{ 2330250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2331250003Sadrian HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr; 2332250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2333250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 2334250003Sadrian 2335250003Sadrian *is_cal_done = AH_TRUE; 2336250003Sadrian 2337250003Sadrian 2338250003Sadrian /* XXX: For initial wasp bringup - disable periodic calibration */ 2339250003Sadrian /* Invalid channel check */ 2340250003Sadrian if (ichan == AH_NULL) { 2341250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 2342250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 2343250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 2344250003Sadrian return AH_FALSE; 2345250003Sadrian } 2346250003Sadrian 2347250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2348250003Sadrian "%s: Entering, Doing NF Cal = %d\n", __func__, do_nf_cal); 2349250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 0 Rx IQ Cal Correction 0x%08x\n", 2350250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 2351250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) { 2352250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2353250003Sadrian "%s: Chain 1 Rx IQ Cal Correction 0x%08x\n", 2354250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B1)); 2355250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 2356250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2357250003Sadrian "%s: Chain 2 Rx IQ Cal Correction 0x%08x\n", 2358250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B2)); 2359250003Sadrian } 2360250003Sadrian } 2361250003Sadrian 2362250008Sadrian OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq); 2363250003Sadrian 2364250003Sadrian /* For given calibration: 2365250003Sadrian * 1. Call generic cal routine 2366250003Sadrian * 2. When this cal is done (is_cal_done) if we have more cals waiting 2367250003Sadrian * (eg after reset), mask this to upper layers by not propagating 2368250003Sadrian * is_cal_done if it is set to TRUE. 2369250003Sadrian * Instead, change is_cal_done to FALSE and setup the waiting cal(s) 2370250003Sadrian * to be run. 2371250003Sadrian */ 2372250003Sadrian if (curr_cal && (curr_cal->cal_data->cal_type & *sched_cals) && 2373250003Sadrian (curr_cal->cal_state == CAL_RUNNING || 2374250003Sadrian curr_cal->cal_state == CAL_WAITING)) 2375250003Sadrian { 2376250003Sadrian ar9300_per_calibration(ah, ichan, rxchainmask, curr_cal, is_cal_done); 2377250003Sadrian 2378250003Sadrian if (*is_cal_done == AH_TRUE) { 2379250003Sadrian ahp->ah_cal_list_curr = curr_cal = curr_cal->cal_next; 2380250003Sadrian 2381250003Sadrian if (curr_cal && curr_cal->cal_state == CAL_WAITING) { 2382250003Sadrian *is_cal_done = AH_FALSE; 2383250003Sadrian ar9300_reset_calibration(ah, curr_cal); 2384250003Sadrian } else { 2385250003Sadrian *sched_cals &= ~IQ_MISMATCH_CAL; 2386250003Sadrian } 2387250003Sadrian } 2388250003Sadrian } 2389250003Sadrian 2390250003Sadrian /* Do NF cal only at longer intervals */ 2391250003Sadrian if (do_nf_cal) { 2392250003Sadrian int nf_done; 2393250003Sadrian 2394250003Sadrian /* Get the value from the previous NF cal and update history buffer */ 2395250008Sadrian nf_done = ar9300_store_new_nf(ah, chan, is_scan); 2396250008Sadrian#if 0 2397250003Sadrian if (ichan->channel_flags & CHANNEL_CW_INT) { 2398250003Sadrian chan->channel_flags |= CHANNEL_CW_INT; 2399250003Sadrian } 2400250008Sadrian#endif 2401250008Sadrian chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; 2402250003Sadrian 2403250003Sadrian if (nf_done) { 2404250003Sadrian /* 2405250003Sadrian * Load the NF from history buffer of the current channel. 2406250003Sadrian * NF is slow time-variant, so it is OK to use a historical value. 2407250003Sadrian */ 2408250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 2409250003Sadrian ar9300_load_nf(ah, nf_buf); 2410250003Sadrian 2411250003Sadrian /* start NF calibration, without updating BB NF register*/ 2412250003Sadrian ar9300_start_nf_cal(ah); 2413250003Sadrian } 2414250003Sadrian } 2415250003Sadrian return AH_TRUE; 2416250003Sadrian} 2417250003Sadrian 2418250003Sadrian/* ar9300_iq_cal_collect 2419250003Sadrian * Collect data from HW to later perform IQ Mismatch Calibration 2420250003Sadrian */ 2421250003Sadrianvoid 2422250003Sadrianar9300_iq_cal_collect(struct ath_hal *ah, u_int8_t num_chains) 2423250003Sadrian{ 2424250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2425250003Sadrian int i; 2426250003Sadrian 2427250003Sadrian /* 2428250003Sadrian * Accumulate IQ cal measures for active chains 2429250003Sadrian */ 2430250003Sadrian for (i = 0; i < num_chains; i++) { 2431250003Sadrian ahp->ah_total_power_meas_i[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 2432250003Sadrian ahp->ah_total_power_meas_q[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 2433250003Sadrian ahp->ah_total_iq_corr_meas[i] = 2434250003Sadrian (int32_t) OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 2435250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2436250003Sadrian "%d: Chn %d " 2437250003Sadrian "Reg Offset(0x%04x)pmi=0x%08x; " 2438250003Sadrian "Reg Offset(0x%04x)pmq=0x%08x; " 2439250003Sadrian "Reg Offset (0x%04x)iqcm=0x%08x;\n", 2440250003Sadrian ahp->ah_cal_samples, 2441250003Sadrian i, 2442250003Sadrian (unsigned) AR_PHY_CAL_MEAS_0(i), 2443250003Sadrian ahp->ah_total_power_meas_i[i], 2444250003Sadrian (unsigned) AR_PHY_CAL_MEAS_1(i), 2445250003Sadrian ahp->ah_total_power_meas_q[i], 2446250003Sadrian (unsigned) AR_PHY_CAL_MEAS_2(i), 2447250003Sadrian ahp->ah_total_iq_corr_meas[i]); 2448250003Sadrian } 2449250003Sadrian} 2450250003Sadrian 2451250003Sadrian/* ar9300_iq_calibration 2452250003Sadrian * Use HW data to perform IQ Mismatch Calibration 2453250003Sadrian */ 2454250003Sadrianvoid 2455250003Sadrianar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains) 2456250003Sadrian{ 2457250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2458250003Sadrian u_int32_t power_meas_q, power_meas_i, iq_corr_meas; 2459250003Sadrian u_int32_t q_coff_denom, i_coff_denom; 2460250003Sadrian int32_t q_coff, i_coff; 2461250003Sadrian int iq_corr_neg, i; 2462250003Sadrian static const u_int32_t offset_array[3] = { 2463250003Sadrian AR_PHY_RX_IQCAL_CORR_B0, 2464250003Sadrian AR_PHY_RX_IQCAL_CORR_B1, 2465250003Sadrian AR_PHY_RX_IQCAL_CORR_B2, 2466250003Sadrian }; 2467250003Sadrian 2468250003Sadrian for (i = 0; i < num_chains; i++) { 2469250003Sadrian power_meas_i = ahp->ah_total_power_meas_i[i]; 2470250003Sadrian power_meas_q = ahp->ah_total_power_meas_q[i]; 2471250003Sadrian iq_corr_meas = ahp->ah_total_iq_corr_meas[i]; 2472250003Sadrian 2473250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2474250003Sadrian "Starting IQ Cal and Correction for Chain %d\n", i); 2475250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2476250003Sadrian "Orignal: Chn %diq_corr_meas = 0x%08x\n", 2477250003Sadrian i, ahp->ah_total_iq_corr_meas[i]); 2478250003Sadrian 2479250003Sadrian iq_corr_neg = 0; 2480250003Sadrian 2481250003Sadrian /* iq_corr_meas is always negative. */ 2482250003Sadrian if (iq_corr_meas > 0x80000000) { 2483250003Sadrian iq_corr_meas = (0xffffffff - iq_corr_meas) + 1; 2484250003Sadrian iq_corr_neg = 1; 2485250003Sadrian } 2486250003Sadrian 2487250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2488250003Sadrian "Chn %d pwr_meas_i = 0x%08x\n", i, power_meas_i); 2489250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2490250003Sadrian "Chn %d pwr_meas_q = 0x%08x\n", i, power_meas_q); 2491250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2492250003Sadrian "iq_corr_neg is 0x%08x\n", iq_corr_neg); 2493250003Sadrian 2494250003Sadrian i_coff_denom = (power_meas_i / 2 + power_meas_q / 2) / 256; 2495250003Sadrian q_coff_denom = power_meas_q / 64; 2496250003Sadrian 2497250003Sadrian /* Protect against divide-by-0 */ 2498250003Sadrian if ((i_coff_denom != 0) && (q_coff_denom != 0)) { 2499250003Sadrian /* IQ corr_meas is already negated if iqcorr_neg == 1 */ 2500250003Sadrian i_coff = iq_corr_meas / i_coff_denom; 2501250003Sadrian q_coff = power_meas_i / q_coff_denom - 64; 2502250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2503250003Sadrian "Chn %d i_coff = 0x%08x\n", i, i_coff); 2504250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2505250003Sadrian "Chn %d q_coff = 0x%08x\n", i, q_coff); 2506250003Sadrian 2507250003Sadrian /* Force bounds on i_coff */ 2508250003Sadrian if (i_coff >= 63) { 2509250003Sadrian i_coff = 63; 2510250003Sadrian } else if (i_coff <= -63) { 2511250003Sadrian i_coff = -63; 2512250003Sadrian } 2513250003Sadrian 2514250003Sadrian /* Negate i_coff if iq_corr_neg == 0 */ 2515250003Sadrian if (iq_corr_neg == 0x0) { 2516250003Sadrian i_coff = -i_coff; 2517250003Sadrian } 2518250003Sadrian 2519250003Sadrian /* Force bounds on q_coff */ 2520250003Sadrian if (q_coff >= 63) { 2521250003Sadrian q_coff = 63; 2522250003Sadrian } else if (q_coff <= -63) { 2523250003Sadrian q_coff = -63; 2524250003Sadrian } 2525250003Sadrian 2526250003Sadrian i_coff = i_coff & 0x7f; 2527250003Sadrian q_coff = q_coff & 0x7f; 2528250003Sadrian 2529250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2530250003Sadrian "Chn %d : i_coff = 0x%x q_coff = 0x%x\n", i, i_coff, q_coff); 2531250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2532250003Sadrian "Register offset (0x%04x) before update = 0x%x\n", 2533250003Sadrian offset_array[i], OS_REG_READ(ah, offset_array[i])); 2534250003Sadrian 2535250003Sadrian OS_REG_RMW_FIELD(ah, offset_array[i], 2536250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff); 2537250003Sadrian OS_REG_RMW_FIELD(ah, offset_array[i], 2538250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff); 2539250003Sadrian 2540250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2541250003Sadrian "Register offset (0x%04x) QI COFF (bitfields 0x%08x) " 2542250003Sadrian "after update = 0x%x\n", 2543250003Sadrian offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 2544250003Sadrian OS_REG_READ(ah, offset_array[i])); 2545250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2546250003Sadrian "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) " 2547250003Sadrian "after update = 0x%x\n", 2548250003Sadrian offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 2549250003Sadrian OS_REG_READ(ah, offset_array[i])); 2550250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2551250003Sadrian "IQ Cal and Correction done for Chain %d\n", i); 2552250003Sadrian } 2553250003Sadrian } 2554250003Sadrian 2555250003Sadrian OS_REG_SET_BIT(ah, 2556250003Sadrian AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); 2557250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2558250003Sadrian "IQ Cal and Correction (offset 0x%04x) enabled " 2559250003Sadrian "(bit position 0x%08x). New Value 0x%08x\n", 2560250003Sadrian (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), 2561250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, 2562250003Sadrian OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 2563250003Sadrian} 2564250003Sadrian 2565250003Sadrian/* 2566250003Sadrian * Set a limit on the overall output power. Used for dynamic 2567250003Sadrian * transmit power control and the like. 2568250003Sadrian * 2569250003Sadrian * NB: limit is in units of 0.5 dbM. 2570250003Sadrian */ 2571250003SadrianHAL_BOOL 2572250003Sadrianar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit, 2573250003Sadrian u_int16_t extra_txpow, u_int16_t tpc_in_db) 2574250003Sadrian{ 2575250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2576250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 2577250008Sadrian const struct ieee80211_channel *chan = ahpriv->ah_curchan; 2578250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2579250003Sadrian 2580250003Sadrian if (NULL == chan) { 2581250008Sadrian return AH_FALSE; 2582250008Sadrian } 2583250003Sadrian 2584250008Sadrian ahpriv->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); 2585250008Sadrian ahpriv->ah_extraTxPow = extra_txpow; 2586250008Sadrian 2587250003Sadrian if(chan == NULL) { 2588250003Sadrian return AH_FALSE; 2589250003Sadrian } 2590250008Sadrian if (ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan, 2591250003Sadrian ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), 2592250003Sadrian ath_hal_get_twice_max_regpower(ahpriv, ichan, chan), 2593250008Sadrian AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)) != HAL_OK) 2594250003Sadrian { 2595250003Sadrian return AH_FALSE; 2596250003Sadrian } 2597250003Sadrian return AH_TRUE; 2598250003Sadrian} 2599250003Sadrian 2600250003Sadrian/* 2601250003Sadrian * Exported call to check for a recent gain reading and return 2602250003Sadrian * the current state of the thermal calibration gain engine. 2603250003Sadrian */ 2604250003SadrianHAL_RFGAIN 2605250003Sadrianar9300_get_rfgain(struct ath_hal *ah) 2606250003Sadrian{ 2607250003Sadrian return HAL_RFGAIN_INACTIVE; 2608250003Sadrian} 2609250003Sadrian 2610250003Sadrian#define HAL_GREEN_AP_RX_MASK 0x1 2611250003Sadrian 2612250003Sadrianstatic inline void 2613250003Sadrianar9300_init_chain_masks(struct ath_hal *ah, int rx_chainmask, int tx_chainmask) 2614250003Sadrian{ 2615250008Sadrian if (AH9300(ah)->green_ap_ps_on) { 2616250003Sadrian rx_chainmask = HAL_GREEN_AP_RX_MASK; 2617250003Sadrian } 2618250003Sadrian if (rx_chainmask == 0x5) { 2619250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); 2620250003Sadrian } 2621250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 2622250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 2623250003Sadrian 2624250003Sadrian /* 2625250003Sadrian * Adaptive Power Management: 2626250003Sadrian * Some 3 stream chips exceed the PCIe power requirements. 2627250003Sadrian * This workaround will reduce power consumption by using 2 tx chains 2628250003Sadrian * for 1 and 2 stream rates (5 GHz only). 2629250003Sadrian * 2630250003Sadrian * Set the self gen mask to 2 tx chains when APM is enabled. 2631250003Sadrian * 2632250003Sadrian */ 2633250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halApmEnable && (tx_chainmask == 0x7)) { 2634250003Sadrian OS_REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); 2635250003Sadrian } 2636250003Sadrian else { 2637250003Sadrian OS_REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); 2638250003Sadrian } 2639250003Sadrian 2640250003Sadrian if (tx_chainmask == 0x5) { 2641250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); 2642250003Sadrian } 2643250003Sadrian} 2644250003Sadrian 2645250003Sadrian/* 2646250003Sadrian * Override INI values with chip specific configuration. 2647250003Sadrian */ 2648250003Sadrianstatic inline void 2649250008Sadrianar9300_override_ini(struct ath_hal *ah, struct ieee80211_channel *chan) 2650250003Sadrian{ 2651250003Sadrian u_int32_t val; 2652250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 2653250003Sadrian 2654250003Sadrian /* 2655250003Sadrian * Set the RX_ABORT and RX_DIS and clear it only after 2656250003Sadrian * RXE is set for MAC. This prevents frames with 2657250003Sadrian * corrupted descriptor status. 2658250003Sadrian */ 2659250003Sadrian OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); 2660250003Sadrian /* 2661250003Sadrian * For Merlin and above, there is a new feature that allows Multicast 2662250003Sadrian * search based on both MAC Address and Key ID. 2663250003Sadrian * By default, this feature is enabled. 2664250003Sadrian * But since the driver is not using this feature, we switch it off; 2665250003Sadrian * otherwise multicast search based on MAC addr only will fail. 2666250003Sadrian */ 2667250003Sadrian val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE); 2668250003Sadrian OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, 2669250003Sadrian val | AR_BUG_58603_FIX_ENABLE | AR_AGG_WEP_ENABLE); 2670250003Sadrian 2671250003Sadrian 2672250003Sadrian /* Osprey revision specific configuration */ 2673250003Sadrian 2674250003Sadrian /* Osprey 2.0+ - if SW RAC support is disabled, must also disable 2675250003Sadrian * the Osprey 2.0 hardware RAC fix. 2676250003Sadrian */ 2677250008Sadrian if (p_cap->halIsrRacSupport == AH_FALSE) { 2678250003Sadrian OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_MISSING_TX_INTR_FIX_ENABLE); 2679250003Sadrian } 2680250003Sadrian 2681250003Sadrian /* try to enable old pal if it is needed for h/w green tx */ 2682250003Sadrian ar9300_hwgreentx_set_pal_spare(ah, 1); 2683250003Sadrian} 2684250003Sadrian 2685250003Sadrianstatic inline void 2686250003Sadrianar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, 2687250003Sadrian int column) 2688250003Sadrian{ 2689250003Sadrian int i, reg_writes = 0; 2690250003Sadrian 2691250003Sadrian /* New INI format: Array may be undefined (pre, core, post arrays) */ 2692250003Sadrian if (ini_arr->ia_array == NULL) { 2693250003Sadrian return; 2694250003Sadrian } 2695250003Sadrian 2696250003Sadrian /* 2697250003Sadrian * New INI format: Pre, core, and post arrays for a given subsystem may be 2698250003Sadrian * modal (> 2 columns) or non-modal (2 columns). 2699250003Sadrian * Determine if the array is non-modal and force the column to 1. 2700250003Sadrian */ 2701250003Sadrian if (column >= ini_arr->ia_columns) { 2702250003Sadrian column = 1; 2703250003Sadrian } 2704250003Sadrian 2705250003Sadrian for (i = 0; i < ini_arr->ia_rows; i++) { 2706250003Sadrian u_int32_t reg = INI_RA(ini_arr, i, 0); 2707250003Sadrian u_int32_t val = INI_RA(ini_arr, i, column); 2708250003Sadrian 2709250003Sadrian /* 2710250003Sadrian ** Determine if this is a shift register value 2711250003Sadrian ** (reg >= 0x16000 && reg < 0x17000 for Osprey) , 2712250003Sadrian ** and insert the configured delay if so. 2713250003Sadrian ** -this delay is not required for Osprey (EV#71410) 2714250003Sadrian */ 2715250003Sadrian OS_REG_WRITE(ah, reg, val); 2716250003Sadrian WAR_6773(reg_writes); 2717250003Sadrian 2718250003Sadrian } 2719250003Sadrian} 2720250003Sadrian 2721250003Sadrianstatic inline HAL_STATUS 2722250008Sadrianar9300_process_ini(struct ath_hal *ah, struct ieee80211_channel *chan, 2723250003Sadrian HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode) 2724250003Sadrian{ 2725250003Sadrian int reg_writes = 0; 2726250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2727250003Sadrian u_int modes_index, modes_txgaintable_index = 0; 2728250003Sadrian int i; 2729250003Sadrian HAL_STATUS status; 2730250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 2731250003Sadrian /* Setup the indices for the next set of register array writes */ 2732250003Sadrian /* TODO: 2733250003Sadrian * If the channel marker is indicative of the current mode rather 2734250003Sadrian * than capability, we do not need to check the phy mode below. 2735250003Sadrian */ 2736250008Sadrian#if 0 2737250003Sadrian switch (chan->channel_flags & CHANNEL_ALL) { 2738250003Sadrian case CHANNEL_A: 2739250003Sadrian case CHANNEL_A_HT20: 2740250003Sadrian if (AR_SREV_SCORPION(ah)){ 2741250003Sadrian if (chan->channel <= 5350){ 2742250003Sadrian modes_txgaintable_index = 1; 2743250003Sadrian }else if ((chan->channel > 5350) && (chan->channel <= 5600)){ 2744250003Sadrian modes_txgaintable_index = 3; 2745250003Sadrian }else if (chan->channel > 5600){ 2746250003Sadrian modes_txgaintable_index = 5; 2747250003Sadrian } 2748250003Sadrian } 2749250003Sadrian modes_index = 1; 2750250003Sadrian break; 2751250003Sadrian 2752250003Sadrian case CHANNEL_A_HT40PLUS: 2753250003Sadrian case CHANNEL_A_HT40MINUS: 2754250003Sadrian if (AR_SREV_SCORPION(ah)){ 2755250003Sadrian if (chan->channel <= 5350){ 2756250003Sadrian modes_txgaintable_index = 2; 2757250003Sadrian }else if ((chan->channel > 5350) && (chan->channel <= 5600)){ 2758250003Sadrian modes_txgaintable_index = 4; 2759250003Sadrian }else if (chan->channel > 5600){ 2760250003Sadrian modes_txgaintable_index = 6; 2761250003Sadrian } 2762250003Sadrian } 2763250003Sadrian modes_index = 2; 2764250003Sadrian break; 2765250003Sadrian 2766250003Sadrian case CHANNEL_PUREG: 2767250003Sadrian case CHANNEL_G_HT20: 2768250003Sadrian case CHANNEL_B: 2769250003Sadrian if (AR_SREV_SCORPION(ah)){ 2770250003Sadrian modes_txgaintable_index = 8; 2771250003Sadrian } 2772250003Sadrian modes_index = 4; 2773250003Sadrian break; 2774250003Sadrian 2775250003Sadrian case CHANNEL_G_HT40PLUS: 2776250003Sadrian case CHANNEL_G_HT40MINUS: 2777250003Sadrian if (AR_SREV_SCORPION(ah)){ 2778250003Sadrian modes_txgaintable_index = 7; 2779250003Sadrian } 2780250003Sadrian modes_index = 3; 2781250003Sadrian break; 2782250003Sadrian 2783250003Sadrian case CHANNEL_108G: 2784250003Sadrian modes_index = 5; 2785250003Sadrian break; 2786250003Sadrian 2787250003Sadrian default: 2788250003Sadrian HALASSERT(0); 2789250003Sadrian return HAL_EINVAL; 2790250003Sadrian } 2791250008Sadrian#endif 2792250003Sadrian 2793250008Sadrian /* FreeBSD */ 2794250008Sadrian if (IS_CHAN_5GHZ(ichan)) { 2795250008Sadrian if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) { 2796250008Sadrian if (AR_SREV_SCORPION(ah)){ 2797250008Sadrian if (ichan->channel <= 5350){ 2798250008Sadrian modes_txgaintable_index = 2; 2799250008Sadrian }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){ 2800250008Sadrian modes_txgaintable_index = 4; 2801250008Sadrian }else if (ichan->channel > 5600){ 2802250008Sadrian modes_txgaintable_index = 6; 2803250008Sadrian } 2804250008Sadrian } 2805250008Sadrian modes_index = 2; 2806250008Sadrian } else if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_HT20(chan)) { 2807250008Sadrian if (AR_SREV_SCORPION(ah)){ 2808250008Sadrian if (ichan->channel <= 5350){ 2809250008Sadrian modes_txgaintable_index = 1; 2810250008Sadrian }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){ 2811250008Sadrian modes_txgaintable_index = 3; 2812250008Sadrian }else if (ichan->channel > 5600){ 2813250008Sadrian modes_txgaintable_index = 5; 2814250008Sadrian } 2815250008Sadrian } 2816250008Sadrian modes_index = 1; 2817250008Sadrian } else 2818250008Sadrian return HAL_EINVAL; 2819250008Sadrian } else if (IS_CHAN_2GHZ(ichan)) { 2820250008Sadrian if (IEEE80211_IS_CHAN_108G(chan)) { 2821250008Sadrian modes_index = 5; 2822250008Sadrian } else if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) { 2823250008Sadrian if (AR_SREV_SCORPION(ah)){ 2824250008Sadrian modes_txgaintable_index = 7; 2825250008Sadrian } 2826250008Sadrian modes_index = 3; 2827250008Sadrian } else if (IEEE80211_IS_CHAN_HT20(chan) || IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_PUREG(chan)) { 2828250008Sadrian if (AR_SREV_SCORPION(ah)){ 2829250008Sadrian modes_txgaintable_index = 8; 2830250008Sadrian } 2831250008Sadrian modes_index = 4; 2832250008Sadrian } else 2833250008Sadrian return HAL_EINVAL; 2834250008Sadrian } else 2835250008Sadrian return HAL_EINVAL; 2836250008Sadrian 2837250003Sadrian#if 0 2838250003Sadrian /* Set correct Baseband to analog shift setting to access analog chips. */ 2839250003Sadrian OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); 2840250003Sadrian#endif 2841250003Sadrian 2842250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2843250003Sadrian "ar9300_process_ini: " 2844250003Sadrian "Skipping OS-REG-WRITE(ah, AR-PHY(0), 0x00000007)\n"); 2845250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2846250003Sadrian "ar9300_process_ini: no ADDac programming\n"); 2847250003Sadrian 2848250003Sadrian 2849250003Sadrian /* 2850250003Sadrian * Osprey 2.0+ - new INI format. 2851250003Sadrian * Each subsystem has a pre, core, and post array. 2852250003Sadrian */ 2853250003Sadrian for (i = 0; i < ATH_INI_NUM_SPLIT; i++) { 2854250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_soc[i], modes_index); 2855250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_mac[i], modes_index); 2856250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_bb[i], modes_index); 2857250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_radio[i], modes_index); 2858250003Sadrian if ((i == ATH_INI_POST) && (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah))) { 2859250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_radio_post_sys2ant, modes_index); 2860250003Sadrian } 2861250003Sadrian 2862250003Sadrian } 2863250003Sadrian 2864250003Sadrian if (!(AR_SREV_SOC(ah))) { 2865250003Sadrian /* Doubler issue : Some board doesn't work well with MCS15. Turn off doubler after freq locking is complete*/ 2866250003Sadrian //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)); 2867250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2868250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2869250003Sadrian //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)); 2870250003Sadrian 2871250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2872250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2873250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2874250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2875250003Sadrian OS_DELAY(200); 2876250003Sadrian 2877250003Sadrian //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)); 2878250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 2879250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 2880250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 2881250003Sadrian //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)); 2882250003Sadrian 2883250003Sadrian OS_DELAY(1); 2884250003Sadrian 2885250003Sadrian //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)); 2886250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2887250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2888250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2889250003Sadrian //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)); 2890250003Sadrian 2891250003Sadrian OS_DELAY(200); 2892250003Sadrian 2893250003Sadrian //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)); 2894250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf); 2895250003Sadrian //OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_SYNTH12, 1<< 16); /* clr charge pump */ 2896250003Sadrian //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)); 2897250003Sadrian 2898250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2899250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 2900250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2901250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 2902250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2903250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 2904250003Sadrian //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)); 2905250003Sadrian } 2906250003Sadrian 2907250003Sadrian /* Write rxgain Array Parameters */ 2908250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain, 1, reg_writes); 2909250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain programming\n"); 2910250003Sadrian 2911250003Sadrian if (AR_SREV_SCORPION(ah)) { 2912250003Sadrian /* Write rxgain bounds Array */ 2913250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, modes_index, reg_writes); 2914250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain table bounds programming\n"); 2915250003Sadrian } 2916250003Sadrian /* UB124 xLNA settings */ 2917250003Sadrian if (AR_SREV_WASP(ah) && ar9300_rx_gain_index_get(ah) == 2) { 2918250003Sadrian#define REG_WRITE(_reg,_val) *((volatile u_int32_t *)(_reg)) = (_val); 2919250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 2920250003Sadrian u_int32_t val; 2921250003Sadrian /* B8040000: bit[0]=0, bit[3]=0; */ 2922250003Sadrian val = REG_READ(0xB8040000); 2923250003Sadrian val &= 0xfffffff6; 2924250003Sadrian REG_WRITE(0xB8040000, val); 2925250003Sadrian /* B804002c: bit[31:24]=0x2e; bit[7:0]=0x2f; */ 2926250003Sadrian val = REG_READ(0xB804002c); 2927250003Sadrian val &= 0x00ffff00; 2928250003Sadrian val |= 0x2e00002f; 2929250003Sadrian REG_WRITE(0xB804002c, val); 2930250003Sadrian /* B804006c: bit[1]=1; */ 2931250003Sadrian val = REG_READ(0xB804006c); 2932250003Sadrian val |= 0x2; 2933250003Sadrian REG_WRITE(0xB804006c, val); 2934250003Sadrian#undef REG_READ 2935250003Sadrian#undef REG_WRITE 2936250003Sadrian } 2937250003Sadrian 2938250003Sadrian 2939250003Sadrian /* Write txgain Array Parameters */ 2940250003Sadrian if (AR_SREV_SCORPION(ah)) { 2941250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_txgaintable_index, 2942250003Sadrian reg_writes); 2943250003Sadrian }else{ 2944250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_index, reg_writes); 2945250003Sadrian } 2946250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Tx Gain programming\n"); 2947250003Sadrian 2948250003Sadrian 2949250003Sadrian /* For 5GHz channels requiring Fast Clock, apply different modal values */ 2950250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { 2951250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2952250003Sadrian "%s: Fast clock enabled, use special ini values\n", __func__); 2953250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_additional, modes_index, reg_writes); 2954250003Sadrian } 2955250003Sadrian 2956250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 2957250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2958250003Sadrian "%s: use xtal ini for AH9300(ah)->clk_25mhz: %d\n", 2959250003Sadrian __func__, AH9300(ah)->clk_25mhz); 2960250003Sadrian REG_WRITE_ARRAY( 2961250003Sadrian &ahp->ah_ini_modes_additional, 1/*modes_index*/, reg_writes); 2962250003Sadrian } 2963250003Sadrian 2964250003Sadrian if (AR_SREV_WASP(ah) && (AH9300(ah)->clk_25mhz == 0)) { 2965250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Apply 40MHz ini settings\n", __func__); 2966250003Sadrian REG_WRITE_ARRAY( 2967250003Sadrian &ahp->ah_ini_modes_additional_40mhz, 1/*modesIndex*/, reg_writes); 2968250003Sadrian } 2969250003Sadrian 2970250008Sadrian /* Handle Japan Channel 14 channel spreading */ 2971250008Sadrian if (2484 == ichan->channel) { 2972250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_japan2484, 1); 2973250003Sadrian } 2974250003Sadrian 2975250003Sadrian#if 0 2976250003Sadrian if (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah)) { 2977250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_BTCOEX_MAX_TXPWR, 1); 2978250003Sadrian } 2979250003Sadrian#endif 2980250003Sadrian 2981250003Sadrian /* Override INI with chip specific configuration */ 2982250003Sadrian ar9300_override_ini(ah, chan); 2983250003Sadrian 2984250003Sadrian /* Setup 11n MAC/Phy mode registers */ 2985250003Sadrian ar9300_set_11n_regs(ah, chan, macmode); 2986250003Sadrian 2987250003Sadrian /* 2988250003Sadrian * Moved ar9300_init_chain_masks() here to ensure the swap bit is set before 2989250003Sadrian * the pdadc table is written. Swap must occur before any radio dependent 2990250003Sadrian * replicated register access. The pdadc curve addressing in particular 2991250003Sadrian * depends on the consistent setting of the swap bit. 2992250003Sadrian */ 2993250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask); 2994250003Sadrian 2995250003Sadrian /* 2996250003Sadrian * Setup the transmit power values. 2997250003Sadrian * 2998250003Sadrian * After the public to private hal channel mapping, ichan contains the 2999250003Sadrian * valid regulatory power value. 3000250003Sadrian * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan. 3001250003Sadrian */ 3002250008Sadrian status = ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan, 3003250003Sadrian ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), 3004250003Sadrian ath_hal_get_twice_max_regpower(ahpriv, ichan, chan), 3005250008Sadrian AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)); 3006250003Sadrian if (status != HAL_OK) { 3007250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 3008250003Sadrian "%s: error init'ing transmit power\n", __func__); 3009250003Sadrian return HAL_EIO; 3010250003Sadrian } 3011250003Sadrian 3012250003Sadrian 3013250003Sadrian return HAL_OK; 3014250003Sadrian#undef N 3015250003Sadrian} 3016250003Sadrian 3017250003Sadrian/* ar9300_is_cal_supp 3018250003Sadrian * Determine if calibration is supported by device and channel flags 3019250003Sadrian */ 3020250003Sadrianinline static HAL_BOOL 3021250008Sadrianar9300_is_cal_supp(struct ath_hal *ah, const struct ieee80211_channel *chan, 3022250003Sadrian HAL_CAL_TYPES cal_type) 3023250003Sadrian{ 3024250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3025250003Sadrian HAL_BOOL retval = AH_FALSE; 3026250003Sadrian 3027250003Sadrian switch (cal_type & ahp->ah_supp_cals) { 3028250003Sadrian case IQ_MISMATCH_CAL: 3029250003Sadrian /* Run IQ Mismatch for non-CCK only */ 3030250008Sadrian if (!IEEE80211_IS_CHAN_B(chan)) { 3031250003Sadrian retval = AH_TRUE; 3032250003Sadrian } 3033250003Sadrian break; 3034250003Sadrian case TEMP_COMP_CAL: 3035250003Sadrian retval = AH_TRUE; 3036250003Sadrian break; 3037250003Sadrian } 3038250003Sadrian 3039250003Sadrian return retval; 3040250003Sadrian} 3041250003Sadrian 3042250003Sadrian 3043250003Sadrian#if 0 3044250003Sadrian/* ar9285_pa_cal 3045250003Sadrian * PA Calibration for Kite 1.1 and later versions of Kite. 3046250003Sadrian * - from system's team. 3047250003Sadrian */ 3048250003Sadrianstatic inline void 3049250003Sadrianar9285_pa_cal(struct ath_hal *ah) 3050250003Sadrian{ 3051250003Sadrian u_int32_t reg_val; 3052250003Sadrian int i, lo_gn, offs_6_1, offs_0; 3053250003Sadrian u_int8_t reflo; 3054250003Sadrian u_int32_t phy_test2_reg_val, phy_adc_ctl_reg_val; 3055250003Sadrian u_int32_t an_top2_reg_val, phy_tst_dac_reg_val; 3056250003Sadrian 3057250003Sadrian 3058250003Sadrian /* Kite 1.1 WAR for Bug 35666 3059250003Sadrian * Increase the LDO value to 1.28V before accessing analog Reg */ 3060250003Sadrian if (AR_SREV_KITE_11(ah)) { 3061250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14) ); 3062250003Sadrian } 3063250003Sadrian an_top2_reg_val = OS_REG_READ(ah, AR9285_AN_TOP2); 3064250003Sadrian 3065250003Sadrian /* set pdv2i pdrxtxbb */ 3066250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1); 3067250003Sadrian reg_val |= ((0x1 << 5) | (0x1 << 7)); 3068250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val); 3069250003Sadrian 3070250003Sadrian /* clear pwddb */ 3071250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G7); 3072250003Sadrian reg_val &= 0xfffffffd; 3073250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G7, reg_val); 3074250003Sadrian 3075250003Sadrian /* clear enpacal */ 3076250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3077250003Sadrian reg_val &= 0xfffff7ff; 3078250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3079250003Sadrian 3080250003Sadrian /* set offcal */ 3081250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2); 3082250003Sadrian reg_val |= (0x1 << 12); 3083250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val); 3084250003Sadrian 3085250003Sadrian /* set pdpadrv1=pdpadrv2=pdpaout=1 */ 3086250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3087250003Sadrian reg_val |= (0x7 << 23); 3088250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3089250003Sadrian 3090250003Sadrian /* Read back reflo, increase it by 1 and write it. */ 3091250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3092250003Sadrian reflo = ((reg_val >> 26) & 0x7); 3093250003Sadrian 3094250003Sadrian if (reflo < 0x7) { 3095250003Sadrian reflo++; 3096250003Sadrian } 3097250003Sadrian reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26)); 3098250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3099250003Sadrian 3100250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3101250003Sadrian reflo = ((reg_val >> 26) & 0x7); 3102250003Sadrian 3103250003Sadrian /* use TX single carrier to transmit 3104250003Sadrian * dac const 3105250003Sadrian * reg. 15 3106250003Sadrian */ 3107250003Sadrian phy_tst_dac_reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST); 3108250003Sadrian OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, ((0x7ff << 11) | 0x7ff)); 3109250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST); 3110250003Sadrian 3111250003Sadrian /* source is dac const 3112250003Sadrian * reg. 2 3113250003Sadrian */ 3114250003Sadrian phy_test2_reg_val = OS_REG_READ(ah, AR_PHY_TEST2); 3115250003Sadrian OS_REG_WRITE(ah, AR_PHY_TEST2, ((0x1 << 7) | (0x1 << 1))); 3116250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_TEST2); 3117250003Sadrian 3118250003Sadrian /* set dac on 3119250003Sadrian * reg. 11 3120250003Sadrian */ 3121250003Sadrian phy_adc_ctl_reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL); 3122250003Sadrian OS_REG_WRITE(ah, AR_PHY_ADC_CTL, 0x80008000); 3123250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL); 3124250003Sadrian 3125250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP2, (0x1 << 27) | (0x1 << 17) | (0x1 << 16) | 3126250003Sadrian (0x1 << 14) | (0x1 << 12) | (0x1 << 11) | 3127250003Sadrian (0x1 << 7) | (0x1 << 5)); 3128250003Sadrian 3129250003Sadrian OS_DELAY(10); /* 10 usec */ 3130250003Sadrian 3131250003Sadrian /* clear off[6:0] */ 3132250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3133250003Sadrian reg_val &= 0xfc0fffff; 3134250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3135250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3136250003Sadrian reg_val &= 0xfdffffff; 3137250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3138250003Sadrian 3139250003Sadrian offs_6_1 = 0; 3140250003Sadrian for (i = 6; i > 0; i--) { 3141250003Sadrian /* sef off[$k]==1 */ 3142250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3143250003Sadrian reg_val &= 0xfc0fffff; 3144250003Sadrian reg_val = reg_val | (0x1 << (19 + i)) | ((offs_6_1) << 20); 3145250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3146250003Sadrian lo_gn = (OS_REG_READ(ah, AR9285_AN_RF2G9)) & 0x1; 3147250003Sadrian offs_6_1 = offs_6_1 | (lo_gn << (i - 1)); 3148250003Sadrian } 3149250003Sadrian 3150250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3151250003Sadrian reg_val &= 0xfc0fffff; 3152250003Sadrian reg_val = reg_val | ((offs_6_1 - 1) << 20); 3153250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3154250003Sadrian 3155250003Sadrian /* set off_0=1; */ 3156250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3157250003Sadrian reg_val &= 0xfdffffff; 3158250003Sadrian reg_val = reg_val | (0x1 << 25); 3159250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3160250003Sadrian 3161250003Sadrian lo_gn = OS_REG_READ(ah, AR9285_AN_RF2G9) & 0x1; 3162250003Sadrian offs_0 = lo_gn; 3163250003Sadrian 3164250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3165250003Sadrian reg_val &= 0xfdffffff; 3166250003Sadrian reg_val = reg_val | (offs_0 << 25); 3167250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3168250003Sadrian 3169250003Sadrian /* clear pdv2i */ 3170250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1); 3171250003Sadrian reg_val &= 0xffffff5f; 3172250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val); 3173250003Sadrian 3174250003Sadrian /* set enpacal */ 3175250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3176250003Sadrian reg_val |= (0x1 << 11); 3177250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3178250003Sadrian 3179250003Sadrian /* clear offcal */ 3180250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2); 3181250003Sadrian reg_val &= 0xffffefff; 3182250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val); 3183250003Sadrian 3184250003Sadrian /* set pdpadrv1=pdpadrv2=pdpaout=0 */ 3185250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3186250003Sadrian reg_val &= 0xfc7fffff; 3187250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3188250003Sadrian 3189250003Sadrian /* Read back reflo, decrease it by 1 and write it. */ 3190250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3191250003Sadrian reflo = (reg_val >> 26) & 0x7; 3192250003Sadrian if (reflo) { 3193250003Sadrian reflo--; 3194250003Sadrian } 3195250003Sadrian reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26)); 3196250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3197250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3198250003Sadrian reflo = (reg_val >> 26) & 0x7; 3199250003Sadrian 3200250003Sadrian /* write back registers */ 3201250003Sadrian OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, phy_tst_dac_reg_val); 3202250003Sadrian OS_REG_WRITE(ah, AR_PHY_TEST2, phy_test2_reg_val); 3203250003Sadrian OS_REG_WRITE(ah, AR_PHY_ADC_CTL, phy_adc_ctl_reg_val); 3204250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP2, an_top2_reg_val); 3205250003Sadrian 3206250003Sadrian /* Kite 1.1 WAR for Bug 35666 3207250003Sadrian * Decrease the LDO value back to 1.20V */ 3208250003Sadrian if (AR_SREV_KITE_11(ah)) { 3209250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); 3210250003Sadrian } 3211250003Sadrian} 3212250003Sadrian#endif 3213250003Sadrian 3214250003Sadrian/* ar9300_run_init_cals 3215250003Sadrian * Runs non-periodic calibrations 3216250003Sadrian */ 3217250003Sadrianinline static HAL_BOOL 3218250003Sadrianar9300_run_init_cals(struct ath_hal *ah, int init_cal_count) 3219250003Sadrian{ 3220250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3221250003Sadrian HAL_CHANNEL_INTERNAL ichan; /* bogus */ 3222250003Sadrian HAL_BOOL is_cal_done; 3223250003Sadrian HAL_CAL_LIST *curr_cal; 3224250008Sadrian const HAL_PERCAL_DATA *cal_data; 3225250003Sadrian int i; 3226250003Sadrian 3227250003Sadrian curr_cal = ahp->ah_cal_list_curr; 3228250003Sadrian if (curr_cal == AH_NULL) { 3229250003Sadrian return AH_FALSE; 3230250003Sadrian } 3231250008Sadrian cal_data = curr_cal->cal_data; 3232250008Sadrian ichan.calValid = 0; 3233250003Sadrian 3234250003Sadrian for (i = 0; i < init_cal_count; i++) { 3235250003Sadrian /* Reset this Cal */ 3236250003Sadrian ar9300_reset_calibration(ah, curr_cal); 3237250003Sadrian /* Poll for offset calibration complete */ 3238250003Sadrian if (!ath_hal_wait( 3239250008Sadrian ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL, 0)) 3240250003Sadrian { 3241250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3242250003Sadrian "%s: Cal %d failed to complete in 100ms.\n", 3243250003Sadrian __func__, curr_cal->cal_data->cal_type); 3244250003Sadrian /* Re-initialize list pointers for periodic cals */ 3245250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr 3246250003Sadrian = AH_NULL; 3247250003Sadrian return AH_FALSE; 3248250003Sadrian } 3249250003Sadrian /* Run this cal */ 3250250003Sadrian ar9300_per_calibration( 3251250003Sadrian ah, &ichan, ahp->ah_rx_chainmask, curr_cal, &is_cal_done); 3252250003Sadrian if (is_cal_done == AH_FALSE) { 3253250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3254250003Sadrian "%s: Not able to run Init Cal %d.\n", __func__, 3255250003Sadrian curr_cal->cal_data->cal_type); 3256250003Sadrian } 3257250003Sadrian if (curr_cal->cal_next) { 3258250003Sadrian curr_cal = curr_cal->cal_next; 3259250003Sadrian } 3260250003Sadrian } 3261250003Sadrian 3262250003Sadrian /* Re-initialize list pointers for periodic cals */ 3263250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; 3264250003Sadrian return AH_TRUE; 3265250003Sadrian} 3266250003Sadrian 3267250003Sadrian#if 0 3268250003Sadrianstatic void 3269250003Sadrianar9300_tx_carrier_leak_war(struct ath_hal *ah) 3270250003Sadrian{ 3271250003Sadrian unsigned long tx_gain_table_max; 3272250003Sadrian unsigned long reg_bb_cl_map_0_b0 = 0xffffffff; 3273250003Sadrian unsigned long reg_bb_cl_map_1_b0 = 0xffffffff; 3274250003Sadrian unsigned long reg_bb_cl_map_2_b0 = 0xffffffff; 3275250003Sadrian unsigned long reg_bb_cl_map_3_b0 = 0xffffffff; 3276250003Sadrian unsigned long tx_gain, cal_run = 0; 3277250003Sadrian unsigned long cal_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3278250003Sadrian unsigned long cal_gain_index[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3279250003Sadrian unsigned long new_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3280250003Sadrian int i, j; 3281250003Sadrian 3282250003Sadrian OS_MEMSET(new_gain, 0, sizeof(new_gain)); 3283250003Sadrian /*printf(" Running TxCarrierLeakWAR\n");*/ 3284250003Sadrian 3285250003Sadrian /* process tx gain table, we use cl_map_hw_gen=0. */ 3286250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_MAP_HW_GEN, 0); 3287250003Sadrian 3288250003Sadrian //the table we used is txbb_gc[2:0], 1dB[2:1]. 3289250003Sadrian tx_gain_table_max = OS_REG_READ_FIELD(ah, 3290250003Sadrian AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX); 3291250003Sadrian 3292250003Sadrian for (i = 0; i <= tx_gain_table_max; i++) { 3293250003Sadrian tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4); 3294250003Sadrian cal_gain[i] = (((tx_gain >> 5)& 0x7) << 2) | 3295250003Sadrian (((tx_gain >> 1) & 0x3) << 0); 3296250003Sadrian if (i == 0) { 3297250003Sadrian cal_gain_index[i] = cal_run; 3298250003Sadrian new_gain[i] = 1; 3299250003Sadrian cal_run++; 3300250003Sadrian } else { 3301250003Sadrian new_gain[i] = 1; 3302250003Sadrian for (j = 0; j < i; j++) { 3303250003Sadrian /* 3304250003Sadrian printf("i=%d, j=%d cal_gain[$i]=0x%04x\n", i, j, cal_gain[i]); 3305250003Sadrian */ 3306250003Sadrian if (new_gain[i]) { 3307250003Sadrian if ((cal_gain[i] != cal_gain[j])) { 3308250003Sadrian new_gain[i] = 1; 3309250003Sadrian } else { 3310250003Sadrian /* if old gain found, use old cal_run value. */ 3311250003Sadrian new_gain[i] = 0; 3312250003Sadrian cal_gain_index[i] = cal_gain_index[j]; 3313250003Sadrian } 3314250003Sadrian } 3315250003Sadrian } 3316250003Sadrian /* if new gain found, increase cal_run */ 3317250003Sadrian if (new_gain[i] == 1) { 3318250003Sadrian cal_gain_index[i] = cal_run; 3319250003Sadrian cal_run++; 3320250003Sadrian } 3321250003Sadrian } 3322250003Sadrian 3323250003Sadrian reg_bb_cl_map_0_b0 = (reg_bb_cl_map_0_b0 & ~(0x1 << i)) | 3324250003Sadrian ((cal_gain_index[i] >> 0 & 0x1) << i); 3325250003Sadrian reg_bb_cl_map_1_b0 = (reg_bb_cl_map_1_b0 & ~(0x1 << i)) | 3326250003Sadrian ((cal_gain_index[i] >> 1 & 0x1) << i); 3327250003Sadrian reg_bb_cl_map_2_b0 = (reg_bb_cl_map_2_b0 & ~(0x1 << i)) | 3328250003Sadrian ((cal_gain_index[i] >> 2 & 0x1) << i); 3329250003Sadrian reg_bb_cl_map_3_b0 = (reg_bb_cl_map_3_b0 & ~(0x1 << i)) | 3330250003Sadrian ((cal_gain_index[i] >> 3 & 0x1) << i); 3331250003Sadrian 3332250003Sadrian /* 3333250003Sadrian printf("i=%2d, cal_gain[$i]= 0x%04x, cal_run= %d, " 3334250003Sadrian "cal_gain_index[i]=%d, new_gain[i] = %d\n", 3335250003Sadrian i, cal_gain[i], cal_run, cal_gain_index[i], new_gain[i]); 3336250003Sadrian */ 3337250003Sadrian } 3338250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B0, reg_bb_cl_map_0_b0); 3339250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B0, reg_bb_cl_map_1_b0); 3340250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B0, reg_bb_cl_map_2_b0); 3341250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B0, reg_bb_cl_map_3_b0); 3342250003Sadrian if (AR_SREV_WASP(ah)) { 3343250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B1, reg_bb_cl_map_0_b0); 3344250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B1, reg_bb_cl_map_1_b0); 3345250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B1, reg_bb_cl_map_2_b0); 3346250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B1, reg_bb_cl_map_3_b0); 3347250003Sadrian } 3348250003Sadrian} 3349250003Sadrian#endif 3350250003Sadrian 3351250003Sadrian 3352250003Sadrianstatic inline void 3353250003Sadrianar9300_invalidate_saved_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 3354250003Sadrian{ 3355250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3356250003Sadrian if (AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse & 3357250003Sadrian ATH_CAL_REUSE_REDO_IN_FULL_RESET) 3358250003Sadrian { 3359250003Sadrian ichan->one_time_txiqcal_done = AH_FALSE; 3360250003Sadrian ichan->one_time_txclcal_done = AH_FALSE; 3361250003Sadrian } 3362250003Sadrian#endif 3363250003Sadrian} 3364250003Sadrian 3365250003Sadrianstatic inline HAL_BOOL 3366250003Sadrianar9300_restore_rtt_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 3367250003Sadrian{ 3368250003Sadrian HAL_BOOL restore_status = AH_FALSE; 3369250003Sadrian 3370250003Sadrian return restore_status; 3371250003Sadrian} 3372250003Sadrian 3373250003Sadrian/* ar9300_init_cal 3374250003Sadrian * Initialize Calibration infrastructure 3375250003Sadrian */ 3376250003Sadrianstatic inline HAL_BOOL 3377250008Sadrianar9300_init_cal_internal(struct ath_hal *ah, struct ieee80211_channel *chan, 3378250008Sadrian HAL_CHANNEL_INTERNAL *ichan, 3379250008Sadrian HAL_BOOL enable_rtt, HAL_BOOL do_rtt_cal, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr) 3380250003Sadrian{ 3381250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3382250003Sadrian HAL_BOOL txiqcal_success_flag = AH_FALSE; 3383250003Sadrian HAL_BOOL cal_done = AH_FALSE; 3384250003Sadrian int iqcal_idx = 0; 3385250003Sadrian HAL_BOOL do_sep_iq_cal = AH_FALSE; 3386250003Sadrian HAL_BOOL do_agc_cal = do_rtt_cal; 3387250003Sadrian HAL_BOOL is_cal_reusable = AH_TRUE; 3388250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3389250003Sadrian HAL_BOOL cal_reuse_enable = AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse & 3390250003Sadrian ATH_CAL_REUSE_ENABLE; 3391250003Sadrian HAL_BOOL clc_success = AH_FALSE; 3392250003Sadrian int32_t ch_idx, j, cl_tab_reg; 3393250003Sadrian u_int32_t BB_cl_tab_entry = MAX_BB_CL_TABLE_ENTRY; 3394250003Sadrian u_int32_t BB_cl_tab_b[AR9300_MAX_CHAINS] = { 3395250003Sadrian AR_PHY_CL_TAB_0, 3396250003Sadrian AR_PHY_CL_TAB_1, 3397250003Sadrian AR_PHY_CL_TAB_2 3398250003Sadrian }; 3399250003Sadrian#endif 3400250003Sadrian 3401250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 3402250003Sadrian /* Hornet: 1 x 1 */ 3403250003Sadrian ahp->ah_rx_cal_chainmask = 0x1; 3404250003Sadrian ahp->ah_tx_cal_chainmask = 0x1; 3405250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { 3406250003Sadrian /* Wasp/Jupiter: 2 x 2 */ 3407250003Sadrian ahp->ah_rx_cal_chainmask = 0x3; 3408250003Sadrian ahp->ah_tx_cal_chainmask = 0x3; 3409250003Sadrian } else { 3410250003Sadrian /* 3411250003Sadrian * Osprey needs to be configured for the correct chain mode 3412250003Sadrian * before running AGC/TxIQ cals. 3413250003Sadrian */ 3414250003Sadrian if (ahp->ah_enterprise_mode & AR_ENT_OTP_CHAIN2_DISABLE) { 3415250003Sadrian /* chain 2 disabled - 2 chain mode */ 3416250003Sadrian ahp->ah_rx_cal_chainmask = 0x3; 3417250003Sadrian ahp->ah_tx_cal_chainmask = 0x3; 3418250003Sadrian } else { 3419250003Sadrian ahp->ah_rx_cal_chainmask = 0x7; 3420250003Sadrian ahp->ah_tx_cal_chainmask = 0x7; 3421250003Sadrian } 3422250003Sadrian } 3423250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_cal_chainmask, ahp->ah_tx_cal_chainmask); 3424250003Sadrian 3425250003Sadrian 3426250003Sadrian if (ahp->tx_cl_cal_enable) { 3427250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3428250003Sadrian /* disable Carrie Leak or set do_agc_cal accordingly */ 3429250003Sadrian if (cal_reuse_enable && ichan->one_time_txclcal_done) 3430250003Sadrian { 3431250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 3432250003Sadrian } else 3433250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3434250003Sadrian { 3435250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 3436250003Sadrian do_agc_cal = AH_TRUE; 3437250003Sadrian } 3438250003Sadrian } 3439250003Sadrian 3440250003Sadrian /* Do Tx IQ Calibration here for osprey hornet and wasp */ 3441250003Sadrian /* XXX: For initial wasp bringup - check and enable this */ 3442250003Sadrian /* EV 74233: Tx IQ fails to complete for half/quarter rates */ 3443250008Sadrian if (!(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { 3444250003Sadrian if (ahp->tx_iq_cal_enable) { 3445250003Sadrian /* this should be eventually moved to INI file */ 3446250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah), 3447250003Sadrian AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); 3448250003Sadrian 3449250003Sadrian /* 3450250003Sadrian * For poseidon and later chips, 3451250003Sadrian * Tx IQ cal HW run will be a part of AGC calibration 3452250003Sadrian */ 3453250003Sadrian if (ahp->tx_iq_cal_during_agc_cal) { 3454250003Sadrian /* 3455250003Sadrian * txiqcal_success_flag always set to 1 to run 3456250003Sadrian * ar9300_tx_iq_cal_post_proc 3457250003Sadrian * if following AGC cal passes 3458250003Sadrian */ 3459250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3460250003Sadrian if (!cal_reuse_enable || !ichan->one_time_txiqcal_done) 3461250003Sadrian { 3462250003Sadrian txiqcal_success_flag = AH_TRUE; 3463250003Sadrian OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3464250003Sadrian OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) | 3465250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 3466250003Sadrian } else { 3467250003Sadrian OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3468250003Sadrian OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) & 3469250003Sadrian (~AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)); 3470250003Sadrian } 3471250003Sadrian#else 3472250003Sadrian if (OS_REG_READ_FIELD(ah, 3473250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0(ah), 3474250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)){ 3475250003Sadrian if (apply_last_iqcorr == AH_TRUE) { 3476250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3477250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 3478250003Sadrian txiqcal_success_flag = AH_FALSE; 3479250003Sadrian } else { 3480250003Sadrian txiqcal_success_flag = AH_TRUE; 3481250003Sadrian } 3482250003Sadrian }else{ 3483250003Sadrian txiqcal_success_flag = AH_FALSE; 3484250003Sadrian } 3485250003Sadrian#endif 3486250003Sadrian if (txiqcal_success_flag) { 3487250003Sadrian do_agc_cal = AH_TRUE; 3488250003Sadrian } 3489250003Sadrian } else 3490250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3491250003Sadrian if (!cal_reuse_enable || !ichan->one_time_txiqcal_done) 3492250003Sadrian#endif 3493250003Sadrian { 3494250003Sadrian do_sep_iq_cal = AH_TRUE; 3495250003Sadrian do_agc_cal = AH_TRUE; 3496250003Sadrian } 3497250003Sadrian } 3498250003Sadrian } 3499250003Sadrian 3500250003Sadrian#if ATH_SUPPORT_MCI 3501250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 3502250003Sadrian IS_CHAN_2GHZ(ichan) && 3503250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 3504250003Sadrian do_agc_cal && 3505250008Sadrian !(ah->ah_config.ath_hal_mci_config & 3506250003Sadrian ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 3507250003Sadrian { 3508250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 3509250003Sadrian 3510250003Sadrian /* Send CAL_REQ only when BT is AWAKE. */ 3511250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_REQ 0x%X\n", 3512250003Sadrian __func__, ahp->ah_mci_wlan_cal_seq); 3513250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_REQ); 3514250003Sadrian payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_seq++; 3515250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 3516250003Sadrian 3517250003Sadrian /* Wait BT_CAL_GRANT for 50ms */ 3518250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3519250003Sadrian "(MCI) %s: Wait for BT_CAL_GRANT\n", __func__); 3520250003Sadrian if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) 3521250003Sadrian { 3522250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3523250003Sadrian "(MCI) %s: Got BT_CAL_GRANT.\n", __func__); 3524250003Sadrian } 3525250003Sadrian else { 3526250003Sadrian is_cal_reusable = AH_FALSE; 3527250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3528250003Sadrian "(MCI) %s: BT is not responding.\n", __func__); 3529250003Sadrian } 3530250003Sadrian } 3531250003Sadrian#endif /* ATH_SUPPORT_MCI */ 3532250003Sadrian 3533250003Sadrian if (do_sep_iq_cal) 3534250003Sadrian { 3535250003Sadrian /* enable Tx IQ Calibration HW for osprey/hornet/wasp */ 3536250003Sadrian txiqcal_success_flag = ar9300_tx_iq_cal_hw_run(ah); 3537250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); 3538250003Sadrian OS_DELAY(5); 3539250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 3540250003Sadrian } 3541250003Sadrian#if 0 3542250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 3543250003Sadrian ar9300_tx_carrier_leak_war(ah); 3544250003Sadrian } 3545250003Sadrian#endif 3546250003Sadrian /* 3547250003Sadrian * Calibrate the AGC 3548250003Sadrian * 3549250003Sadrian * Tx IQ cal is a part of AGC cal for Jupiter/Poseidon, etc. 3550250003Sadrian * please enable the bit of txiqcal_control_0[31] in INI file 3551250003Sadrian * for Jupiter/Poseidon/etc. 3552250003Sadrian */ 3553250003Sadrian if(!AR_SREV_SCORPION(ah)) { 3554250003Sadrian if (do_agc_cal || !skip_if_none) { 3555250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3556250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3557250003Sadrian 3558250003Sadrian /* Poll for offset calibration complete */ 3559250003Sadrian cal_done = ath_hal_wait(ah, 3560250008Sadrian AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0); 3561250003Sadrian if (!cal_done) { 3562250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3563250003Sadrian "(FCS) CAL NOT DONE!!! - %d\n", ichan->channel); 3564250003Sadrian } 3565250003Sadrian } else { 3566250003Sadrian cal_done = AH_TRUE; 3567250003Sadrian } 3568250003Sadrian /* 3569250003Sadrian * Tx IQ cal post-processing in SW 3570250003Sadrian * This part of code should be common to all chips, 3571250003Sadrian * no chip specific code for Jupiter/Posdeion except for register names. 3572250003Sadrian */ 3573250003Sadrian if (txiqcal_success_flag) { 3574251098Sadrian ar9300_tx_iq_cal_post_proc(ah,ichan, 1, 1,is_cal_reusable, AH_FALSE); 3575250003Sadrian } 3576250003Sadrian } else { 3577250003Sadrian if (!txiqcal_success_flag) { 3578250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3579250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3580250008Sadrian if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 3581250008Sadrian 0)) { 3582250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3583250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3584250003Sadrian "noisy environment?\n", __func__); 3585250003Sadrian return AH_FALSE; 3586250003Sadrian } 3587250003Sadrian if (apply_last_iqcorr == AH_TRUE) { 3588250003Sadrian ar9300_tx_iq_cal_post_proc(ah, ichan, 0, 0, is_cal_reusable, AH_TRUE); 3589250003Sadrian } 3590250003Sadrian } else { 3591250003Sadrian for (iqcal_idx=0;iqcal_idx<MAXIQCAL;iqcal_idx++) { 3592250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3593250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3594250003Sadrian 3595250003Sadrian /* Poll for offset calibration complete */ 3596250003Sadrian if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, 3597250008Sadrian AR_PHY_AGC_CONTROL_CAL, 0)) { 3598250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3599250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3600250003Sadrian "noisy environment?\n", __func__); 3601250003Sadrian return AH_FALSE; 3602250003Sadrian } 3603250003Sadrian /* 3604250003Sadrian * Tx IQ cal post-processing in SW 3605250003Sadrian * This part of code should be common to all chips, 3606250003Sadrian * no chip specific code for Jupiter/Posdeion except for register names. 3607250003Sadrian */ 3608250003Sadrian ar9300_tx_iq_cal_post_proc(ah, ichan, iqcal_idx+1, MAXIQCAL, is_cal_reusable, AH_FALSE); 3609250003Sadrian } 3610250003Sadrian } 3611250003Sadrian } 3612250003Sadrian 3613250003Sadrian 3614250003Sadrian#if ATH_SUPPORT_MCI 3615250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 3616250003Sadrian IS_CHAN_2GHZ(ichan) && 3617250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 3618250003Sadrian do_agc_cal && 3619250008Sadrian !(ah->ah_config.ath_hal_mci_config & 3620250003Sadrian ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 3621250003Sadrian { 3622250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 3623250003Sadrian 3624250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_DONE 0x%X\n", 3625250003Sadrian __func__, ahp->ah_mci_wlan_cal_done); 3626250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); 3627250003Sadrian payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_done++; 3628250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 3629250003Sadrian } 3630250003Sadrian#endif /* ATH_SUPPORT_MCI */ 3631250003Sadrian 3632250003Sadrian 3633250003Sadrian if (!cal_done && !AR_SREV_SCORPION(ah) ) 3634250003Sadrian { 3635250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3636250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3637250003Sadrian "noisy environment?\n", __func__); 3638250003Sadrian return AH_FALSE; 3639250003Sadrian } 3640250003Sadrian 3641250003Sadrian#if 0 3642250003Sadrian /* Beacon stuck fix, refer to EV 120056 */ 3643250003Sadrian if(IS_CHAN_2GHZ(chan) && AR_SREV_SCORPION(ah)) 3644250003Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING5, OS_REG_READ(ah,AR_PHY_TIMING5) & ~AR_PHY_TIMING5_CYCPWR_THR1_ENABLE); 3645250003Sadrian#endif 3646250003Sadrian 3647250003Sadrian#if 0 3648250003Sadrian /* Do PA Calibration */ 3649250003Sadrian if (AR_SREV_KITE(ah) && AR_SREV_KITE_11_OR_LATER(ah)) { 3650250003Sadrian ar9285_pa_cal(ah); 3651250003Sadrian } 3652250003Sadrian#endif 3653250003Sadrian 3654250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3655250003Sadrian if (ichan->one_time_txiqcal_done) { 3656250003Sadrian ar9300_tx_iq_cal_apply(ah, ichan); 3657250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3658250003Sadrian "(FCS) TXIQCAL applied - %d\n", ichan->channel); 3659250003Sadrian } 3660250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3661250003Sadrian 3662250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3663250003Sadrian if (cal_reuse_enable && ahp->tx_cl_cal_enable) 3664250003Sadrian { 3665250003Sadrian clc_success = (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & 3666250003Sadrian AR_PHY_AGC_CONTROL_CLC_SUCCESS) ? 1 : 0; 3667250003Sadrian 3668250003Sadrian if (ichan->one_time_txclcal_done) 3669250003Sadrian { 3670250003Sadrian /* reapply CL cal results */ 3671250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 3672250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 3673250003Sadrian continue; 3674250003Sadrian } 3675250003Sadrian cl_tab_reg = BB_cl_tab_b[ch_idx]; 3676250003Sadrian for (j = 0; j < BB_cl_tab_entry; j++) { 3677250003Sadrian OS_REG_WRITE(ah, cl_tab_reg, ichan->tx_clcal[ch_idx][j]); 3678250003Sadrian cl_tab_reg += 4;; 3679250003Sadrian } 3680250003Sadrian } 3681250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3682250003Sadrian "(FCS) TX CL CAL applied - %d\n", ichan->channel); 3683250003Sadrian } 3684250003Sadrian else if (is_cal_reusable && clc_success) { 3685250003Sadrian /* save CL cal results */ 3686250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 3687250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 3688250003Sadrian continue; 3689250003Sadrian } 3690250003Sadrian cl_tab_reg = BB_cl_tab_b[ch_idx]; 3691250003Sadrian for (j = 0; j < BB_cl_tab_entry; j++) { 3692250003Sadrian ichan->tx_clcal[ch_idx][j] = OS_REG_READ(ah, cl_tab_reg); 3693250003Sadrian cl_tab_reg += 4; 3694250003Sadrian } 3695250003Sadrian } 3696250003Sadrian ichan->one_time_txclcal_done = AH_TRUE; 3697250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3698250003Sadrian "(FCS) TX CL CAL saved - %d\n", ichan->channel); 3699250003Sadrian } 3700250003Sadrian } 3701250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3702250003Sadrian 3703250003Sadrian /* Revert chainmasks to their original values before NF cal */ 3704250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask); 3705250003Sadrian 3706250003Sadrian#if !FIX_NOISE_FLOOR 3707250003Sadrian /* 3708250003Sadrian * Do NF calibration after DC offset and other CALs. 3709250003Sadrian * Per system engineers, noise floor value can sometimes be 20 dB 3710250003Sadrian * higher than normal value if DC offset and noise floor cal are 3711250003Sadrian * triggered at the same time. 3712250003Sadrian */ 3713250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3714250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); 3715250003Sadrian#endif 3716250003Sadrian 3717250003Sadrian /* Initialize list pointers */ 3718250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; 3719250003Sadrian 3720250003Sadrian /* 3721250003Sadrian * Enable IQ, ADC Gain, ADC DC Offset Cals 3722250003Sadrian */ 3723250003Sadrian /* Setup all non-periodic, init time only calibrations */ 3724250003Sadrian /* XXX: Init DC Offset not working yet */ 3725250003Sadrian#ifdef not_yet 3726250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, ADC_DC_INIT_CAL)) { 3727250003Sadrian INIT_CAL(&ahp->ah_adc_dc_cal_init_data); 3728250003Sadrian INSERT_CAL(ahp, &ahp->ah_adc_dc_cal_init_data); 3729250003Sadrian } 3730250003Sadrian 3731250003Sadrian /* Initialize current pointer to first element in list */ 3732250003Sadrian ahp->ah_cal_list_curr = ahp->ah_cal_list; 3733250003Sadrian 3734250003Sadrian if (ahp->ah_cal_list_curr) { 3735250003Sadrian if (ar9300_run_init_cals(ah, 0) == AH_FALSE) { 3736250003Sadrian return AH_FALSE; 3737250003Sadrian } 3738250003Sadrian } 3739250003Sadrian#endif 3740250003Sadrian /* end - Init time calibrations */ 3741250003Sadrian 3742250003Sadrian /* If Cals are supported, add them to list via INIT/INSERT_CAL */ 3743250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, IQ_MISMATCH_CAL)) { 3744250003Sadrian INIT_CAL(&ahp->ah_iq_cal_data); 3745250003Sadrian INSERT_CAL(ahp, &ahp->ah_iq_cal_data); 3746250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3747250003Sadrian "%s: enabling IQ Calibration.\n", __func__); 3748250003Sadrian } 3749250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, TEMP_COMP_CAL)) { 3750250003Sadrian INIT_CAL(&ahp->ah_temp_comp_cal_data); 3751250003Sadrian INSERT_CAL(ahp, &ahp->ah_temp_comp_cal_data); 3752250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3753250003Sadrian "%s: enabling Temperature Compensation Calibration.\n", __func__); 3754250003Sadrian } 3755250003Sadrian 3756250003Sadrian /* Initialize current pointer to first element in list */ 3757250003Sadrian ahp->ah_cal_list_curr = ahp->ah_cal_list; 3758250003Sadrian 3759250003Sadrian /* Reset state within current cal */ 3760250003Sadrian if (ahp->ah_cal_list_curr) { 3761250003Sadrian ar9300_reset_calibration(ah, ahp->ah_cal_list_curr); 3762250003Sadrian } 3763250003Sadrian 3764250003Sadrian /* Mark all calibrations on this channel as being invalid */ 3765250008Sadrian ichan->calValid = 0; 3766250003Sadrian 3767250003Sadrian return AH_TRUE; 3768250003Sadrian} 3769250003Sadrian 3770250003Sadrianstatic inline HAL_BOOL 3771250008Sadrianar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr) 3772250003Sadrian{ 3773250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 3774250003Sadrian HAL_BOOL do_rtt_cal = AH_TRUE; 3775250003Sadrian HAL_BOOL enable_rtt = AH_FALSE; 3776250003Sadrian 3777250003Sadrian HALASSERT(ichan); 3778250003Sadrian 3779250003Sadrian return ar9300_init_cal_internal(ah, chan, ichan, enable_rtt, do_rtt_cal, skip_if_none, apply_last_iqcorr); 3780250003Sadrian} 3781250003Sadrian 3782250003Sadrian/* ar9300_reset_cal_valid 3783250003Sadrian * Entry point for upper layers to restart current cal. 3784250003Sadrian * Reset the calibration valid bit in channel. 3785250003Sadrian */ 3786250003Sadrianvoid 3787250008Sadrianar9300_reset_cal_valid(struct ath_hal *ah, const struct ieee80211_channel *chan, 3788250003Sadrian HAL_BOOL *is_cal_done, u_int32_t cal_type) 3789250003Sadrian{ 3790250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3791250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 3792250003Sadrian HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr; 3793250003Sadrian 3794250003Sadrian *is_cal_done = AH_TRUE; 3795250003Sadrian 3796250003Sadrian if (curr_cal == AH_NULL) { 3797250003Sadrian return; 3798250003Sadrian } 3799250003Sadrian if (ichan == AH_NULL) { 3800250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3801250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 3802250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 3803250003Sadrian return; 3804250003Sadrian } 3805250003Sadrian 3806250003Sadrian if (!(cal_type & IQ_MISMATCH_CAL)) { 3807250003Sadrian *is_cal_done = AH_FALSE; 3808250003Sadrian return; 3809250003Sadrian } 3810250003Sadrian 3811250003Sadrian /* Expected that this calibration has run before, post-reset. 3812250003Sadrian * Current state should be done 3813250003Sadrian */ 3814250003Sadrian if (curr_cal->cal_state != CAL_DONE) { 3815250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3816250003Sadrian "%s: Calibration state incorrect, %d\n", 3817250003Sadrian __func__, curr_cal->cal_state); 3818250003Sadrian return; 3819250003Sadrian } 3820250003Sadrian 3821250003Sadrian /* Verify Cal is supported on this channel */ 3822250003Sadrian if (ar9300_is_cal_supp(ah, chan, curr_cal->cal_data->cal_type) == AH_FALSE) { 3823250003Sadrian return; 3824250003Sadrian } 3825250003Sadrian 3826250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3827250003Sadrian "%s: Resetting Cal %d state for channel %u/0x%x\n", __func__, 3828250008Sadrian curr_cal->cal_data->cal_type, chan->ic_freq, chan->ic_flags); 3829250003Sadrian 3830250003Sadrian /* Disable cal validity in channel */ 3831250008Sadrian ichan->calValid &= ~curr_cal->cal_data->cal_type; 3832250003Sadrian curr_cal->cal_state = CAL_WAITING; 3833250003Sadrian /* Indicate to upper layers that we need polling */ 3834250003Sadrian *is_cal_done = AH_FALSE; 3835250003Sadrian} 3836250003Sadrian 3837250003Sadrianstatic inline void 3838250003Sadrianar9300_set_dma(struct ath_hal *ah) 3839250003Sadrian{ 3840250003Sadrian u_int32_t regval; 3841250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3842250003Sadrian 3843250003Sadrian#if 0 3844250003Sadrian /* 3845250003Sadrian * set AHB_MODE not to do cacheline prefetches 3846250003Sadrian */ 3847250003Sadrian regval = OS_REG_READ(ah, AR_AHB_MODE); 3848250003Sadrian OS_REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); 3849250003Sadrian#endif 3850250003Sadrian 3851250003Sadrian /* 3852250003Sadrian * let mac dma reads be in 128 byte chunks 3853250003Sadrian */ 3854250003Sadrian regval = OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; 3855250003Sadrian OS_REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); 3856250003Sadrian 3857250003Sadrian /* 3858250003Sadrian * Restore TX Trigger Level to its pre-reset value. 3859250003Sadrian * The initial value depends on whether aggregation is enabled, and is 3860250003Sadrian * adjusted whenever underruns are detected. 3861250003Sadrian */ 3862250003Sadrian /* 3863250003Sadrian OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, AH_PRIVATE(ah)->ah_tx_trig_level); 3864250003Sadrian */ 3865250003Sadrian /* 3866250003Sadrian * Osprey 1.0 bug (EV 61936). Don't change trigger level from .ini default. 3867250003Sadrian * Osprey 2.0 - hardware recommends using the default INI settings. 3868250003Sadrian */ 3869250003Sadrian#if 0 3870250003Sadrian OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, 0x3f); 3871250003Sadrian#endif 3872250003Sadrian /* 3873250003Sadrian * let mac dma writes be in 128 byte chunks 3874250003Sadrian */ 3875250003Sadrian regval = OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; 3876250003Sadrian OS_REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); 3877250003Sadrian 3878250003Sadrian /* 3879250003Sadrian * Setup receive FIFO threshold to hold off TX activities 3880250003Sadrian */ 3881250003Sadrian OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); 3882250003Sadrian 3883250003Sadrian /* 3884250003Sadrian * reduce the number of usable entries in PCU TXBUF to avoid 3885250003Sadrian * wrap around bugs. (bug 20428) 3886250003Sadrian */ 3887250003Sadrian 3888250003Sadrian if (AR_SREV_WASP(ah) && 3889250003Sadrian (AH_PRIVATE((ah))->ah_macRev > AR_SREV_REVISION_WASP_12)) { 3890250003Sadrian /* Wasp 1.3 fix for EV#85395 requires usable entries 3891250003Sadrian * to be set to 0x500 3892250003Sadrian */ 3893250003Sadrian OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, 0x500); 3894250003Sadrian } else { 3895250003Sadrian OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); 3896250003Sadrian } 3897250003Sadrian 3898250003Sadrian /* 3899250003Sadrian * Enable HPQ for UAPSD 3900250003Sadrian */ 3901250003Sadrian if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 3902250003Sadrian OS_REG_WRITE(ah, AR_HP_Q_CONTROL, 3903250003Sadrian AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN); 3904250003Sadrian } 3905250003Sadrian 3906250003Sadrian /* 3907250003Sadrian * set the transmit status ring 3908250003Sadrian */ 3909250003Sadrian ar9300_reset_tx_status_ring(ah); 3910250003Sadrian 3911250003Sadrian /* 3912250003Sadrian * set rxbp threshold. Must be non-zero for RX_EOL to occur. 3913250003Sadrian * For Osprey 2.0+, keep the original thresholds 3914250003Sadrian * otherwise performance is lost due to excessive RX EOL interrupts. 3915250003Sadrian */ 3916250003Sadrian OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1); 3917250003Sadrian OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1); 3918250003Sadrian 3919250003Sadrian /* 3920250003Sadrian * set receive buffer size. 3921250003Sadrian */ 3922250003Sadrian if (ahp->rx_buf_size) { 3923250003Sadrian OS_REG_WRITE(ah, AR_DATABUF, ahp->rx_buf_size); 3924250003Sadrian } 3925250003Sadrian} 3926250003Sadrian 3927250003Sadrianstatic inline void 3928250008Sadrianar9300_init_bb(struct ath_hal *ah, struct ieee80211_channel *chan) 3929250003Sadrian{ 3930250003Sadrian u_int32_t synth_delay; 3931250003Sadrian 3932250003Sadrian /* 3933250003Sadrian * Wait for the frequency synth to settle (synth goes on 3934250003Sadrian * via AR_PHY_ACTIVE_EN). Read the phy active delay register. 3935250003Sadrian * Value is in 100ns increments. 3936250003Sadrian */ 3937250003Sadrian synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; 3938250008Sadrian if (IEEE80211_IS_CHAN_CCK(chan)) { 3939250003Sadrian synth_delay = (4 * synth_delay) / 22; 3940250003Sadrian } else { 3941250003Sadrian synth_delay /= 10; 3942250003Sadrian } 3943250003Sadrian 3944250003Sadrian /* Activate the PHY (includes baseband activate + synthesizer on) */ 3945250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 3946250003Sadrian 3947250003Sadrian /* 3948250003Sadrian * There is an issue if the AP starts the calibration before 3949250003Sadrian * the base band timeout completes. This could result in the 3950250003Sadrian * rx_clear AH_FALSE triggering. As a workaround we add delay an 3951250003Sadrian * extra BASE_ACTIVATE_DELAY usecs to ensure this condition 3952250003Sadrian * does not happen. 3953250003Sadrian */ 3954250003Sadrian OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY); 3955250003Sadrian} 3956250003Sadrian 3957250003Sadrianstatic inline void 3958250003Sadrianar9300_init_interrupt_masks(struct ath_hal *ah, HAL_OPMODE opmode) 3959250003Sadrian{ 3960250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3961250003Sadrian u_int32_t msi_cfg = 0; 3962250003Sadrian u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; 3963250003Sadrian 3964250003Sadrian /* 3965250003Sadrian * Setup interrupt handling. Note that ar9300_reset_tx_queue 3966250003Sadrian * manipulates the secondary IMR's as queues are enabled 3967250003Sadrian * and disabled. This is done with RMW ops to insure the 3968250003Sadrian * settings we make here are preserved. 3969250003Sadrian */ 3970250003Sadrian ahp->ah_mask_reg = 3971250003Sadrian AR_IMR_TXERR | AR_IMR_TXURN | 3972250003Sadrian AR_IMR_RXERR | AR_IMR_RXORN | 3973250003Sadrian AR_IMR_BCNMISC; 3974250003Sadrian 3975250003Sadrian if (ahp->ah_intr_mitigation_rx) { 3976250003Sadrian /* enable interrupt mitigation for rx */ 3977250003Sadrian ahp->ah_mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR | AR_IMR_RXOK_HP; 3978250003Sadrian msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR; 3979250003Sadrian } else { 3980250003Sadrian ahp->ah_mask_reg |= AR_IMR_RXOK_LP | AR_IMR_RXOK_HP; 3981250003Sadrian msi_cfg |= AR_INTCFG_MSI_RXOK; 3982250003Sadrian } 3983250003Sadrian if (ahp->ah_intr_mitigation_tx) { 3984250003Sadrian /* enable interrupt mitigation for tx */ 3985250003Sadrian ahp->ah_mask_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR; 3986250003Sadrian msi_cfg |= AR_INTCFG_MSI_TXINTM | AR_INTCFG_MSI_TXMINTR; 3987250003Sadrian } else { 3988250003Sadrian ahp->ah_mask_reg |= AR_IMR_TXOK; 3989250003Sadrian msi_cfg |= AR_INTCFG_MSI_TXOK; 3990250003Sadrian } 3991250003Sadrian if (opmode == HAL_M_HOSTAP) { 3992250003Sadrian ahp->ah_mask_reg |= AR_IMR_MIB; 3993250003Sadrian } 3994250003Sadrian 3995250003Sadrian OS_REG_WRITE(ah, AR_IMR, ahp->ah_mask_reg); 3996250003Sadrian OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); 3997250003Sadrian ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2); 3998250003Sadrian 3999250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 4000250003Sadrian /* Cache MSI register value */ 4001250003Sadrian ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI)); 4002250003Sadrian ahp->ah_msi_reg |= AR_PCIE_MSI_HW_DBI_WR_EN; 4003250003Sadrian if (AR_SREV_POSEIDON(ah)) { 4004250003Sadrian ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 4005250003Sadrian } else { 4006250003Sadrian ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR; 4007250003Sadrian } 4008250003Sadrian /* Program MSI configuration */ 4009250003Sadrian OS_REG_WRITE(ah, AR_INTCFG, msi_cfg); 4010250003Sadrian } 4011250003Sadrian 4012250003Sadrian /* 4013250003Sadrian * debug - enable to see all synchronous interrupts status 4014250003Sadrian */ 4015250003Sadrian /* Clear any pending sync cause interrupts */ 4016250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE), 0xFFFFFFFF); 4017250003Sadrian 4018250003Sadrian /* Allow host interface sync interrupt sources to set cause bit */ 4019250003Sadrian if (AR_SREV_POSEIDON(ah)) { 4020250003Sadrian sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; 4021250003Sadrian } 4022250003Sadrian else if (AR_SREV_WASP(ah)) { 4023250003Sadrian sync_en_def = AR9340_INTR_SYNC_DEFAULT; 4024250003Sadrian } 4025250003Sadrian OS_REG_WRITE(ah, 4026250003Sadrian AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), sync_en_def); 4027250003Sadrian 4028250003Sadrian /* _Disable_ host interface sync interrupt when cause bits set */ 4029250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 0); 4030250003Sadrian 4031250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0); 4032250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 0); 4033250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE), 0); 4034250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK), 0); 4035250003Sadrian} 4036250003Sadrian 4037250003Sadrianstatic inline void 4038250003Sadrianar9300_init_qos(struct ath_hal *ah) 4039250003Sadrian{ 4040250003Sadrian OS_REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); /* XXX magic */ 4041250003Sadrian OS_REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); /* XXX magic */ 4042250003Sadrian 4043250003Sadrian /* Turn on NOACK Support for QoS packets */ 4044250003Sadrian OS_REG_WRITE(ah, AR_QOS_NO_ACK, 4045250003Sadrian SM(2, AR_QOS_NO_ACK_TWO_BIT) | 4046250003Sadrian SM(5, AR_QOS_NO_ACK_BIT_OFF) | 4047250003Sadrian SM(0, AR_QOS_NO_ACK_BYTE_OFF)); 4048250003Sadrian 4049250003Sadrian /* 4050250003Sadrian * initialize TXOP for all TIDs 4051250003Sadrian */ 4052250003Sadrian OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); 4053250003Sadrian OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); 4054250003Sadrian OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); 4055250003Sadrian OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); 4056250003Sadrian OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); 4057250003Sadrian} 4058250003Sadrian 4059250003Sadrianstatic inline void 4060250003Sadrianar9300_init_user_settings(struct ath_hal *ah) 4061250003Sadrian{ 4062250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4063250003Sadrian 4064250003Sadrian /* Restore user-specified settings */ 4065250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 4066250003Sadrian "--AP %s ahp->ah_misc_mode 0x%x\n", __func__, ahp->ah_misc_mode); 4067250003Sadrian if (ahp->ah_misc_mode != 0) { 4068250003Sadrian OS_REG_WRITE(ah, 4069250003Sadrian AR_PCU_MISC, OS_REG_READ(ah, AR_PCU_MISC) | ahp->ah_misc_mode); 4070250003Sadrian } 4071250003Sadrian if (ahp->ah_get_plcp_hdr) { 4072250003Sadrian OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM); 4073250003Sadrian } 4074250003Sadrian if (ahp->ah_slot_time != (u_int) -1) { 4075250003Sadrian ar9300_set_slot_time(ah, ahp->ah_slot_time); 4076250003Sadrian } 4077250003Sadrian if (ahp->ah_ack_timeout != (u_int) -1) { 4078250003Sadrian ar9300_set_ack_timeout(ah, ahp->ah_ack_timeout); 4079250003Sadrian } 4080250003Sadrian if (AH_PRIVATE(ah)->ah_diagreg != 0) { 4081250003Sadrian OS_REG_SET_BIT(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 4082250003Sadrian } 4083250003Sadrian if (ahp->ah_beacon_rssi_threshold != 0) { 4084250003Sadrian ar9300_set_hw_beacon_rssi_threshold(ah, ahp->ah_beacon_rssi_threshold); 4085250003Sadrian } 4086250003Sadrian#ifdef ATH_SUPPORT_DFS 4087250003Sadrian if (ahp->ah_cac_quiet_enabled) { 4088250003Sadrian ar9300_cac_tx_quiet(ah, 1); 4089250003Sadrian } 4090250003Sadrian#endif /* ATH_SUPPORT_DFS */ 4091250003Sadrian} 4092250003Sadrian 4093250003Sadrianint 4094250003Sadrianar9300_get_spur_info(struct ath_hal * ah, int *enable, int len, u_int16_t *freq) 4095250003Sadrian{ 4096250008Sadrian// struct ath_hal_private *ap = AH_PRIVATE(ah); 4097250003Sadrian int i, j; 4098250003Sadrian 4099250003Sadrian for (i = 0; i < len; i++) { 4100250003Sadrian freq[i] = 0; 4101250003Sadrian } 4102250003Sadrian 4103250008Sadrian *enable = ah->ah_config.ath_hal_spur_mode; 4104250003Sadrian for (i = 0, j = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 4105250008Sadrian if (AH9300(ah)->ath_hal_spur_chans[i][0] != AR_NO_SPUR) { 4106250008Sadrian freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][0]; 4107250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 4108250008Sadrian "1. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][0]); 4109250003Sadrian } 4110250008Sadrian if (AH9300(ah)->ath_hal_spur_chans[i][1] != AR_NO_SPUR) { 4111250008Sadrian freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][1]; 4112250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 4113250008Sadrian "2. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][1]); 4114250003Sadrian } 4115250003Sadrian } 4116250003Sadrian 4117250003Sadrian return 0; 4118250003Sadrian} 4119250003Sadrian 4120250003Sadrian#define ATH_HAL_2GHZ_FREQ_MIN 20000 4121250003Sadrian#define ATH_HAL_2GHZ_FREQ_MAX 29999 4122250003Sadrian#define ATH_HAL_5GHZ_FREQ_MIN 50000 4123250003Sadrian#define ATH_HAL_5GHZ_FREQ_MAX 59999 4124250003Sadrian 4125250008Sadrian#if 0 4126250003Sadrianint 4127250003Sadrianar9300_set_spur_info(struct ath_hal * ah, int enable, int len, u_int16_t *freq) 4128250003Sadrian{ 4129250003Sadrian struct ath_hal_private *ap = AH_PRIVATE(ah); 4130250003Sadrian int i, j, k; 4131250003Sadrian 4132250003Sadrian ap->ah_config.ath_hal_spur_mode = enable; 4133250003Sadrian 4134250003Sadrian if (ap->ah_config.ath_hal_spur_mode == SPUR_ENABLE_IOCTL) { 4135250003Sadrian for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 4136250008Sadrian AH9300(ah)->ath_hal_spur_chans[i][0] = AR_NO_SPUR; 4137250008Sadrian AH9300(ah)->ath_hal_spur_chans[i][1] = AR_NO_SPUR; 4138250003Sadrian } 4139250003Sadrian for (i = 0, j = 0, k = 0; i < len; i++) { 4140250003Sadrian if (freq[i] > ATH_HAL_2GHZ_FREQ_MIN && 4141250003Sadrian freq[i] < ATH_HAL_2GHZ_FREQ_MAX) 4142250003Sadrian { 4143250003Sadrian /* 2GHz Spur */ 4144250003Sadrian if (j < AR_EEPROM_MODAL_SPURS) { 4145250008Sadrian AH9300(ah)->ath_hal_spur_chans[j++][1] = freq[i]; 4146250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "1 set spur %d\n", freq[i]); 4147250003Sadrian } 4148250003Sadrian } else if (freq[i] > ATH_HAL_5GHZ_FREQ_MIN && 4149250003Sadrian freq[i] < ATH_HAL_5GHZ_FREQ_MAX) 4150250003Sadrian { 4151250003Sadrian /* 5Ghz Spur */ 4152250003Sadrian if (k < AR_EEPROM_MODAL_SPURS) { 4153250008Sadrian AH9300(ah)->ath_hal_spur_chans[k++][0] = freq[i]; 4154250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "2 set spur %d\n", freq[i]); 4155250003Sadrian } 4156250003Sadrian } 4157250003Sadrian } 4158250003Sadrian } 4159250003Sadrian 4160250003Sadrian return 0; 4161250003Sadrian} 4162250008Sadrian#endif 4163250003Sadrian 4164250003Sadrian#define ar9300_check_op_mode(_opmode) \ 4165250003Sadrian ((_opmode == HAL_M_STA) || (_opmode == HAL_M_IBSS) ||\ 4166250003Sadrian (_opmode == HAL_M_HOSTAP) || (_opmode == HAL_M_MONITOR)) 4167250003Sadrian 4168250003Sadrian 4169250003Sadrian 4170250003Sadrian 4171250003Sadrian#ifndef ATH_NF_PER_CHAN 4172250003Sadrian/* 4173250003Sadrian* To fixed first reset noise floor value not correct issue 4174250003Sadrian* For ART need it to fixed low rate sens too low issue 4175250003Sadrian*/ 4176250003Sadrianstatic int 4177250003SadrianFirst_NFCal(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, 4178250008Sadrian int is_scan, struct ieee80211_channel *chan) 4179250003Sadrian{ 4180250003Sadrian HAL_NFCAL_HIST_FULL *nfh; 4181250003Sadrian int i, j, k; 4182250008Sadrian int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; 4183250003Sadrian int is_2g = 0; 4184250003Sadrian int nf_hist_len; 4185250003Sadrian int stats = 0; 4186250003Sadrian 4187250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 4188250003Sadrian#define IS(_c, _f) (((_c)->channel_flags & _f) || 0) 4189250003Sadrian 4190250003Sadrian 4191250003Sadrian if ((!is_scan) && 4192250008Sadrian chan->ic_freq == AH_PRIVATE(ah)->ah_curchan->ic_freq) 4193250003Sadrian { 4194250003Sadrian nfh = &AH_PRIVATE(ah)->nf_cal_hist; 4195250003Sadrian } else { 4196250003Sadrian nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 4197250003Sadrian } 4198250008Sadrian 4199250003Sadrian ar9300_start_nf_cal(ah); 4200250003Sadrian for (j = 0; j < 10000; j++) { 4201250003Sadrian if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){ 4202250003Sadrian break; 4203250003Sadrian } 4204250003Sadrian OS_DELAY(10); 4205250003Sadrian } 4206250003Sadrian if (j < 10000) { 4207250008Sadrian is_2g = IEEE80211_IS_CHAN_2GHZ(chan); 4208250003Sadrian ar9300_upload_noise_floor(ah, is_2g, nfarray); 4209250003Sadrian 4210250003Sadrian if (is_scan) { 4211250003Sadrian /* 4212250003Sadrian * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct 4213250003Sadrian * rather than a HAL_NFCAL_HIST_FULL struct. 4214250003Sadrian * As long as we only use the first history element of nf_cal_buffer 4215250008Sadrian * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use 4216250003Sadrian * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably. 4217250003Sadrian */ 4218250003Sadrian nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 4219250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; 4220250003Sadrian } else { 4221250003Sadrian nfh = &AH_PRIVATE(ah)->nf_cal_hist; 4222250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 4223250003Sadrian } 4224250003Sadrian 4225250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i ++) { 4226250003Sadrian for (k = 0; k < HAL_NF_CAL_HIST_LEN_FULL; k++) { 4227250003Sadrian nfh->nf_cal_buffer[k][i] = nfarray[i]; 4228250003Sadrian } 4229250003Sadrian nfh->base.priv_nf[i] = ar9300_limit_nf_range(ah, 4230250003Sadrian ar9300_get_nf_hist_mid(ah, nfh, i, nf_hist_len)); 4231250003Sadrian } 4232250003Sadrian 4233250003Sadrian 4234250003Sadrian //ar9300StoreNewNf(ah, ichan, is_scan); 4235250003Sadrian 4236250003Sadrian /* 4237250003Sadrian * See if the NF value from the old channel should be 4238250003Sadrian * retained when switching to a new channel. 4239250003Sadrian * TBD: this may need to be changed, as it wipes out the 4240250003Sadrian * purpose of saving NF values for each channel. 4241250003Sadrian */ 4242250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) 4243250003Sadrian { 4244250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) 4245250003Sadrian { 4246250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4247250003Sadrian AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ) 4248250003Sadrian { 4249250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4250250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4251250003Sadrian } 4252250003Sadrian } else { 4253250003Sadrian if (AR_SREV_AR9580(ah)) { 4254250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4255250003Sadrian AR_PHY_CCA_NOM_VAL_PEACOCK_5GHZ) 4256250003Sadrian { 4257250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4258250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4259250003Sadrian } 4260250003Sadrian } else { 4261250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4262250003Sadrian AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ) 4263250003Sadrian { 4264250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4265250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4266250003Sadrian } 4267250003Sadrian } 4268250003Sadrian } 4269250003Sadrian } 4270250003Sadrian /* 4271250003Sadrian * Copy the channel's NF buffer, which may have been modified 4272250003Sadrian * just above here, to the full NF history buffer. 4273250003Sadrian */ 4274250003Sadrian ar9300_reset_nf_hist_buff(ah, ichan); 4275250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 4276250003Sadrian ar9300_load_nf(ah, nf_buf); 4277250003Sadrian stats = 0; 4278250003Sadrian } else { 4279250003Sadrian stats = 1; 4280250003Sadrian } 4281250003Sadrian#undef IS 4282250003Sadrian return stats; 4283250003Sadrian} 4284250003Sadrian#endif 4285250003Sadrian 4286250003Sadrian 4287250003Sadrian/* 4288250003Sadrian * Places the device in and out of reset and then places sane 4289250003Sadrian * values in the registers based on EEPROM config, initialization 4290250003Sadrian * vectors (as determined by the mode), and station configuration 4291250003Sadrian * 4292250003Sadrian * b_channel_change is used to preserve DMA/PCU registers across 4293250003Sadrian * a HW Reset during channel change. 4294250003Sadrian */ 4295250003SadrianHAL_BOOL 4296250008Sadrianar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, 4297250003Sadrian HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask, 4298250003Sadrian HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change, 4299250003Sadrian HAL_STATUS *status, int is_scan) 4300250003Sadrian{ 4301250003Sadrian#define FAIL(_code) do { ecode = _code; goto bad; } while (0) 4302250003Sadrian u_int32_t save_led_state; 4303250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4304250003Sadrian struct ath_hal_private *ap = AH_PRIVATE(ah); 4305250003Sadrian HAL_CHANNEL_INTERNAL *ichan; 4306250008Sadrian //const struct ieee80211_channel *curchan = ap->ah_curchan; 4307250003Sadrian#if ATH_SUPPORT_MCI 4308250003Sadrian HAL_BOOL save_full_sleep = ahp->ah_chip_full_sleep; 4309250003Sadrian#endif 4310250003Sadrian u_int32_t save_def_antenna; 4311250003Sadrian u_int32_t mac_sta_id1; 4312250003Sadrian HAL_STATUS ecode; 4313250003Sadrian int i, rx_chainmask; 4314250003Sadrian int nf_hist_buff_reset = 0; 4315250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 4316250003Sadrian#ifdef ATH_FORCE_PPM 4317250003Sadrian u_int32_t save_force_val, tmp_reg; 4318250003Sadrian#endif 4319250003Sadrian HAL_BOOL stopped, cal_ret; 4320250003Sadrian HAL_BOOL apply_last_iqcorr = AH_FALSE; 4321250003Sadrian 4322250003Sadrian if (OS_REG_READ(ah, AR_IER) == AR_IER_ENABLE) { 4323250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "** Reset called with WLAN " 4324250003Sadrian "interrupt enabled %08x **\n", ar9300_get_interrupts(ah)); 4325250003Sadrian } 4326250003Sadrian 4327250003Sadrian /* 4328250003Sadrian * Set the status to "ok" by default to cover the cases 4329250003Sadrian * where we return AH_FALSE without going to "bad" 4330250003Sadrian */ 4331250003Sadrian HALASSERT(status); 4332250003Sadrian *status = HAL_OK; 4333250008Sadrian if ((ah->ah_config.ath_hal_sta_update_tx_pwr_enable)) { 4334250008Sadrian AH9300(ah)->green_tx_status = HAL_RSSI_TX_POWER_NONE; 4335250003Sadrian } 4336250003Sadrian 4337250003Sadrian#if ATH_SUPPORT_MCI 4338250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 4339250003Sadrian (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah))) 4340250003Sadrian { 4341250008Sadrian ar9300_mci_2g5g_changed(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4342250003Sadrian } 4343250003Sadrian#endif 4344250003Sadrian 4345250003Sadrian ahp->ah_ext_prot_spacing = extprotspacing; 4346250008Sadrian ahp->ah_tx_chainmask = txchainmask & ap->ah_caps.halTxChainMask; 4347250008Sadrian ahp->ah_rx_chainmask = rxchainmask & ap->ah_caps.halRxChainMask; 4348250008Sadrian ahp->ah_tx_cal_chainmask = ap->ah_caps.halTxChainMask; 4349250008Sadrian ahp->ah_rx_cal_chainmask = ap->ah_caps.halRxChainMask; 4350250003Sadrian HALASSERT(ar9300_check_op_mode(opmode)); 4351250003Sadrian 4352250003Sadrian OS_MARK(ah, AH_MARK_RESET, b_channel_change); 4353250003Sadrian 4354250003Sadrian /* 4355250003Sadrian * Map public channel to private. 4356250003Sadrian */ 4357250003Sadrian ichan = ar9300_check_chan(ah, chan); 4358250003Sadrian if (ichan == AH_NULL) { 4359250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 4360250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 4361250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 4362250003Sadrian FAIL(HAL_EINVAL); 4363250003Sadrian } 4364250003Sadrian 4365250003Sadrian ichan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */ 4366250008Sadrian#if 0 4367250003Sadrian chan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */ 4368250008Sadrian#endif 4369250003Sadrian 4370250003Sadrian if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) { 4371250003Sadrian /* Need to stop RX DMA before reset otherwise chip might hang */ 4372250003Sadrian stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */ 4373250003Sadrian ar9300_set_rx_filter(ah, 0); 4374250003Sadrian stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */ 4375250003Sadrian if (!stopped) { 4376250003Sadrian /* 4377250003Sadrian * During the transition from full sleep to reset, 4378250003Sadrian * recv DMA regs are not available to be read 4379250003Sadrian */ 4380250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 4381250003Sadrian "%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__); 4382250003Sadrian b_channel_change = AH_FALSE; 4383250003Sadrian } 4384250003Sadrian } else { 4385250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 4386250003Sadrian "%s[%d]: Chip is already in full sleep\n", __func__, __LINE__); 4387250003Sadrian } 4388250003Sadrian 4389250003Sadrian#if ATH_SUPPORT_MCI 4390250008Sadrian if ((AH_PRIVATE(ah)->ah_caps.halMciSupport) && 4391250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_CAL_START)) 4392250003Sadrian { 4393250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 4394250003Sadrian 4395250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4396250003Sadrian "(MCI) %s: Stop rx for BT cal.\n", __func__); 4397250003Sadrian ahp->ah_mci_bt_state = MCI_BT_CAL; 4398250003Sadrian 4399250003Sadrian /* 4400250003Sadrian * MCIFIX: disable mci interrupt here. This is to avoid SW_MSG_DONE or 4401250003Sadrian * RX_MSG bits to trigger MCI_INT and lead to mci_intr reentry. 4402250003Sadrian */ 4403250003Sadrian ar9300_mci_disable_interrupt(ah); 4404250003Sadrian 4405250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4406250003Sadrian "(MCI) %s: Send WLAN_CAL_GRANT\n", __func__); 4407250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); 4408250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 4409250003Sadrian 4410250003Sadrian /* Wait BT calibration to be completed for 25ms */ 4411250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4412250003Sadrian "(MCI) %s: BT is calibrating.\n", __func__); 4413250003Sadrian if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) { 4414250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4415250003Sadrian "(MCI) %s: Got BT_CAL_DONE.\n", __func__); 4416250003Sadrian } 4417250003Sadrian else { 4418250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4419250003Sadrian "(MCI) %s: ### BT cal takes too long. Force bt_state to be bt_awake.\n", 4420250003Sadrian __func__); 4421250003Sadrian } 4422250003Sadrian ahp->ah_mci_bt_state = MCI_BT_AWAKE; 4423250003Sadrian /* MCIFIX: enable mci interrupt here */ 4424250003Sadrian ar9300_mci_enable_interrupt(ah); 4425250003Sadrian 4426250003Sadrian return AH_TRUE; 4427250003Sadrian } 4428250003Sadrian#endif 4429250003Sadrian 4430250003Sadrian /* Bring out of sleep mode */ 4431250003Sadrian if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { 4432250003Sadrian *status = HAL_INV_PMODE; 4433250003Sadrian return AH_FALSE; 4434250003Sadrian } 4435250003Sadrian 4436250003Sadrian /* Check the Rx mitigation config again, it might have changed 4437250003Sadrian * during attach in ath_vap_attach. 4438250003Sadrian */ 4439250008Sadrian if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) { 4440250003Sadrian ahp->ah_intr_mitigation_rx = AH_TRUE; 4441250003Sadrian } else { 4442250003Sadrian ahp->ah_intr_mitigation_rx = AH_FALSE; 4443250003Sadrian } 4444250003Sadrian 4445250008Sadrian /* 4446250008Sadrian * XXX TODO FreeBSD: 4447250008Sadrian * 4448250008Sadrian * This is painful because we don't have a non-const channel pointer 4449250008Sadrian * at this stage. 4450250008Sadrian * 4451250008Sadrian * Make sure this gets fixed! 4452250008Sadrian */ 4453250008Sadrian#if 0 4454250003Sadrian /* Get the value from the previous NF cal and update history buffer */ 4455250003Sadrian if (curchan && (ahp->ah_chip_full_sleep != AH_TRUE)) { 4456250003Sadrian ar9300_store_new_nf(ah, curchan, is_scan); 4457250003Sadrian } 4458250008Sadrian#endif 4459250003Sadrian 4460250003Sadrian /* 4461250003Sadrian * Account for the effect of being in either the 2 GHz or 5 GHz band 4462250003Sadrian * on the nominal, max allowable, and min allowable noise floor values. 4463250003Sadrian */ 4464250008Sadrian AH9300(ah)->nfp = IS_CHAN_2GHZ(ichan) ? &ahp->nf_2GHz : &ahp->nf_5GHz; 4465250003Sadrian 4466250008Sadrian /* 4467250008Sadrian * XXX For now, don't apply the last IQ correction. 4468250008Sadrian * 4469250008Sadrian * This should be done when scorpion is enabled on FreeBSD; just be 4470250008Sadrian * sure to fix this channel match code so it uses net80211 flags 4471250008Sadrian * instead. 4472250008Sadrian */ 4473250008Sadrian#if 0 4474250003Sadrian if (AR_SREV_SCORPION(ah) && curchan && (chan->channel == curchan->channel) && 4475250003Sadrian ((chan->channel_flags & (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)) == 4476250003Sadrian (curchan->channel_flags & 4477250003Sadrian (CHANNEL_ALL | CHANNEL_HALF | CHANNEL_QUARTER)))) { 4478250003Sadrian apply_last_iqcorr = AH_TRUE; 4479250003Sadrian } 4480250008Sadrian#endif 4481250008Sadrian apply_last_iqcorr = AH_FALSE; 4482250008Sadrian 4483250003Sadrian 4484250003Sadrian#ifndef ATH_NF_PER_CHAN 4485250003Sadrian /* 4486250003Sadrian * If there's only one full-size home-channel NF history buffer 4487250003Sadrian * rather than a full-size NF history buffer per channel, decide 4488250003Sadrian * whether to (re)initialize the home-channel NF buffer. 4489250003Sadrian * If this is just a channel change for a scan, or if the channel 4490250003Sadrian * is not being changed, don't mess up the home channel NF history 4491250003Sadrian * buffer with NF values from this scanned channel. If we're 4492250003Sadrian * changing the home channel to a new channel, reset the home-channel 4493250003Sadrian * NF history buffer with the most accurate NF known for the new channel. 4494250003Sadrian */ 4495250003Sadrian if (!is_scan && (!ap->ah_curchan || 4496250008Sadrian ap->ah_curchan->ic_freq != chan->ic_freq)) // || 4497250008Sadrian// ap->ah_curchan->channel_flags != chan->channel_flags)) 4498250003Sadrian { 4499250003Sadrian nf_hist_buff_reset = 1; 4500250003Sadrian ar9300_reset_nf_hist_buff(ah, ichan); 4501250003Sadrian } 4502250003Sadrian#endif 4503250003Sadrian /* 4504250003Sadrian * Fast channel change (Change synthesizer based on channel freq 4505250003Sadrian * without resetting chip) 4506250003Sadrian * Don't do it when 4507250003Sadrian * - Flag is not set 4508250003Sadrian * - Chip is just coming out of full sleep 4509250003Sadrian * - Channel to be set is same as current channel 4510250003Sadrian * - Channel flags are different, like when moving from 2GHz to 5GHz 4511250003Sadrian * channels 4512250003Sadrian * - Merlin: Switching in/out of fast clock enabled channels 4513250003Sadrian * (not currently coded, since fast clock is enabled 4514250003Sadrian * across the 5GHz band 4515250003Sadrian * and we already do a full reset when switching in/out 4516250003Sadrian * of 5GHz channels) 4517250003Sadrian */ 4518250008Sadrian#if 0 4519250003Sadrian if (b_channel_change && 4520250003Sadrian (ahp->ah_chip_full_sleep != AH_TRUE) && 4521250003Sadrian (AH_PRIVATE(ah)->ah_curchan != AH_NULL) && 4522250003Sadrian ((chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) && 4523250003Sadrian (((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & chan->channel_flags) == 4524250003Sadrian ((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & AH_PRIVATE(ah)->ah_curchan->channel_flags)))) 4525250003Sadrian { 4526250003Sadrian if (ar9300_channel_change(ah, chan, ichan, macmode)) { 4527250003Sadrian chan->channel_flags = ichan->channel_flags; 4528250003Sadrian chan->priv_flags = ichan->priv_flags; 4529250003Sadrian AH_PRIVATE(ah)->ah_curchan->ah_channel_time = 0; 4530250003Sadrian AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar9300_get_tsf64(ah); 4531250003Sadrian 4532250003Sadrian /* 4533250003Sadrian * Load the NF from history buffer of the current channel. 4534250003Sadrian * NF is slow time-variant, so it is OK to use a historical value. 4535250003Sadrian */ 4536250003Sadrian ar9300_get_nf_hist_base(ah, 4537250003Sadrian AH_PRIVATE(ah)->ah_curchan, is_scan, nf_buf); 4538250003Sadrian ar9300_load_nf(ah, nf_buf); 4539250003Sadrian 4540250003Sadrian /* start NF calibration, without updating BB NF register*/ 4541250003Sadrian ar9300_start_nf_cal(ah); 4542250003Sadrian 4543250003Sadrian /* 4544250003Sadrian * If channel_change completed and DMA was stopped 4545250003Sadrian * successfully - skip the rest of reset 4546250003Sadrian */ 4547250003Sadrian if (AH9300(ah)->ah_dma_stuck != AH_TRUE) { 4548250003Sadrian WAR_USB_DISABLE_PLL_LOCK_DETECT(ah); 4549250003Sadrian#if ATH_SUPPORT_MCI 4550250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) 4551250003Sadrian { 4552250003Sadrian ar9300_mci_2g5g_switch(ah, AH_TRUE); 4553250003Sadrian } 4554250003Sadrian#endif 4555250008Sadrian return HAL_OK; 4556250003Sadrian } 4557250003Sadrian } 4558250003Sadrian } 4559250008Sadrian#endif /* #if 0 */ 4560250003Sadrian 4561250003Sadrian#if ATH_SUPPORT_MCI 4562250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4563250003Sadrian ar9300_mci_disable_interrupt(ah); 4564250003Sadrian if (ahp->ah_mci_ready && !save_full_sleep) { 4565250003Sadrian ar9300_mci_mute_bt(ah); 4566250003Sadrian OS_DELAY(20); 4567250003Sadrian OS_REG_WRITE(ah, AR_BTCOEX_CTRL, 0); 4568250003Sadrian } 4569250003Sadrian 4570250003Sadrian ahp->ah_mci_bt_state = MCI_BT_SLEEP; 4571250003Sadrian ahp->ah_mci_ready = AH_FALSE; 4572250003Sadrian } 4573250003Sadrian#endif 4574250003Sadrian 4575250003Sadrian AH9300(ah)->ah_dma_stuck = AH_FALSE; 4576250003Sadrian#ifdef ATH_FORCE_PPM 4577250003Sadrian /* Preserve force ppm state */ 4578250003Sadrian save_force_val = 4579250003Sadrian OS_REG_READ(ah, AR_PHY_TIMING2) & 4580250003Sadrian (AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL); 4581250003Sadrian#endif 4582250003Sadrian /* 4583250003Sadrian * Preserve the antenna on a channel change 4584250003Sadrian */ 4585250003Sadrian save_def_antenna = OS_REG_READ(ah, AR_DEF_ANTENNA); 4586250003Sadrian if (0 == ahp->ah_smartantenna_enable ) 4587250003Sadrian { 4588250003Sadrian if (save_def_antenna == 0) { 4589250003Sadrian save_def_antenna = 1; 4590250003Sadrian } 4591250003Sadrian } 4592250003Sadrian 4593250003Sadrian /* Save hardware flag before chip reset clears the register */ 4594250003Sadrian mac_sta_id1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; 4595250003Sadrian 4596250003Sadrian /* Save led state from pci config register */ 4597250003Sadrian save_led_state = OS_REG_READ(ah, AR_CFG_LED) & 4598250003Sadrian (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | 4599250003Sadrian AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW); 4600250003Sadrian 4601250003Sadrian /* Mark PHY inactive prior to reset, to be undone in ar9300_init_bb () */ 4602250003Sadrian ar9300_mark_phy_inactive(ah); 4603250003Sadrian 4604250003Sadrian if (!ar9300_chip_reset(ah, chan)) { 4605250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: chip reset failed\n", __func__); 4606250003Sadrian FAIL(HAL_EIO); 4607250003Sadrian } 4608250003Sadrian 4609250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4610250003Sadrian 4611250003Sadrian 4612250003Sadrian /* Disable JTAG */ 4613250003Sadrian OS_REG_SET_BIT(ah, 4614250003Sadrian AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE); 4615250003Sadrian 4616250003Sadrian /* 4617250003Sadrian * Note that ar9300_init_chain_masks() is called from within 4618250003Sadrian * ar9300_process_ini() to ensure the swap bit is set before 4619250003Sadrian * the pdadc table is written. 4620250003Sadrian */ 4621250003Sadrian ecode = ar9300_process_ini(ah, chan, ichan, macmode); 4622250003Sadrian if (ecode != HAL_OK) { 4623250003Sadrian goto bad; 4624250003Sadrian } 4625250003Sadrian 4626250003Sadrian ahp->ah_immunity_on = AH_FALSE; 4627250003Sadrian 4628250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 4629250003Sadrian ahp->tx_iq_cal_enable = OS_REG_READ_FIELD(ah, 4630250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0(ah), 4631250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL) ? 4632250003Sadrian 1 : 0; 4633250003Sadrian } 4634250003Sadrian ahp->tx_cl_cal_enable = (OS_REG_READ(ah, AR_PHY_CL_CAL_CTL) & 4635250003Sadrian AR_PHY_CL_CAL_ENABLE) ? 1 : 0; 4636250003Sadrian 4637250003Sadrian /* For devices with full HW RIFS Rx support (Sowl/Howl/Merlin, etc), 4638250003Sadrian * restore register settings from prior to reset. 4639250003Sadrian */ 4640250003Sadrian if ((AH_PRIVATE(ah)->ah_curchan != AH_NULL) && 4641250003Sadrian (ar9300_get_capability(ah, HAL_CAP_LDPCWAR, 0, AH_NULL) == HAL_OK)) 4642250003Sadrian { 4643250003Sadrian /* Re-program RIFS Rx policy after reset */ 4644250003Sadrian ar9300_set_rifs_delay(ah, ahp->ah_rifs_enabled); 4645250003Sadrian } 4646250003Sadrian 4647250003Sadrian#if ATH_SUPPORT_MCI 4648250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4649250008Sadrian ar9300_mci_reset(ah, AH_FALSE, IS_CHAN_2GHZ(ichan), save_full_sleep); 4650250003Sadrian } 4651250003Sadrian#endif 4652250003Sadrian 4653250003Sadrian /* Initialize Management Frame Protection */ 4654250003Sadrian ar9300_init_mfp(ah); 4655250003Sadrian 4656250003Sadrian ahp->ah_immunity_vals[0] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4657250003Sadrian AR_PHY_SFCORR_LOW_M1_THRESH_LOW); 4658250003Sadrian ahp->ah_immunity_vals[1] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4659250003Sadrian AR_PHY_SFCORR_LOW_M2_THRESH_LOW); 4660250003Sadrian ahp->ah_immunity_vals[2] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4661250003Sadrian AR_PHY_SFCORR_M1_THRESH); 4662250003Sadrian ahp->ah_immunity_vals[3] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4663250003Sadrian AR_PHY_SFCORR_M2_THRESH); 4664250003Sadrian ahp->ah_immunity_vals[4] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4665250003Sadrian AR_PHY_SFCORR_M2COUNT_THR); 4666250003Sadrian ahp->ah_immunity_vals[5] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4667250003Sadrian AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW); 4668250003Sadrian 4669250003Sadrian /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ 4670250008Sadrian if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) { 4671250008Sadrian ar9300_set_delta_slope(ah, chan); 4672250003Sadrian } 4673250003Sadrian 4674250003Sadrian ar9300_spur_mitigate(ah, chan); 4675250008Sadrian if (!ar9300_eeprom_set_board_values(ah, chan)) { 4676250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4677250003Sadrian "%s: error setting board options\n", __func__); 4678250003Sadrian FAIL(HAL_EIO); 4679250003Sadrian } 4680250003Sadrian 4681250003Sadrian#ifdef ATH_HAL_WAR_REG16284_APH128 4682250003Sadrian /* temp work around, will be removed. */ 4683250003Sadrian if (AR_SREV_WASP(ah)) { 4684250003Sadrian OS_REG_WRITE(ah, 0x16284, 0x1553e000); 4685250003Sadrian } 4686250003Sadrian#endif 4687250003Sadrian 4688250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4689250003Sadrian 4690250003Sadrian OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); 4691250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) 4692250003Sadrian | mac_sta_id1 4693250003Sadrian | AR_STA_ID1_RTS_USE_DEF 4694250008Sadrian | (ah->ah_config.ath_hal_6mb_ack ? AR_STA_ID1_ACKCTS_6MB : 0) 4695250003Sadrian | ahp->ah_sta_id1_defaults 4696250003Sadrian ); 4697250003Sadrian ar9300_set_operating_mode(ah, opmode); 4698250003Sadrian 4699250003Sadrian /* Set Venice BSSID mask according to current state */ 4700250003Sadrian OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssid_mask)); 4701250003Sadrian OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssid_mask + 4)); 4702250003Sadrian 4703250003Sadrian /* Restore previous antenna */ 4704250003Sadrian OS_REG_WRITE(ah, AR_DEF_ANTENNA, save_def_antenna); 4705250003Sadrian#ifdef ATH_FORCE_PPM 4706250003Sadrian /* Restore force ppm state */ 4707250003Sadrian tmp_reg = OS_REG_READ(ah, AR_PHY_TIMING2) & 4708250003Sadrian ~(AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL); 4709250003Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING2, tmp_reg | save_force_val); 4710250003Sadrian#endif 4711250003Sadrian 4712250003Sadrian /* then our BSSID and assocID */ 4713250003Sadrian OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 4714250003Sadrian OS_REG_WRITE(ah, AR_BSS_ID1, 4715250003Sadrian LE_READ_2(ahp->ah_bssid + 4) | 4716250003Sadrian ((ahp->ah_assoc_id & 0x3fff) << AR_BSS_ID1_AID_S)); 4717250003Sadrian 4718250003Sadrian OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ 4719250003Sadrian 4720250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR); 4721250003Sadrian 4722250003Sadrian /* HW beacon processing */ 4723250008Sadrian /* 4724250008Sadrian * XXX what happens if I just leave filter_interval=0? 4725250008Sadrian * it stays disabled? 4726250008Sadrian */ 4727250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_BCN_WEIGHT, 4728250003Sadrian INIT_RSSI_BEACON_WEIGHT); 4729250003Sadrian OS_REG_SET_BIT(ah, AR_HWBCNPROC1, AR_HWBCNPROC1_CRC_ENABLE | 4730250003Sadrian AR_HWBCNPROC1_EXCLUDE_TIM_ELM); 4731250008Sadrian if (ah->ah_config.ath_hal_beacon_filter_interval) { 4732250003Sadrian OS_REG_RMW_FIELD(ah, AR_HWBCNPROC2, AR_HWBCNPROC2_FILTER_INTERVAL, 4733250008Sadrian ah->ah_config.ath_hal_beacon_filter_interval); 4734250003Sadrian OS_REG_SET_BIT(ah, AR_HWBCNPROC2, 4735250003Sadrian AR_HWBCNPROC2_FILTER_INTERVAL_ENABLE); 4736250003Sadrian } 4737250003Sadrian 4738250003Sadrian 4739250003Sadrian /* 4740250003Sadrian * Set Channel now modifies bank 6 parameters for FOWL workaround 4741250003Sadrian * to force rf_pwd_icsyndiv bias current as function of synth 4742250003Sadrian * frequency.Thus must be called after ar9300_process_ini() to ensure 4743250003Sadrian * analog register cache is valid. 4744250003Sadrian */ 4745250008Sadrian if (!ahp->ah_rf_hal.set_channel(ah, chan)) { 4746250003Sadrian FAIL(HAL_EIO); 4747250003Sadrian } 4748250003Sadrian 4749250003Sadrian 4750250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4751250003Sadrian 4752250003Sadrian /* Set 1:1 QCU to DCU mapping for all queues */ 4753250003Sadrian for (i = 0; i < AR_NUM_DCU; i++) { 4754250003Sadrian OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); 4755250003Sadrian } 4756250003Sadrian 4757250003Sadrian ahp->ah_intr_txqs = 0; 4758250008Sadrian for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) { 4759250003Sadrian ar9300_reset_tx_queue(ah, i); 4760250003Sadrian } 4761250003Sadrian 4762250003Sadrian ar9300_init_interrupt_masks(ah, opmode); 4763250003Sadrian 4764250003Sadrian /* Reset ier reference count to disabled */ 4765250008Sadrian// OS_ATOMIC_SET(&ahp->ah_ier_ref_count, 1); 4766250003Sadrian if (ath_hal_isrfkillenabled(ah)) { 4767250003Sadrian ar9300_enable_rf_kill(ah); 4768250003Sadrian } 4769250003Sadrian 4770250003Sadrian /* must be called AFTER ini is processed */ 4771250003Sadrian ar9300_ani_init_defaults(ah, macmode); 4772250003Sadrian 4773250003Sadrian ar9300_init_qos(ah); 4774250003Sadrian 4775250003Sadrian ar9300_init_user_settings(ah); 4776250003Sadrian 4777250003Sadrian 4778250003Sadrian AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ 4779250003Sadrian 4780250003Sadrian OS_MARK(ah, AH_MARK_RESET_DONE, 0); 4781250003Sadrian 4782250003Sadrian /* 4783250003Sadrian * disable seq number generation in hw 4784250003Sadrian */ 4785250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, 4786250003Sadrian OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); 4787250003Sadrian 4788250003Sadrian ar9300_set_dma(ah); 4789250003Sadrian 4790250003Sadrian /* 4791250003Sadrian * program OBS bus to see MAC interrupts 4792250003Sadrian */ 4793250003Sadrian#if ATH_SUPPORT_MCI 4794250008Sadrian if (!AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4795250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8); 4796250003Sadrian } 4797250003Sadrian#else 4798250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8); 4799250003Sadrian#endif 4800250003Sadrian 4801250003Sadrian 4802250003Sadrian /* enabling AR_GTTM_IGNORE_IDLE in GTTM register so that 4803250003Sadrian GTT timer will not increment if the channel idle indicates 4804250003Sadrian the air is busy or NAV is still counting down */ 4805250003Sadrian OS_REG_WRITE(ah, AR_GTTM, AR_GTTM_IGNORE_IDLE); 4806250003Sadrian 4807250003Sadrian /* 4808250003Sadrian * GTT debug mode setting 4809250003Sadrian */ 4810250003Sadrian /* 4811250003Sadrian OS_REG_WRITE(ah, 0x64, 0x00320000); 4812250003Sadrian OS_REG_WRITE(ah, 0x68, 7); 4813250003Sadrian OS_REG_WRITE(ah, 0x4080, 0xC); 4814250003Sadrian */ 4815250003Sadrian /* 4816250003Sadrian * Disable general interrupt mitigation by setting MIRT = 0x0 4817250003Sadrian * Rx and tx interrupt mitigation are conditionally enabled below. 4818250003Sadrian */ 4819250003Sadrian OS_REG_WRITE(ah, AR_MIRT, 0); 4820250003Sadrian if (ahp->ah_intr_mitigation_rx) { 4821250003Sadrian /* 4822250003Sadrian * Enable Interrupt Mitigation for Rx. 4823250003Sadrian * If no build-specific limits for the rx interrupt mitigation 4824250003Sadrian * timer have been specified, use conservative defaults. 4825250003Sadrian */ 4826250003Sadrian #ifndef AH_RIMT_VAL_LAST 4827250003Sadrian #define AH_RIMT_LAST_MICROSEC 500 4828250003Sadrian #endif 4829250003Sadrian #ifndef AH_RIMT_VAL_FIRST 4830250003Sadrian #define AH_RIMT_FIRST_MICROSEC 2000 4831250003Sadrian #endif 4832250003Sadrian#ifndef HOST_OFFLOAD 4833250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, AH_RIMT_LAST_MICROSEC); 4834250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, AH_RIMT_FIRST_MICROSEC); 4835250003Sadrian#else 4836250003Sadrian /* lower mitigation level to reduce latency for offload arch. */ 4837250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 4838250003Sadrian (AH_RIMT_LAST_MICROSEC >> 2)); 4839250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 4840250003Sadrian (AH_RIMT_FIRST_MICROSEC >> 2)); 4841250003Sadrian#endif 4842250003Sadrian } 4843250003Sadrian 4844250003Sadrian if (ahp->ah_intr_mitigation_tx) { 4845250003Sadrian /* 4846250003Sadrian * Enable Interrupt Mitigation for Tx. 4847250003Sadrian * If no build-specific limits for the tx interrupt mitigation 4848250003Sadrian * timer have been specified, use the values preferred for 4849250003Sadrian * the carrier group's products. 4850250003Sadrian */ 4851250003Sadrian #ifndef AH_TIMT_LAST 4852250003Sadrian #define AH_TIMT_LAST_MICROSEC 300 4853250003Sadrian #endif 4854250003Sadrian #ifndef AH_TIMT_FIRST 4855250003Sadrian #define AH_TIMT_FIRST_MICROSEC 750 4856250003Sadrian #endif 4857250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, AH_TIMT_LAST_MICROSEC); 4858250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, AH_TIMT_FIRST_MICROSEC); 4859250003Sadrian } 4860250003Sadrian 4861250003Sadrian rx_chainmask = ahp->ah_rx_chainmask; 4862250003Sadrian 4863250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 4864250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 4865250003Sadrian 4866250003Sadrian ar9300_init_bb(ah, chan); 4867250003Sadrian 4868250003Sadrian /* BB Step 7: Calibration */ 4869250003Sadrian ar9300_invalidate_saved_cals(ah, ichan); 4870250003Sadrian cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); 4871250003Sadrian 4872250003Sadrian#if ATH_SUPPORT_MCI 4873250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { 4874250008Sadrian if (IS_CHAN_2GHZ(ichan) && 4875250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_SLEEP)) 4876250003Sadrian { 4877250003Sadrian if (ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || 4878250003Sadrian ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) 4879250003Sadrian { 4880250003Sadrian /* 4881250003Sadrian * BT is sleeping. Check if BT wakes up duing WLAN 4882250003Sadrian * calibration. If BT wakes up during WLAN calibration, need 4883250003Sadrian * to go through all message exchanges again and recal. 4884250003Sadrian */ 4885250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4886250003Sadrian "(MCI) ### %s: BT wakes up during WLAN calibration.\n", 4887250003Sadrian __func__); 4888250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 4889250003Sadrian AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | 4890250003Sadrian AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); 4891250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) send REMOTE_RESET\n"); 4892250003Sadrian ar9300_mci_remote_reset(ah, AH_TRUE); 4893250003Sadrian ar9300_mci_send_sys_waking(ah, AH_TRUE); 4894250003Sadrian OS_DELAY(1); 4895250008Sadrian if (IS_CHAN_2GHZ(ichan)) { 4896250003Sadrian ar9300_mci_send_lna_transfer(ah, AH_TRUE); 4897250003Sadrian } 4898250003Sadrian ahp->ah_mci_bt_state = MCI_BT_AWAKE; 4899250003Sadrian 4900250003Sadrian /* Redo calibration */ 4901250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Re-calibrate.\n", 4902250003Sadrian __func__); 4903250003Sadrian ar9300_invalidate_saved_cals(ah, ichan); 4904250008Sadrian cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); 4905250003Sadrian } 4906250003Sadrian } 4907250003Sadrian ar9300_mci_enable_interrupt(ah); 4908250003Sadrian } 4909250003Sadrian#endif 4910250003Sadrian 4911250003Sadrian if (!cal_ret) { 4912250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Init Cal Failed\n", __func__); 4913250003Sadrian FAIL(HAL_ESELFTEST); 4914250003Sadrian } 4915250003Sadrian 4916250003Sadrian ar9300_init_txbf(ah); 4917250003Sadrian#if 0 4918250003Sadrian /* 4919250003Sadrian * WAR for owl 1.0 - restore chain mask for 2-chain cfgs after cal 4920250003Sadrian */ 4921250003Sadrian rx_chainmask = ahp->ah_rx_chainmask; 4922250003Sadrian if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { 4923250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 4924250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 4925250003Sadrian } 4926250003Sadrian#endif 4927250003Sadrian 4928250003Sadrian /* Restore previous led state */ 4929250003Sadrian OS_REG_WRITE(ah, AR_CFG_LED, save_led_state | AR_CFG_SCLK_32KHZ); 4930250003Sadrian 4931250008Sadrian#if ATH_BT_COEX 4932250003Sadrian if (ahp->ah_bt_coex_config_type != HAL_BT_COEX_CFG_NONE) { 4933250003Sadrian ar9300_init_bt_coex(ah); 4934250003Sadrian 4935250003Sadrian#if ATH_SUPPORT_MCI 4936250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { 4937250003Sadrian /* Check BT state again to make sure it's not changed. */ 4938250003Sadrian ar9300_mci_sync_bt_state(ah); 4939250003Sadrian ar9300_mci_2g5g_switch(ah, AH_TRUE); 4940250003Sadrian 4941250003Sadrian if ((ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 4942250003Sadrian (ahp->ah_mci_query_bt == AH_TRUE)) 4943250003Sadrian { 4944250003Sadrian ahp->ah_mci_need_flush_btinfo = AH_TRUE; 4945250003Sadrian } 4946250003Sadrian } 4947250003Sadrian#endif 4948250003Sadrian } 4949250003Sadrian#endif 4950250003Sadrian 4951250003Sadrian /* Start TSF2 for generic timer 8-15. */ 4952250003Sadrian ar9300_start_tsf2(ah); 4953250003Sadrian 4954250003Sadrian /* MIMO Power save setting */ 4955250003Sadrian if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) == HAL_OK) { 4956250003Sadrian ar9300_set_sm_power_mode(ah, ahp->ah_sm_power_mode); 4957250003Sadrian } 4958250003Sadrian 4959250003Sadrian /* 4960250003Sadrian * For big endian systems turn on swapping for descriptors 4961250003Sadrian */ 4962250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 4963250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 4964250003Sadrian OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB, 0); 4965250003Sadrian } else { 4966250003Sadrian ar9300_init_cfg_reg(ah); 4967250003Sadrian } 4968250003Sadrian#endif 4969250003Sadrian 4970250003Sadrian if ( AR_SREV_OSPREY(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 4971250003Sadrian OS_REG_RMW(ah, AR_CFG_LED, AR_CFG_LED_ASSOC_CTL, AR_CFG_LED_ASSOC_CTL); 4972250003Sadrian } 4973250003Sadrian 4974250003Sadrian#if !(defined(ART_BUILD)) && defined(ATH_SUPPORT_LED) 4975250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 4976250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 4977250003Sadrian#define ATH_GPIO_OUT_FUNCTION3 0xB8040038 4978250003Sadrian#define ATH_GPIO_OE 0xB8040000 4979250003Sadrian if ( AR_SREV_WASP(ah)) { 4980250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 4981250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x33 << 8) ); 4982250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) ))); 4983250003Sadrian } 4984250003Sadrian else { 4985250003Sadrian 4986250003Sadrian /* Disable 2G WLAN LED. During ath_open, reset function is called even before channel is set. 4987250003Sadrian So 2GHz is taken as default and it also blinks. Hence 4988250003Sadrian to avoid both from blinking, disable 2G led while in 5G mode */ 4989250003Sadrian 4990250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) | (1 << 13) )); 4991250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x33) ); 4992250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) ))); 4993250003Sadrian } 4994250003Sadrian 4995250003Sadrian } 4996250003Sadrian else if (AR_SREV_SCORPION(ah)) { 4997250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 4998250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x2F << 8) ); 4999250003Sadrian REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )) | (0x1 << 12))); 5000250003Sadrian } else if (IS_CHAN_5GHZ((AH_PRIVATE(ah)->ah_curchan))) { 5001250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x2F) ); 5002250003Sadrian REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )) | (0x1 << 13))); 5003250003Sadrian } 5004250003Sadrian } 5005250003Sadrian#undef REG_READ 5006250003Sadrian#undef REG_WRITE 5007250003Sadrian#endif 5008250003Sadrian 5009250008Sadrian /* XXX FreeBSD What's this? -adrian */ 5010250008Sadrian#if 0 5011250003Sadrian chan->channel_flags = ichan->channel_flags; 5012250003Sadrian chan->priv_flags = ichan->priv_flags; 5013250008Sadrian#endif 5014250003Sadrian 5015250003Sadrian#if FIX_NOISE_FLOOR 5016250008Sadrian /* XXX FreeBSD is ichan appropariate? It was curchan.. */ 5017250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 5018250003Sadrian ar9300_load_nf(ah, nf_buf); 5019250003Sadrian if (nf_hist_buff_reset == 1) 5020250003Sadrian { 5021250003Sadrian nf_hist_buff_reset = 0; 5022250003Sadrian #ifndef ATH_NF_PER_CHAN 5023250003Sadrian if (First_NFCal(ah, ichan, is_scan, chan)){ 5024250003Sadrian } 5025250003Sadrian #endif /* ATH_NF_PER_CHAN */ 5026250003Sadrian } 5027250003Sadrian else{ 5028250003Sadrian ar9300_start_nf_cal(ah); 5029250003Sadrian } 5030250003Sadrian#endif 5031250003Sadrian 5032250003Sadrian#ifdef AH_SUPPORT_AR9300 5033250003Sadrian /* BB Panic Watchdog */ 5034250003Sadrian if (ar9300_get_capability(ah, HAL_CAP_BB_PANIC_WATCHDOG, 0, AH_NULL) == 5035250003Sadrian HAL_OK) 5036250003Sadrian { 5037250003Sadrian ar9300_config_bb_panic_watchdog(ah); 5038250003Sadrian } 5039250003Sadrian#endif 5040250003Sadrian 5041250003Sadrian /* While receiving unsupported rate frame receive state machine 5042250003Sadrian * gets into a state 0xb and if phy_restart happens when rx 5043250003Sadrian * state machine is in 0xb state, BB would go hang, if we 5044250003Sadrian * see 0xb state after first bb panic, make sure that we 5045250003Sadrian * disable the phy_restart. 5046250003Sadrian * 5047250003Sadrian * There may be multiple panics, make sure that we always do 5048250003Sadrian * this if we see this panic at least once. This is required 5049250003Sadrian * because reset seems to be writing from INI file. 5050250003Sadrian */ 5051250003Sadrian if ((ar9300_get_capability(ah, HAL_CAP_PHYRESTART_CLR_WAR, 0, AH_NULL) 5052250008Sadrian == HAL_OK) && (((MS((AH9300(ah)->ah_bb_panic_last_status), 5053250003Sadrian AR_PHY_BB_WD_RX_OFDM_SM)) == 0xb) || 5054250008Sadrian AH9300(ah)->ah_phyrestart_disabled) ) 5055250003Sadrian { 5056250003Sadrian ar9300_disable_phy_restart(ah, 1); 5057250003Sadrian } 5058250003Sadrian 5059250003Sadrian 5060250003Sadrian 5061250003Sadrian ahp->ah_radar1 = MS(OS_REG_READ(ah, AR_PHY_RADAR_1), 5062250003Sadrian AR_PHY_RADAR_1_CF_BIN_THRESH); 5063250003Sadrian ahp->ah_dc_offset = MS(OS_REG_READ(ah, AR_PHY_TIMING2), 5064250003Sadrian AR_PHY_TIMING2_DC_OFFSET); 5065250003Sadrian ahp->ah_disable_cck = MS(OS_REG_READ(ah, AR_PHY_MODE), 5066250003Sadrian AR_PHY_MODE_DISABLE_CCK); 5067250003Sadrian 5068250008Sadrian if (AH9300(ah)->ah_enable_keysearch_always) { 5069250003Sadrian ar9300_enable_keysearch_always(ah, 1); 5070250003Sadrian } 5071250003Sadrian 5072250003Sadrian#if ATH_LOW_POWER_ENABLE 5073250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val) 5074250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 5075250003Sadrian if (AR_SREV_OSPREY(ah)) { 5076250003Sadrian REG_WRITE(0xb4000080, REG_READ(0xb4000080) | 3); 5077250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 5078250003Sadrian OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), 5079250003Sadrian AR_PCIE_PM_CTRL_ENA); 5080250003Sadrian OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_SPARE), 0xffffffff); 5081250003Sadrian } 5082250003Sadrian#undef REG_READ 5083250003Sadrian#undef REG_WRITE 5084250003Sadrian#endif /* ATH_LOW_POWER_ENABLE */ 5085250003Sadrian 5086250003Sadrian WAR_USB_DISABLE_PLL_LOCK_DETECT(ah); 5087250003Sadrian 5088250003Sadrian /* H/W Green TX */ 5089250003Sadrian ar9300_control_signals_for_green_tx_mode(ah); 5090250003Sadrian /* Smart Antenna, only for 5GHz on Scropion */ 5091250008Sadrian if (IEEE80211_IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan)) && AR_SREV_SCORPION(ah)) { 5092250003Sadrian ahp->ah_smartantenna_enable = 0; 5093250003Sadrian } 5094250003Sadrian 5095250003Sadrian ar9300_set_smart_antenna(ah, ahp->ah_smartantenna_enable); 5096250003Sadrian 5097250003Sadrian 5098250003Sadrian return AH_TRUE; 5099250003Sadrianbad: 5100250003Sadrian OS_MARK(ah, AH_MARK_RESET_DONE, ecode); 5101250003Sadrian *status = ecode; 5102250003Sadrian 5103250003Sadrian return AH_FALSE; 5104250003Sadrian#undef FAIL 5105250003Sadrian} 5106250003Sadrian 5107250003Sadrianvoid 5108250003Sadrianar9300_green_ap_ps_on_off( struct ath_hal *ah, u_int16_t on_off) 5109250003Sadrian{ 5110250003Sadrian /* Set/reset the ps flag */ 5111250008Sadrian AH9300(ah)->green_ap_ps_on = !!on_off; 5112250003Sadrian} 5113250003Sadrian 5114250003Sadrian/* 5115250003Sadrian * This function returns 1, where it is possible to do 5116250003Sadrian * single-chain power save. 5117250003Sadrian */ 5118250003Sadrianu_int16_t 5119250003Sadrianar9300_is_single_ant_power_save_possible(struct ath_hal *ah) 5120250003Sadrian{ 5121250003Sadrian return AH_TRUE; 5122250003Sadrian} 5123250003Sadrian 5124250003Sadrian/* To avoid compilation warnings. Functions not used when EMULATION. */ 5125250003Sadrian/* 5126250003Sadrian * ar9300_find_mag_approx() 5127250003Sadrian */ 5128250003Sadrianstatic int32_t 5129250003Sadrianar9300_find_mag_approx(struct ath_hal *ah, int32_t in_re, int32_t in_im) 5130250003Sadrian{ 5131250003Sadrian int32_t abs_i = abs(in_re); 5132250003Sadrian int32_t abs_q = abs(in_im); 5133250003Sadrian int32_t max_abs, min_abs; 5134250003Sadrian 5135250003Sadrian if (abs_i > abs_q) { 5136250003Sadrian max_abs = abs_i; 5137250003Sadrian min_abs = abs_q; 5138250003Sadrian } else { 5139250003Sadrian max_abs = abs_q; 5140250003Sadrian min_abs = abs_i; 5141250003Sadrian } 5142250003Sadrian 5143250003Sadrian return (max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4)); 5144250003Sadrian} 5145250003Sadrian 5146250003Sadrian/* 5147250003Sadrian * ar9300_solve_iq_cal() 5148250003Sadrian * solve 4x4 linear equation used in loopback iq cal. 5149250003Sadrian */ 5150250003Sadrianstatic HAL_BOOL 5151250003Sadrianar9300_solve_iq_cal( 5152250003Sadrian struct ath_hal *ah, 5153250003Sadrian int32_t sin_2phi_1, 5154250003Sadrian int32_t cos_2phi_1, 5155250003Sadrian int32_t sin_2phi_2, 5156250003Sadrian int32_t cos_2phi_2, 5157250003Sadrian int32_t mag_a0_d0, 5158250003Sadrian int32_t phs_a0_d0, 5159250003Sadrian int32_t mag_a1_d0, 5160250003Sadrian int32_t phs_a1_d0, 5161250003Sadrian int32_t solved_eq[]) 5162250003Sadrian{ 5163250003Sadrian int32_t f1 = cos_2phi_1 - cos_2phi_2; 5164250003Sadrian int32_t f3 = sin_2phi_1 - sin_2phi_2; 5165250003Sadrian int32_t f2; 5166250003Sadrian int32_t mag_tx, phs_tx, mag_rx, phs_rx; 5167250003Sadrian const int32_t result_shift = 1 << 15; 5168250003Sadrian 5169250003Sadrian f2 = (((int64_t)f1 * (int64_t)f1) / result_shift) + (((int64_t)f3 * (int64_t)f3) / result_shift); 5170250003Sadrian 5171250003Sadrian if (0 == f2) { 5172250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d).\n", 5173250003Sadrian __func__, __LINE__); 5174250003Sadrian return AH_FALSE; 5175250003Sadrian } 5176250003Sadrian 5177250003Sadrian /* magnitude mismatch, tx */ 5178250003Sadrian mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0); 5179250003Sadrian /* phase mismatch, tx */ 5180250003Sadrian phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0); 5181250003Sadrian 5182250003Sadrian mag_tx = (mag_tx / f2); 5183250003Sadrian phs_tx = (phs_tx / f2); 5184250003Sadrian 5185250003Sadrian /* magnitude mismatch, rx */ 5186250003Sadrian mag_rx = 5187250003Sadrian mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / result_shift; 5188250003Sadrian /* phase mismatch, rx */ 5189250003Sadrian phs_rx = 5190250003Sadrian phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / result_shift; 5191250003Sadrian 5192250003Sadrian solved_eq[0] = mag_tx; 5193250003Sadrian solved_eq[1] = phs_tx; 5194250003Sadrian solved_eq[2] = mag_rx; 5195250003Sadrian solved_eq[3] = phs_rx; 5196250003Sadrian 5197250003Sadrian return AH_TRUE; 5198250003Sadrian} 5199250003Sadrian 5200250003Sadrian/* 5201250003Sadrian * ar9300_calc_iq_corr() 5202250003Sadrian */ 5203250003Sadrianstatic HAL_BOOL 5204250003Sadrianar9300_calc_iq_corr(struct ath_hal *ah, int32_t chain_idx, 5205250003Sadrian const int32_t iq_res[], int32_t iqc_coeff[]) 5206250003Sadrian{ 5207250003Sadrian int32_t i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0; 5208250003Sadrian int32_t i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1; 5209250003Sadrian int32_t i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0; 5210250003Sadrian int32_t i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1; 5211250003Sadrian int32_t mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1; 5212250003Sadrian int32_t phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1; 5213250003Sadrian int32_t sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2; 5214250003Sadrian int32_t mag_tx, phs_tx, mag_rx, phs_rx; 5215250003Sadrian int32_t solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx; 5216250003Sadrian int32_t q_q_coff, q_i_coff; 5217250003Sadrian const int32_t res_scale = 1 << 15; 5218250003Sadrian const int32_t delpt_shift = 1 << 8; 5219250003Sadrian int32_t mag1, mag2; 5220250003Sadrian 5221250003Sadrian i2_m_q2_a0_d0 = iq_res[0] & 0xfff; 5222250003Sadrian i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff; 5223250003Sadrian iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8); 5224250003Sadrian 5225250003Sadrian if (i2_m_q2_a0_d0 > 0x800) { 5226250003Sadrian i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1); 5227250003Sadrian } 5228250003Sadrian if (iq_corr_a0_d0 > 0x800) { 5229250003Sadrian iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1); 5230250003Sadrian } 5231250003Sadrian 5232250003Sadrian i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff; 5233250003Sadrian i2_p_q2_a0_d1 = (iq_res[2] & 0xfff); 5234250003Sadrian iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff; 5235250003Sadrian 5236250003Sadrian if (i2_m_q2_a0_d1 > 0x800) { 5237250003Sadrian i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); 5238250003Sadrian } 5239250003Sadrian if (iq_corr_a0_d1 > 0x800) { 5240250003Sadrian iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); 5241250003Sadrian } 5242250003Sadrian 5243250003Sadrian i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8); 5244250003Sadrian i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff; 5245250003Sadrian iq_corr_a1_d0 = iq_res[4] & 0xfff; 5246250003Sadrian 5247250003Sadrian if (i2_m_q2_a1_d0 > 0x800) { 5248250003Sadrian i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1); 5249250003Sadrian } 5250250003Sadrian if (iq_corr_a1_d0 > 0x800) { 5251250003Sadrian iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1); 5252250003Sadrian } 5253250003Sadrian 5254250003Sadrian i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff; 5255250003Sadrian i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8); 5256250003Sadrian iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff; 5257250003Sadrian 5258250003Sadrian if (i2_m_q2_a1_d1 > 0x800) { 5259250003Sadrian i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1); 5260250003Sadrian } 5261250003Sadrian if (iq_corr_a1_d1 > 0x800) { 5262250003Sadrian iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1); 5263250003Sadrian } 5264250003Sadrian 5265250003Sadrian if ((i2_p_q2_a0_d0 == 0) || 5266250003Sadrian (i2_p_q2_a0_d1 == 0) || 5267250003Sadrian (i2_p_q2_a1_d0 == 0) || 5268250003Sadrian (i2_p_q2_a1_d1 == 0)) { 5269250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5270250003Sadrian "%s: Divide by 0(%d):\na0_d0=%d\na0_d1=%d\na2_d0=%d\na1_d1=%d\n", 5271250003Sadrian __func__, __LINE__, 5272250003Sadrian i2_p_q2_a0_d0, i2_p_q2_a0_d1, i2_p_q2_a1_d0, i2_p_q2_a1_d1); 5273250003Sadrian return AH_FALSE; 5274250003Sadrian } 5275250003Sadrian 5276250003Sadrian if ((i2_p_q2_a0_d0 <= 1024) || (i2_p_q2_a0_d0 > 2047) || 5277250003Sadrian (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) || 5278250003Sadrian (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) || 5279250003Sadrian (i2_p_q2_a0_d0 <= iq_corr_a0_d0) || 5280250003Sadrian (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) || 5281250003Sadrian (i2_p_q2_a0_d1 <= iq_corr_a0_d1) || 5282250003Sadrian (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) || 5283250003Sadrian (i2_p_q2_a1_d0 <= iq_corr_a1_d0) || 5284250003Sadrian (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) || 5285250003Sadrian (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) { 5286250003Sadrian return AH_FALSE; 5287250003Sadrian } 5288250003Sadrian 5289250003Sadrian mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; 5290250003Sadrian phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; 5291250003Sadrian 5292250003Sadrian mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1; 5293250003Sadrian phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1; 5294250003Sadrian 5295250003Sadrian mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0; 5296250003Sadrian phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0; 5297250003Sadrian 5298250003Sadrian mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1; 5299250003Sadrian phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1; 5300250003Sadrian 5301250003Sadrian /* without analog phase shift */ 5302250003Sadrian sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT); 5303250003Sadrian /* without analog phase shift */ 5304250003Sadrian cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT); 5305250003Sadrian /* with analog phase shift */ 5306250003Sadrian sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT); 5307250003Sadrian /* with analog phase shift */ 5308250003Sadrian cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT); 5309250003Sadrian 5310250003Sadrian /* force sin^2 + cos^2 = 1; */ 5311250003Sadrian /* find magnitude by approximation */ 5312250003Sadrian mag1 = ar9300_find_mag_approx(ah, cos_2phi_1, sin_2phi_1); 5313250003Sadrian mag2 = ar9300_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); 5314250003Sadrian 5315250003Sadrian if ((mag1 == 0) || (mag2 == 0)) { 5316250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5317250003Sadrian "%s: Divide by 0(%d): mag1=%d, mag2=%d\n", 5318250003Sadrian __func__, __LINE__, mag1, mag2); 5319250003Sadrian return AH_FALSE; 5320250003Sadrian } 5321250003Sadrian 5322250003Sadrian /* normalization sin and cos by mag */ 5323250003Sadrian sin_2phi_1 = (sin_2phi_1 * res_scale / mag1); 5324250003Sadrian cos_2phi_1 = (cos_2phi_1 * res_scale / mag1); 5325250003Sadrian sin_2phi_2 = (sin_2phi_2 * res_scale / mag2); 5326250003Sadrian cos_2phi_2 = (cos_2phi_2 * res_scale / mag2); 5327250003Sadrian 5328250003Sadrian /* calculate IQ mismatch */ 5329250008Sadrian if (AH_FALSE == ar9300_solve_iq_cal(ah, 5330250003Sadrian sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2, mag_a0_d0, 5331250003Sadrian phs_a0_d0, mag_a1_d0, phs_a1_d0, solved_eq)) 5332250003Sadrian { 5333250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5334250003Sadrian "%s: Call to ar9300_solve_iq_cal failed.\n", __func__); 5335250003Sadrian return AH_FALSE; 5336250003Sadrian } 5337250003Sadrian 5338250003Sadrian mag_tx = solved_eq[0]; 5339250003Sadrian phs_tx = solved_eq[1]; 5340250003Sadrian mag_rx = solved_eq[2]; 5341250003Sadrian phs_rx = solved_eq[3]; 5342250003Sadrian 5343250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5344250003Sadrian "%s: chain %d: mag mismatch=%d phase mismatch=%d\n", 5345250003Sadrian __func__, chain_idx, mag_tx / res_scale, phs_tx / res_scale); 5346250003Sadrian 5347250003Sadrian if (res_scale == mag_tx) { 5348250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5349250003Sadrian "%s: Divide by 0(%d): mag_tx=%d, res_scale=%d\n", 5350250003Sadrian __func__, __LINE__, mag_tx, res_scale); 5351250003Sadrian return AH_FALSE; 5352250003Sadrian } 5353250003Sadrian 5354250003Sadrian /* calculate and quantize Tx IQ correction factor */ 5355250003Sadrian mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx); 5356250003Sadrian phs_corr_tx = -phs_tx; 5357250003Sadrian 5358250003Sadrian q_q_coff = (mag_corr_tx * 128 / res_scale); 5359250003Sadrian q_i_coff = (phs_corr_tx * 256 / res_scale); 5360250003Sadrian 5361250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5362250003Sadrian "%s: tx chain %d: mag corr=%d phase corr=%d\n", 5363250003Sadrian __func__, chain_idx, q_q_coff, q_i_coff); 5364250003Sadrian 5365250003Sadrian if (q_i_coff < -63) { 5366250003Sadrian q_i_coff = -63; 5367250003Sadrian } 5368250003Sadrian if (q_i_coff > 63) { 5369250003Sadrian q_i_coff = 63; 5370250003Sadrian } 5371250003Sadrian if (q_q_coff < -63) { 5372250003Sadrian q_q_coff = -63; 5373250003Sadrian } 5374250003Sadrian if (q_q_coff > 63) { 5375250003Sadrian q_q_coff = 63; 5376250003Sadrian } 5377250003Sadrian 5378250003Sadrian iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); 5379250003Sadrian 5380250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: tx chain %d: iq corr coeff=%x\n", 5381250003Sadrian __func__, chain_idx, iqc_coeff[0]); 5382250003Sadrian 5383250003Sadrian if (-mag_rx == res_scale) { 5384250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5385250003Sadrian "%s: Divide by 0(%d): mag_rx=%d, res_scale=%d\n", 5386250003Sadrian __func__, __LINE__, mag_rx, res_scale); 5387250003Sadrian return AH_FALSE; 5388250003Sadrian } 5389250003Sadrian 5390250003Sadrian /* calculate and quantize Rx IQ correction factors */ 5391250003Sadrian mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx); 5392250003Sadrian phs_corr_rx = -phs_rx; 5393250003Sadrian 5394250003Sadrian q_q_coff = (mag_corr_rx * 128 / res_scale); 5395250003Sadrian q_i_coff = (phs_corr_rx * 256 / res_scale); 5396250003Sadrian 5397250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5398250003Sadrian "%s: rx chain %d: mag corr=%d phase corr=%d\n", 5399250003Sadrian __func__, chain_idx, q_q_coff, q_i_coff); 5400250003Sadrian 5401250003Sadrian if (q_i_coff < -63) { 5402250003Sadrian q_i_coff = -63; 5403250003Sadrian } 5404250003Sadrian if (q_i_coff > 63) { 5405250003Sadrian q_i_coff = 63; 5406250003Sadrian } 5407250003Sadrian if (q_q_coff < -63) { 5408250003Sadrian q_q_coff = -63; 5409250003Sadrian } 5410250003Sadrian if (q_q_coff > 63) { 5411250003Sadrian q_q_coff = 63; 5412250003Sadrian } 5413250003Sadrian 5414250003Sadrian iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); 5415250003Sadrian 5416250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: rx chain %d: iq corr coeff=%x\n", 5417250003Sadrian __func__, chain_idx, iqc_coeff[1]); 5418250003Sadrian 5419250003Sadrian return AH_TRUE; 5420250003Sadrian} 5421250003Sadrian 5422250003Sadrian#define MAX_MAG_DELTA 11 //maximum magnitude mismatch delta across gains 5423250003Sadrian#define MAX_PHS_DELTA 10 //maximum phase mismatch delta across gains 5424250003Sadrian#define ABS(x) ((x) >= 0 ? (x) : (-(x))) 5425250003Sadrian 5426250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5427250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5428250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5429250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5430250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5431250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5432250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5433250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5434250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5435250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5436250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5437250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5438250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5439250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5440250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5441250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5442250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5443250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5444250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5445250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5446250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5447250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5448250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5449250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5450250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5451250003Sadrian }; 5452250003Sadrian 5453250003Sadrianstatic void 5454250003Sadrianar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, u_int32_t num_chains, 5455250008Sadrian struct coeff_t *coeff, HAL_BOOL is_cal_reusable) 5456250003Sadrian{ 5457250003Sadrian int nmeasurement, ch_idx, im; 5458250003Sadrian int32_t magnitude, phase; 5459250003Sadrian int32_t magnitude_max, phase_max; 5460250003Sadrian int32_t magnitude_min, phase_min; 5461250003Sadrian 5462250003Sadrian int32_t magnitude_max_idx, phase_max_idx; 5463250003Sadrian int32_t magnitude_min_idx, phase_min_idx; 5464250003Sadrian 5465250003Sadrian int32_t magnitude_avg, phase_avg; 5466250003Sadrian int32_t outlier_mag_idx = 0; 5467250003Sadrian int32_t outlier_phs_idx = 0; 5468250003Sadrian 5469250003Sadrian 5470250003Sadrian if (AR_SREV_POSEIDON(ah)) { 5471250003Sadrian HALASSERT(num_chains == 0x1); 5472250003Sadrian 5473250003Sadrian tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5474250003Sadrian tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5475250003Sadrian tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5476250003Sadrian tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5477250003Sadrian tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5478250003Sadrian tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5479250003Sadrian tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5480250003Sadrian tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5481250003Sadrian } 5482250003Sadrian 5483250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5484250003Sadrian nmeasurement = OS_REG_READ_FIELD(ah, 5485250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); 5486250003Sadrian if (nmeasurement > MAX_MEASUREMENT) { 5487250003Sadrian nmeasurement = MAX_MEASUREMENT; 5488250003Sadrian } 5489250003Sadrian 5490250003Sadrian if (!AR_SREV_SCORPION(ah)) { 5491250003Sadrian /* 5492250003Sadrian * reset max/min variable to min/max values so that 5493250003Sadrian * we always start with 1st calibrated gain value 5494250003Sadrian */ 5495250003Sadrian magnitude_max = -64; 5496250003Sadrian phase_max = -64; 5497250003Sadrian magnitude_min = 63; 5498250003Sadrian phase_min = 63; 5499250003Sadrian magnitude_avg = 0; 5500250003Sadrian phase_avg = 0; 5501250003Sadrian magnitude_max_idx = 0; 5502250003Sadrian magnitude_min_idx = 0; 5503250003Sadrian phase_max_idx = 0; 5504250003Sadrian phase_min_idx = 0; 5505250003Sadrian 5506250003Sadrian /* detect outlier only if nmeasurement > 1 */ 5507250003Sadrian if (nmeasurement > 1) { 5508250003Sadrian /* printf("----------- start outlier detection -----------\n"); */ 5509250003Sadrian /* 5510250003Sadrian * find max/min and phase/mag mismatch across all calibrated gains 5511250003Sadrian */ 5512250003Sadrian for (im = 0; im < nmeasurement; im++) { 5513250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5514250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5515250003Sadrian 5516250003Sadrian magnitude_avg = magnitude_avg + magnitude; 5517250003Sadrian phase_avg = phase_avg + phase; 5518250003Sadrian if (magnitude > magnitude_max) { 5519250003Sadrian magnitude_max = magnitude; 5520250003Sadrian magnitude_max_idx = im; 5521250003Sadrian } 5522250003Sadrian if (magnitude < magnitude_min) { 5523250003Sadrian magnitude_min = magnitude; 5524250003Sadrian magnitude_min_idx = im; 5525250003Sadrian } 5526250003Sadrian if (phase > phase_max) { 5527250003Sadrian phase_max = phase; 5528250003Sadrian phase_max_idx = im; 5529250003Sadrian } 5530250003Sadrian if (phase < phase_min) { 5531250003Sadrian phase_min = phase; 5532250003Sadrian phase_min_idx = im; 5533250003Sadrian } 5534250003Sadrian } 5535250003Sadrian /* find average (exclude max abs value) */ 5536250003Sadrian for (im = 0; im < nmeasurement; im++) { 5537250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5538250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5539250003Sadrian if ((ABS(magnitude) < ABS(magnitude_max)) || 5540250003Sadrian (ABS(magnitude) < ABS(magnitude_min))) 5541250003Sadrian { 5542250003Sadrian magnitude_avg = magnitude_avg + magnitude; 5543250003Sadrian } 5544250003Sadrian if ((ABS(phase) < ABS(phase_max)) || 5545250003Sadrian (ABS(phase) < ABS(phase_min))) 5546250003Sadrian { 5547250003Sadrian phase_avg = phase_avg + phase; 5548250003Sadrian } 5549250003Sadrian } 5550250003Sadrian magnitude_avg = magnitude_avg / (nmeasurement - 1); 5551250003Sadrian phase_avg = phase_avg / (nmeasurement - 1); 5552250003Sadrian 5553250003Sadrian /* detect magnitude outlier */ 5554250003Sadrian if (ABS(magnitude_max - magnitude_min) > MAX_MAG_DELTA) { 5555250003Sadrian if (ABS(magnitude_max - magnitude_avg) > 5556250003Sadrian ABS(magnitude_min - magnitude_avg)) 5557250003Sadrian { 5558250003Sadrian /* max is outlier, force to avg */ 5559250003Sadrian outlier_mag_idx = magnitude_max_idx; 5560250003Sadrian } else { 5561250003Sadrian /* min is outlier, force to avg */ 5562250003Sadrian outlier_mag_idx = magnitude_min_idx; 5563250003Sadrian } 5564250003Sadrian coeff->mag_coeff[ch_idx][outlier_mag_idx][0] = magnitude_avg; 5565250003Sadrian coeff->phs_coeff[ch_idx][outlier_mag_idx][0] = phase_avg; 5566250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5567250003Sadrian "[ch%d][outlier mag gain%d]:: " 5568250003Sadrian "mag_avg = %d (/128), phase_avg = %d (/256)\n", 5569250003Sadrian ch_idx, outlier_mag_idx, magnitude_avg, phase_avg); 5570250003Sadrian } 5571250003Sadrian /* detect phase outlier */ 5572250003Sadrian if (ABS(phase_max - phase_min) > MAX_PHS_DELTA) { 5573250003Sadrian if (ABS(phase_max-phase_avg) > ABS(phase_min - phase_avg)) { 5574250003Sadrian /* max is outlier, force to avg */ 5575250003Sadrian outlier_phs_idx = phase_max_idx; 5576250003Sadrian } else{ 5577250003Sadrian /* min is outlier, force to avg */ 5578250003Sadrian outlier_phs_idx = phase_min_idx; 5579250003Sadrian } 5580250003Sadrian coeff->mag_coeff[ch_idx][outlier_phs_idx][0] = magnitude_avg; 5581250003Sadrian coeff->phs_coeff[ch_idx][outlier_phs_idx][0] = phase_avg; 5582250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5583250003Sadrian "[ch%d][outlier phs gain%d]:: " 5584250003Sadrian "mag_avg = %d (/128), phase_avg = %d (/256)\n", 5585250003Sadrian ch_idx, outlier_phs_idx, magnitude_avg, phase_avg); 5586250003Sadrian } 5587250003Sadrian } 5588250003Sadrian } 5589250003Sadrian 5590250003Sadrian /*printf("------------ after outlier detection -------------\n");*/ 5591250003Sadrian for (im = 0; im < nmeasurement; im++) { 5592250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5593250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5594250003Sadrian 5595250003Sadrian #if 0 5596250003Sadrian printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n", 5597250003Sadrian ch_idx, im, magnitude, phase); 5598250003Sadrian #endif 5599250003Sadrian 5600250003Sadrian coeff->iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7); 5601250003Sadrian 5602250003Sadrian if ((im % 2) == 0) { 5603250003Sadrian OS_REG_RMW_FIELD(ah, 5604250003Sadrian tx_corr_coeff[im][ch_idx], 5605250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 5606250003Sadrian coeff->iqc_coeff[0]); 5607250003Sadrian } else { 5608250003Sadrian OS_REG_RMW_FIELD(ah, 5609250003Sadrian tx_corr_coeff[im][ch_idx], 5610250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 5611250003Sadrian coeff->iqc_coeff[0]); 5612250003Sadrian } 5613250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5614250003Sadrian ichan->tx_corr_coeff[im][ch_idx] = coeff->iqc_coeff[0]; 5615250003Sadrian#endif 5616250003Sadrian } 5617250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5618250003Sadrian ichan->num_measures[ch_idx] = nmeasurement; 5619250003Sadrian#endif 5620250003Sadrian } 5621250003Sadrian 5622250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 5623250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 5624250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 5625250003Sadrian AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 5626250003Sadrian 5627250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5628250003Sadrian if (is_cal_reusable) { 5629250003Sadrian ichan->one_time_txiqcal_done = AH_TRUE; 5630250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 5631250003Sadrian "(FCS) TXIQCAL saved - %d\n", ichan->channel); 5632250003Sadrian } 5633250003Sadrian#endif 5634250003Sadrian} 5635250003Sadrian 5636250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5637250003Sadrianstatic void 5638250003Sadrianar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 5639250003Sadrian{ 5640250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 5641250003Sadrian int nmeasurement, ch_idx, im; 5642250003Sadrian 5643250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5644250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5645250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5646250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5647250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5648250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5649250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5650250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5651250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5652250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5653250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5654250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5655250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5656250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5657250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5658250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5659250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5660250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5661250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5662250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5663250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5664250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5665250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5666250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5667250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5668250003Sadrian }; 5669250003Sadrian 5670250003Sadrian if (AR_SREV_POSEIDON(ah)) { 5671250003Sadrian HALASSERT(ahp->ah_tx_cal_chainmask == 0x1); 5672250003Sadrian 5673250003Sadrian tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5674250003Sadrian tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5675250003Sadrian tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5676250003Sadrian tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5677250003Sadrian tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5678250003Sadrian tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5679250003Sadrian tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5680250003Sadrian tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5681250003Sadrian } 5682250003Sadrian 5683250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 5684250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 5685250003Sadrian continue; 5686250003Sadrian } 5687250003Sadrian nmeasurement = ichan->num_measures[ch_idx]; 5688250003Sadrian 5689250003Sadrian for (im = 0; im < nmeasurement; im++) { 5690250003Sadrian if ((im % 2) == 0) { 5691250003Sadrian OS_REG_RMW_FIELD(ah, 5692250003Sadrian tx_corr_coeff[im][ch_idx], 5693250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 5694250003Sadrian ichan->tx_corr_coeff[im][ch_idx]); 5695250003Sadrian } else { 5696250003Sadrian OS_REG_RMW_FIELD(ah, 5697250003Sadrian tx_corr_coeff[im][ch_idx], 5698250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 5699250003Sadrian ichan->tx_corr_coeff[im][ch_idx]); 5700250003Sadrian } 5701250003Sadrian } 5702250003Sadrian } 5703250003Sadrian 5704250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 5705250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 5706250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 5707250003Sadrian AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 5708250003Sadrian} 5709250003Sadrian#endif 5710250003Sadrian 5711250003Sadrian/* 5712250003Sadrian * ar9300_tx_iq_cal_hw_run is only needed for osprey/wasp/hornet 5713250003Sadrian * It is not needed for jupiter/poseidon. 5714250003Sadrian */ 5715250003SadrianHAL_BOOL 5716250003Sadrianar9300_tx_iq_cal_hw_run(struct ath_hal *ah) 5717250003Sadrian{ 5718250003Sadrian int is_tx_gain_forced; 5719250003Sadrian 5720250003Sadrian is_tx_gain_forced = OS_REG_READ_FIELD(ah, 5721250003Sadrian AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE); 5722250003Sadrian if (is_tx_gain_forced) { 5723250003Sadrian /*printf("Tx gain can not be forced during tx I/Q cal!\n");*/ 5724250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0); 5725250003Sadrian } 5726250003Sadrian 5727250003Sadrian /* enable tx IQ cal */ 5728250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah), 5729250003Sadrian AR_PHY_TX_IQCAL_START_DO_CAL, AR_PHY_TX_IQCAL_START_DO_CAL); 5730250003Sadrian 5731250003Sadrian if (!ath_hal_wait(ah, 5732250008Sadrian AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 0)) 5733250003Sadrian { 5734250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5735250003Sadrian "%s: Tx IQ Cal is never completed.\n", __func__); 5736250003Sadrian return AH_FALSE; 5737250003Sadrian } 5738250003Sadrian return AH_TRUE; 5739250003Sadrian} 5740250003Sadrian 5741250003Sadrianstatic void 5742250003Sadrianar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, 5743250003Sadrian int iqcal_idx, int max_iqcal,HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr) 5744250003Sadrian{ 5745250003Sadrian int nmeasurement=0, im, ix, iy, temp; 5746250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 5747250003Sadrian u_int32_t txiqcal_status[AR9300_MAX_CHAINS] = { 5748250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), 5749250003Sadrian AR_PHY_TX_IQCAL_STATUS_B1, 5750250003Sadrian AR_PHY_TX_IQCAL_STATUS_B2, 5751250003Sadrian }; 5752250003Sadrian const u_int32_t chan_info_tab[] = { 5753250003Sadrian AR_PHY_CHAN_INFO_TAB_0, 5754250003Sadrian AR_PHY_CHAN_INFO_TAB_1, 5755250003Sadrian AR_PHY_CHAN_INFO_TAB_2, 5756250003Sadrian }; 5757250003Sadrian int32_t iq_res[6]; 5758250003Sadrian int32_t ch_idx, j; 5759250003Sadrian u_int32_t num_chains = 0; 5760250003Sadrian static struct coeff_t coeff; 5761250003Sadrian txiqcal_status[0] = AR_PHY_TX_IQCAL_STATUS_B0(ah); 5762250003Sadrian 5763250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 5764250003Sadrian if (ahp->ah_tx_chainmask & (1 << ch_idx)) { 5765250003Sadrian num_chains++; 5766250003Sadrian } 5767250003Sadrian } 5768250003Sadrian 5769250003Sadrian if (apply_last_corr) { 5770250003Sadrian if (coeff.last_cal == AH_TRUE) { 5771250003Sadrian int32_t magnitude, phase; 5772250003Sadrian int ch_idx, im; 5773250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5774250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5775250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5776250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5777250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5778250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5779250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5780250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5781250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5782250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5783250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5784250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5785250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5786250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5787250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5788250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5789250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5790250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5791250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5792250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5793250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5794250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5795250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5796250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5797250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5798250003Sadrian }; 5799250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5800250003Sadrian for (im = 0; im < coeff.last_nmeasurement; im++) { 5801250003Sadrian magnitude = coeff.mag_coeff[ch_idx][im][0]; 5802250003Sadrian phase = coeff.phs_coeff[ch_idx][im][0]; 5803250003Sadrian 5804250003Sadrian#if 0 5805250003Sadrian printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n", 5806250003Sadrian ch_idx, im, magnitude, phase); 5807250003Sadrian#endif 5808250003Sadrian 5809250003Sadrian coeff.iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7); 5810250003Sadrian if ((im % 2) == 0) { 5811250003Sadrian OS_REG_RMW_FIELD(ah, 5812250003Sadrian tx_corr_coeff[im][ch_idx], 5813250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 5814250003Sadrian coeff.iqc_coeff[0]); 5815250003Sadrian } else { 5816250003Sadrian OS_REG_RMW_FIELD(ah, 5817250003Sadrian tx_corr_coeff[im][ch_idx], 5818250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 5819250003Sadrian coeff.iqc_coeff[0]); 5820250003Sadrian } 5821250003Sadrian } 5822250003Sadrian } 5823250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 5824250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 5825250003Sadrian } 5826250003Sadrian return; 5827250003Sadrian } 5828250003Sadrian 5829250003Sadrian 5830250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5831250003Sadrian nmeasurement = OS_REG_READ_FIELD(ah, 5832250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); 5833250003Sadrian if (nmeasurement > MAX_MEASUREMENT) { 5834250003Sadrian nmeasurement = MAX_MEASUREMENT; 5835250003Sadrian } 5836250003Sadrian 5837250003Sadrian for (im = 0; im < nmeasurement; im++) { 5838250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5839250003Sadrian "%s: Doing Tx IQ Cal for chain %d.\n", __func__, ch_idx); 5840250003Sadrian if (OS_REG_READ(ah, txiqcal_status[ch_idx]) & 5841250003Sadrian AR_PHY_TX_IQCAL_STATUS_FAILED) 5842250003Sadrian { 5843250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5844250003Sadrian "%s: Tx IQ Cal failed for chain %d.\n", __func__, ch_idx); 5845250003Sadrian goto TX_IQ_CAL_FAILED_; 5846250003Sadrian } 5847250003Sadrian 5848250003Sadrian for (j = 0; j < 3; j++) { 5849250003Sadrian u_int32_t idx = 2 * j; 5850250003Sadrian /* 3 registers for each calibration result */ 5851250003Sadrian u_int32_t offset = 4 * (3 * im + j); 5852250003Sadrian 5853250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, 5854250003Sadrian AR_PHY_CHAN_INFO_TAB_S2_READ, 0); 5855250003Sadrian /* 32 bits */ 5856250003Sadrian iq_res[idx] = OS_REG_READ(ah, chan_info_tab[ch_idx] + offset); 5857250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, 5858250003Sadrian AR_PHY_CHAN_INFO_TAB_S2_READ, 1); 5859250003Sadrian /* 16 bits */ 5860250003Sadrian iq_res[idx + 1] = 0xffff & 5861250003Sadrian OS_REG_READ(ah, chan_info_tab[ch_idx] + offset); 5862250003Sadrian 5863250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5864250003Sadrian "%s: IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", 5865250003Sadrian __func__, idx, iq_res[idx], idx + 1, iq_res[idx + 1]); 5866250003Sadrian } 5867250003Sadrian 5868250008Sadrian if (AH_FALSE == ar9300_calc_iq_corr( 5869250003Sadrian ah, ch_idx, iq_res, coeff.iqc_coeff)) 5870250003Sadrian { 5871250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5872250003Sadrian "%s: Failed in calculation of IQ correction.\n", 5873250003Sadrian __func__); 5874250003Sadrian goto TX_IQ_CAL_FAILED_; 5875250003Sadrian } 5876250003Sadrian 5877250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1] = coeff.iqc_coeff[0] & 0x7f; 5878250003Sadrian coeff.mag_coeff[ch_idx][im][iqcal_idx-1] = (coeff.iqc_coeff[0] >> 7) & 0x7f; 5879250003Sadrian if (coeff.mag_coeff[ch_idx][im][iqcal_idx-1] > 63) { 5880250003Sadrian coeff.mag_coeff[ch_idx][im][iqcal_idx-1] -= 128; 5881250003Sadrian } 5882250003Sadrian if (coeff.phs_coeff[ch_idx][im][iqcal_idx-1] > 63) { 5883250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1] -= 128; 5884250003Sadrian } 5885250003Sadrian#if 0 5886250003Sadrian ath_hal_printf(ah, "IQCAL::[ch%d][gain%d]:: mag = %d phase = %d \n", 5887250003Sadrian ch_idx, im, coeff.mag_coeff[ch_idx][im][iqcal_idx-1], 5888250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1]); 5889250003Sadrian#endif 5890250003Sadrian } 5891250003Sadrian } 5892250003Sadrian //last iteration; calculate mag and phs 5893250003Sadrian if (iqcal_idx == max_iqcal) { 5894250003Sadrian if (max_iqcal>1) { 5895250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5896250003Sadrian for (im = 0; im < nmeasurement; im++) { 5897250003Sadrian //sort mag and phs 5898250003Sadrian for( ix=0;ix<max_iqcal-1;ix++){ 5899250003Sadrian for( iy=ix+1;iy<=max_iqcal-1;iy++){ 5900250003Sadrian if(coeff.mag_coeff[ch_idx][im][iy] < 5901250003Sadrian coeff.mag_coeff[ch_idx][im][ix]) { 5902250003Sadrian //swap 5903250003Sadrian temp=coeff.mag_coeff[ch_idx][im][ix]; 5904250003Sadrian coeff.mag_coeff[ch_idx][im][ix] = coeff.mag_coeff[ch_idx][im][iy]; 5905250003Sadrian coeff.mag_coeff[ch_idx][im][iy] = temp; 5906250003Sadrian } 5907250003Sadrian if(coeff.phs_coeff[ch_idx][im][iy] < 5908250003Sadrian coeff.phs_coeff[ch_idx][im][ix]){ 5909250003Sadrian //swap 5910250003Sadrian temp=coeff.phs_coeff[ch_idx][im][ix]; 5911250003Sadrian coeff.phs_coeff[ch_idx][im][ix]=coeff.phs_coeff[ch_idx][im][iy]; 5912250003Sadrian coeff.phs_coeff[ch_idx][im][iy]=temp; 5913250003Sadrian } 5914250003Sadrian } 5915250003Sadrian } 5916250003Sadrian //select median; 3rd entry in the sorted array 5917250003Sadrian coeff.mag_coeff[ch_idx][im][0] = 5918250003Sadrian coeff.mag_coeff[ch_idx][im][max_iqcal/2]; 5919250003Sadrian coeff.phs_coeff[ch_idx][im][0] = 5920250003Sadrian coeff.phs_coeff[ch_idx][im][max_iqcal/2]; 5921250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5922250003Sadrian "IQCAL: Median [ch%d][gain%d]:: mag = %d phase = %d \n", 5923250003Sadrian ch_idx, im,coeff.mag_coeff[ch_idx][im][0], 5924250003Sadrian coeff.phs_coeff[ch_idx][im][0]); 5925250003Sadrian } 5926250003Sadrian } 5927250003Sadrian } 5928250003Sadrian ar9300_tx_iq_cal_outlier_detection(ah,ichan, num_chains, &coeff,is_cal_reusable); 5929250003Sadrian } 5930250003Sadrian 5931250003Sadrian 5932250003Sadrian coeff.last_nmeasurement = nmeasurement; 5933250003Sadrian coeff.last_cal = AH_TRUE; 5934250003Sadrian 5935250003Sadrian return; 5936250003Sadrian 5937250003SadrianTX_IQ_CAL_FAILED_: 5938250003Sadrian /* no need to print this, it is AGC failure not chip stuck */ 5939250003Sadrian /*ath_hal_printf(ah, "Tx IQ Cal failed(%d)\n", line);*/ 5940250003Sadrian coeff.last_cal = AH_FALSE; 5941250003Sadrian return; 5942250003Sadrian} 5943250003Sadrian 5944250003Sadrian 5945250003Sadrian/* 5946250003Sadrian * ar9300_disable_phy_restart 5947250003Sadrian * 5948250003Sadrian * In some BBpanics, we can disable the phyrestart 5949250003Sadrian * disable_phy_restart 5950250003Sadrian * != 0, disable the phy restart in h/w 5951250003Sadrian * == 0, enable the phy restart in h/w 5952250003Sadrian */ 5953250003Sadrianvoid ar9300_disable_phy_restart(struct ath_hal *ah, int disable_phy_restart) 5954250003Sadrian{ 5955250003Sadrian u_int32_t val; 5956250003Sadrian 5957250003Sadrian val = OS_REG_READ(ah, AR_PHY_RESTART); 5958250003Sadrian if (disable_phy_restart) { 5959250003Sadrian val &= ~AR_PHY_RESTART_ENA; 5960250008Sadrian AH9300(ah)->ah_phyrestart_disabled = 1; 5961250003Sadrian } else { 5962250003Sadrian val |= AR_PHY_RESTART_ENA; 5963250008Sadrian AH9300(ah)->ah_phyrestart_disabled = 0; 5964250003Sadrian } 5965250003Sadrian OS_REG_WRITE(ah, AR_PHY_RESTART, val); 5966250003Sadrian 5967250003Sadrian val = OS_REG_READ(ah, AR_PHY_RESTART); 5968250003Sadrian} 5969250003Sadrian 5970250003SadrianHAL_BOOL 5971250003Sadrianar9300_interference_is_present(struct ath_hal *ah) 5972250003Sadrian{ 5973250003Sadrian int i; 5974250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 5975250008Sadrian const struct ieee80211_channel *chan = ahpriv->ah_curchan; 5976250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 5977250003Sadrian 5978250008Sadrian if (ichan == NULL) { 5979250008Sadrian ath_hal_printf(ah, "%s: called with ichan=NULL\n", __func__); 5980250008Sadrian return AH_FALSE; 5981250008Sadrian } 5982250008Sadrian 5983250003Sadrian /* This function is called after a stuck beacon, if EACS is enabled. 5984250003Sadrian * If CW interference is severe, then HW goes into a loop of continuous 5985250003Sadrian * stuck beacons and resets. On reset the NF cal history is cleared. 5986250003Sadrian * So the median value of the history cannot be used - 5987250003Sadrian * hence check if any value (Chain 0/Primary Channel) 5988250003Sadrian * is outside the bounds. 5989250003Sadrian */ 5990250008Sadrian HAL_NFCAL_HIST_FULL *h = AH_HOME_CHAN_NFCAL_HIST(ah, ichan); 5991250003Sadrian for (i = 0; i < HAL_NF_CAL_HIST_LEN_FULL; i++) { 5992250003Sadrian if (h->nf_cal_buffer[i][0] > 5993250008Sadrian AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta) 5994250003Sadrian { 5995250003Sadrian return AH_TRUE; 5996250003Sadrian } 5997250003Sadrian 5998250003Sadrian } 5999250003Sadrian return AH_FALSE; 6000250003Sadrian} 6001250003Sadrian 6002250003Sadrian#if ATH_SUPPORT_CRDC 6003250003Sadrianvoid 6004250003Sadrianar9300_crdc_rx_notify(struct ath_hal *ah, struct ath_rx_status *rxs) 6005250003Sadrian{ 6006250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6007250003Sadrian int rssi_index; 6008250003Sadrian 6009250003Sadrian if ((!AR_SREV_WASP(ah)) || 6010250003Sadrian (!ahpriv->ah_config.ath_hal_crdc_enable)) { 6011250003Sadrian return; 6012250003Sadrian } 6013250003Sadrian 6014250003Sadrian if (rxs->rs_isaggr && rxs->rs_moreaggr) { 6015250003Sadrian return; 6016250003Sadrian } 6017250003Sadrian 6018250003Sadrian if ((rxs->rs_rssi_ctl0 >= HAL_RSSI_BAD) || 6019250003Sadrian (rxs->rs_rssi_ctl1 >= HAL_RSSI_BAD)) { 6020250003Sadrian return; 6021250003Sadrian } 6022250003Sadrian 6023250003Sadrian rssi_index = ah->ah_crdc_rssi_ptr % HAL_MAX_CRDC_RSSI_SAMPLE; 6024250003Sadrian 6025250003Sadrian ah->ah_crdc_rssi_sample[0][rssi_index] = rxs->rs_rssi_ctl0; 6026250003Sadrian ah->ah_crdc_rssi_sample[1][rssi_index] = rxs->rs_rssi_ctl1; 6027250003Sadrian 6028250003Sadrian ah->ah_crdc_rssi_ptr++; 6029250003Sadrian} 6030250003Sadrian 6031250003Sadrianstatic int 6032250003Sadrianar9300_crdc_avg_rssi(struct ath_hal *ah, int chain) 6033250003Sadrian{ 6034250003Sadrian int crdc_rssi_sum = 0; 6035250003Sadrian int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr, i; 6036250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6037250003Sadrian int crdc_window = ahpriv->ah_config.ath_hal_crdc_window; 6038250003Sadrian 6039250003Sadrian if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) { 6040250003Sadrian crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE; 6041250003Sadrian } 6042250003Sadrian 6043250003Sadrian for (i = 1; i <= crdc_window; i++) { 6044250003Sadrian crdc_rssi_sum += 6045250003Sadrian ah->ah_crdc_rssi_sample[chain] 6046250003Sadrian [(crdc_rssi_ptr - i) % HAL_MAX_CRDC_RSSI_SAMPLE]; 6047250003Sadrian } 6048250003Sadrian 6049250003Sadrian return crdc_rssi_sum / crdc_window; 6050250003Sadrian} 6051250003Sadrian 6052250003Sadrianstatic void 6053250003Sadrianar9300_crdc_activate(struct ath_hal *ah, int rssi_diff, int enable) 6054250003Sadrian{ 6055250003Sadrian int val, orig_val; 6056250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6057250003Sadrian int crdc_numerator = ahpriv->ah_config.ath_hal_crdc_numerator; 6058250003Sadrian int crdc_denominator = ahpriv->ah_config.ath_hal_crdc_denominator; 6059250003Sadrian int c = (rssi_diff * crdc_numerator) / crdc_denominator; 6060250003Sadrian 6061250003Sadrian val = orig_val = OS_REG_READ(ah, AR_PHY_MULTICHAIN_CTRL); 6062250003Sadrian val &= 0xffffff00; 6063250003Sadrian if (enable) { 6064250003Sadrian val |= 0x1; 6065250003Sadrian val |= ((c << 1) & 0xff); 6066250003Sadrian } 6067250003Sadrian OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_CTRL, val); 6068250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "diff: %02d comp: %02d reg: %08x %08x\n", 6069250003Sadrian rssi_diff, c, orig_val, val); 6070250003Sadrian} 6071250003Sadrian 6072250003Sadrian 6073250003Sadrianvoid ar9300_chain_rssi_diff_compensation(struct ath_hal *ah) 6074250003Sadrian{ 6075250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6076250003Sadrian int crdc_window = ahpriv->ah_config.ath_hal_crdc_window; 6077250003Sadrian int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr; 6078250003Sadrian int crdc_rssi_thresh = ahpriv->ah_config.ath_hal_crdc_rssithresh; 6079250003Sadrian int crdc_diff_thresh = ahpriv->ah_config.ath_hal_crdc_diffthresh; 6080250003Sadrian int avg_rssi[2], avg_rssi_diff; 6081250003Sadrian 6082250003Sadrian if ((!AR_SREV_WASP(ah)) || 6083250003Sadrian (!ahpriv->ah_config.ath_hal_crdc_enable)) { 6084250003Sadrian if (ah->ah_crdc_rssi_ptr) { 6085250003Sadrian ar9300_crdc_activate(ah, 0, 0); 6086250003Sadrian ah->ah_crdc_rssi_ptr = 0; 6087250003Sadrian } 6088250003Sadrian return; 6089250003Sadrian } 6090250003Sadrian 6091250003Sadrian if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) { 6092250003Sadrian crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE; 6093250003Sadrian } 6094250003Sadrian 6095250003Sadrian if (crdc_rssi_ptr < crdc_window) { 6096250003Sadrian return; 6097250003Sadrian } 6098250003Sadrian 6099250003Sadrian avg_rssi[0] = ar9300_crdc_avg_rssi(ah, 0); 6100250003Sadrian avg_rssi[1] = ar9300_crdc_avg_rssi(ah, 1); 6101250003Sadrian avg_rssi_diff = avg_rssi[1] - avg_rssi[0]; 6102250003Sadrian 6103250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "crdc: avg: %02d %02d ", 6104250003Sadrian avg_rssi[0], avg_rssi[1]); 6105250003Sadrian 6106250003Sadrian if ((avg_rssi[0] < crdc_rssi_thresh) && 6107250003Sadrian (avg_rssi[1] < crdc_rssi_thresh)) { 6108250003Sadrian ar9300_crdc_activate(ah, 0, 0); 6109250003Sadrian } else { 6110250003Sadrian if (ABS(avg_rssi_diff) >= crdc_diff_thresh) { 6111250003Sadrian ar9300_crdc_activate(ah, avg_rssi_diff, 1); 6112250003Sadrian } else { 6113250003Sadrian ar9300_crdc_activate(ah, 0, 1); 6114250003Sadrian } 6115250003Sadrian } 6116250003Sadrian} 6117250003Sadrian#endif 6118250003Sadrian 6119250003Sadrian#if ATH_ANT_DIV_COMB 6120250003SadrianHAL_BOOL 6121250008Sadrianar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, const struct ieee80211_channel *chan) 6122250003Sadrian{ 6123250003Sadrian u_int32_t value; 6124250003Sadrian u_int32_t regval; 6125250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 6126250003Sadrian HAL_CHANNEL_INTERNAL *ichan; 6127250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6128250003Sadrian HAL_CAPABILITIES *pcap = &ahpriv->ah_caps; 6129250003Sadrian 6130250003Sadrian if (AR_SREV_POSEIDON(ah)) { 6131250003Sadrian // Make sure this scheme is only used for WB225(Astra) 6132250003Sadrian ahp->ah_lna_div_use_bt_ant_enable = enable; 6133250003Sadrian 6134250003Sadrian ichan = ar9300_check_chan(ah, chan); 6135250003Sadrian if ( ichan == AH_NULL ) { 6136250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n", 6137250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 6138250003Sadrian return AH_FALSE; 6139250003Sadrian } 6140250003Sadrian 6141250003Sadrian if ( enable == TRUE ) { 6142250008Sadrian pcap->halAntDivCombSupport = TRUE; 6143250003Sadrian } else { 6144250008Sadrian pcap->halAntDivCombSupport = pcap->halAntDivCombSupportOrg; 6145250003Sadrian } 6146250003Sadrian 6147250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) 6148250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL_S (0) 6149250003Sadrian value = ar9300_ant_ctrl_common2_get(ah, IS_CHAN_2GHZ(ichan)); 6150250003Sadrian if ( enable == TRUE ) { 6151250003Sadrian value &= ~AR_SWITCH_TABLE_COM2_ALL; 6152250008Sadrian value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable; 6153250003Sadrian } 6154272292Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value); 6155250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); 6156250003Sadrian 6157250003Sadrian value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control); 6158250003Sadrian /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 6159250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 6160250003Sadrian regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */ 6161250003Sadrian regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S; 6162250003Sadrian /* enable_lnadiv */ 6163250003Sadrian regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK); 6164250003Sadrian regval |= ((value >> 6) & 0x1) << 6165250003Sadrian MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT; 6166250003Sadrian if ( enable == TRUE ) { 6167250003Sadrian regval |= ANT_DIV_ENABLE; 6168250003Sadrian } 6169250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 6170250003Sadrian 6171250003Sadrian /* enable fast_div */ 6172250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 6173250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 6174250003Sadrian regval |= ((value >> 7) & 0x1) << 6175250003Sadrian BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT; 6176250003Sadrian if ( enable == TRUE ) { 6177250003Sadrian regval |= FAST_DIV_ENABLE; 6178250003Sadrian } 6179250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 6180250003Sadrian 6181250003Sadrian if ( AR_SREV_POSEIDON_11_OR_LATER(ah) ) { 6182250008Sadrian if (pcap->halAntDivCombSupport) { 6183250003Sadrian /* If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning */ 6184250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 6185250003Sadrian /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 6186250003Sadrian regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | 6187250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | 6188250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK | 6189250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK)); 6190250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA1 << 6191250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 6192250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA2 << 6193250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 6194250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 6195250003Sadrian } 6196250003Sadrian } 6197250003Sadrian 6198250003Sadrian return AH_TRUE; 6199250003Sadrian } else { 6200250003Sadrian return AH_TRUE; 6201250003Sadrian } 6202250003Sadrian} 6203250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 6204