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 */ 1335250003Sadrianinline void 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); 1990250003Sadrian 1991250008Sadrian OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0); 1992250008Sadrian 1993250003Sadrian /* 1994250003Sadrian * Warm reset is optimistic. 1995250003Sadrian */ 1996250003Sadrian if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) { 1997250003Sadrian return AH_FALSE; 1998250003Sadrian } 1999250003Sadrian 2000250003Sadrian /* Bring out of sleep mode (AGAIN) */ 2001250003Sadrian if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { 2002250003Sadrian return AH_FALSE; 2003250003Sadrian } 2004250003Sadrian 2005250003Sadrian ahp->ah_chip_full_sleep = AH_FALSE; 2006250003Sadrian 2007250003Sadrian if (AR_SREV_HORNET(ah)) { 2008250003Sadrian ar9300_internal_regulator_apply(ah); 2009250003Sadrian } 2010250003Sadrian 2011250003Sadrian ar9300_init_pll(ah, chan); 2012250003Sadrian 2013250003Sadrian /* 2014250003Sadrian * Perform warm reset before the mode/PLL/turbo registers 2015250003Sadrian * are changed in order to deactivate the radio. Mode changes 2016250003Sadrian * with an active radio can result in corrupted shifts to the 2017250003Sadrian * radio device. 2018250003Sadrian */ 2019250003Sadrian ar9300_set_rf_mode(ah, chan); 2020250003Sadrian 2021250003Sadrian return AH_TRUE; 2022250003Sadrian} 2023250003Sadrian 2024250003Sadrian/* ar9300_setup_calibration 2025250003Sadrian * Setup HW to collect samples used for current cal 2026250003Sadrian */ 2027250003Sadrianinline static void 2028250003Sadrianar9300_setup_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal) 2029250003Sadrian{ 2030250003Sadrian /* Select calibration to run */ 2031250003Sadrian switch (curr_cal->cal_data->cal_type) { 2032250003Sadrian case IQ_MISMATCH_CAL: 2033250003Sadrian /* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ 2034250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, 2035250003Sadrian AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, 2036250003Sadrian curr_cal->cal_data->cal_count_max); 2037250003Sadrian OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 2038250003Sadrian 2039250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2040250003Sadrian "%s: starting IQ Mismatch Calibration\n", __func__); 2041250003Sadrian 2042250003Sadrian /* Kick-off cal */ 2043250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); 2044250003Sadrian 2045250003Sadrian break; 2046250003Sadrian case TEMP_COMP_CAL: 2047250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || 2048250003Sadrian AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 2049250003Sadrian OS_REG_RMW_FIELD(ah, 2050250003Sadrian AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2051250003Sadrian OS_REG_RMW_FIELD(ah, 2052250003Sadrian AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); 2053250003Sadrian } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 2054250003Sadrian OS_REG_RMW_FIELD(ah, 2055250003Sadrian AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2056250003Sadrian OS_REG_RMW_FIELD(ah, 2057250003Sadrian AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_START, 1); 2058250003Sadrian } else { 2059250003Sadrian OS_REG_RMW_FIELD(ah, 2060250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1); 2061250003Sadrian OS_REG_RMW_FIELD(ah, 2062250003Sadrian AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); 2063250003Sadrian } 2064250003Sadrian 2065250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2066250003Sadrian "%s: starting Temperature Compensation Calibration\n", __func__); 2067250003Sadrian break; 2068250003Sadrian default: 2069250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 2070250003Sadrian "%s called with incorrect calibration type.\n", __func__); 2071250003Sadrian } 2072250003Sadrian} 2073250003Sadrian 2074250003Sadrian/* ar9300_reset_calibration 2075250003Sadrian * Initialize shared data structures and prepare a cal to be run. 2076250003Sadrian */ 2077250003Sadrianinline static void 2078250003Sadrianar9300_reset_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal) 2079250003Sadrian{ 2080250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2081250003Sadrian int i; 2082250003Sadrian 2083250003Sadrian /* Setup HW for new calibration */ 2084250003Sadrian ar9300_setup_calibration(ah, curr_cal); 2085250003Sadrian 2086250003Sadrian /* Change SW state to RUNNING for this calibration */ 2087250003Sadrian curr_cal->cal_state = CAL_RUNNING; 2088250003Sadrian 2089250003Sadrian /* Reset data structures shared between different calibrations */ 2090250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 2091250003Sadrian ahp->ah_meas0.sign[i] = 0; 2092250003Sadrian ahp->ah_meas1.sign[i] = 0; 2093250003Sadrian ahp->ah_meas2.sign[i] = 0; 2094250003Sadrian ahp->ah_meas3.sign[i] = 0; 2095250003Sadrian } 2096250003Sadrian 2097250003Sadrian ahp->ah_cal_samples = 0; 2098250003Sadrian} 2099250003Sadrian 2100250003Sadrian#ifdef XXX_UNUSED_FUNCTION 2101250003Sadrian/* 2102250003Sadrian * Find out which of the RX chains are enabled 2103250003Sadrian */ 2104250003Sadrianstatic u_int32_t 2105250003Sadrianar9300_get_rx_chain_mask(struct ath_hal *ah) 2106250003Sadrian{ 2107250003Sadrian u_int32_t ret_val = OS_REG_READ(ah, AR_PHY_RX_CHAINMASK); 2108250003Sadrian /* The bits [2:0] indicate the rx chain mask and are to be 2109250003Sadrian * interpreted as follows: 2110250003Sadrian * 00x => Only chain 0 is enabled 2111250003Sadrian * 01x => Chain 1 and 0 enabled 2112250003Sadrian * 1xx => Chain 2,1 and 0 enabled 2113250003Sadrian */ 2114250003Sadrian return (ret_val & 0x7); 2115250003Sadrian} 2116250003Sadrian#endif 2117250003Sadrian 2118250003Sadrianstatic void 2119250003Sadrianar9300_get_nf_hist_base(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, 2120250003Sadrian int is_scan, int16_t nf[]) 2121250003Sadrian{ 2122250003Sadrian HAL_NFCAL_BASE *h_base; 2123250003Sadrian 2124250003Sadrian#ifdef ATH_NF_PER_CHAN 2125250003Sadrian h_base = &chan->nf_cal_hist.base; 2126250003Sadrian#else 2127250003Sadrian if (is_scan) { 2128250003Sadrian /* 2129250003Sadrian * The channel we are currently on is not the home channel, 2130250003Sadrian * so we shouldn't use the home channel NF buffer's values on 2131250003Sadrian * this channel. Instead, use the NF single value already 2132250003Sadrian * read for this channel. (Or, if we haven't read the NF for 2133250003Sadrian * this channel yet, the SW default for this chip/band will 2134250003Sadrian * be used.) 2135250003Sadrian */ 2136250003Sadrian h_base = &chan->nf_cal_hist.base; 2137250003Sadrian } else { 2138250003Sadrian /* use the home channel NF info */ 2139250003Sadrian h_base = &AH_PRIVATE(ah)->nf_cal_hist.base; 2140250003Sadrian } 2141250003Sadrian#endif 2142250003Sadrian OS_MEMCPY(nf, h_base->priv_nf, sizeof(h_base->priv_nf)); 2143250003Sadrian} 2144250003Sadrian 2145250003SadrianHAL_BOOL 2146250003Sadrianar9300_load_nf(struct ath_hal *ah, int16_t nf[]) 2147250003Sadrian{ 2148250003Sadrian int i, j; 2149250003Sadrian int32_t val; 2150250003Sadrian /* XXX where are EXT regs defined */ 2151250003Sadrian const u_int32_t ar9300_cca_regs[] = { 2152250003Sadrian AR_PHY_CCA_0, 2153250003Sadrian AR_PHY_CCA_1, 2154250003Sadrian AR_PHY_CCA_2, 2155250003Sadrian AR_PHY_EXT_CCA, 2156250003Sadrian AR_PHY_EXT_CCA_1, 2157250003Sadrian AR_PHY_EXT_CCA_2, 2158250003Sadrian }; 2159250003Sadrian u_int8_t chainmask; 2160250003Sadrian 2161250003Sadrian /* 2162250003Sadrian * Force NF calibration for all chains, otherwise Vista station 2163250003Sadrian * would conduct a bad performance 2164250003Sadrian */ 2165250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 2166250003Sadrian chainmask = 0x9; 2167250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { 2168250003Sadrian chainmask = 0x1b; 2169250003Sadrian } else { 2170250003Sadrian chainmask = 0x3F; 2171250003Sadrian } 2172250003Sadrian 2173250003Sadrian /* 2174250003Sadrian * Write filtered NF values into max_cca_pwr register parameter 2175250003Sadrian * so we can load below. 2176250003Sadrian */ 2177250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 2178250003Sadrian if (chainmask & (1 << i)) { 2179250003Sadrian val = OS_REG_READ(ah, ar9300_cca_regs[i]); 2180250003Sadrian val &= 0xFFFFFE00; 2181250003Sadrian val |= (((u_int32_t)(nf[i]) << 1) & 0x1ff); 2182250003Sadrian OS_REG_WRITE(ah, ar9300_cca_regs[i], val); 2183250003Sadrian } 2184250003Sadrian } 2185250003Sadrian 2186250008Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s: load %d %d %d %d %d %d\n", 2187250008Sadrian __func__, 2188250008Sadrian nf[0], nf[1], nf[2], 2189250008Sadrian nf[3], nf[4], nf[5]); 2190250008Sadrian 2191250003Sadrian /* 2192250003Sadrian * Load software filtered NF value into baseband internal min_cca_pwr 2193250003Sadrian * variable. 2194250003Sadrian */ 2195250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); 2196250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 2197250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 2198250003Sadrian 2199250003Sadrian /* Wait for load to complete, should be fast, a few 10s of us. */ 2200250003Sadrian /* Changed the max delay 250us back to 10000us, since 250us often 2201250003Sadrian * results in NF load timeout and causes deaf condition 2202250003Sadrian * during stress testing 12/12/2009 2203250003Sadrian */ 2204250003Sadrian for (j = 0; j < 10000; j++) { 2205250003Sadrian if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){ 2206250003Sadrian break; 2207250003Sadrian } 2208250003Sadrian OS_DELAY(10); 2209250003Sadrian } 2210250003Sadrian if (j == 10000) { 2211250003Sadrian /* 2212250003Sadrian * We timed out waiting for the noisefloor to load, probably 2213250003Sadrian * due to an in-progress rx. Simply return here and allow 2214250003Sadrian * the load plenty of time to complete before the next 2215250003Sadrian * calibration interval. We need to avoid trying to load -50 2216250003Sadrian * (which happens below) while the previous load is still in 2217250003Sadrian * progress as this can cause rx deafness (see EV 66368,62830). 2218250003Sadrian * Instead by returning here, the baseband nf cal will 2219250003Sadrian * just be capped by our present noisefloor until the next 2220250003Sadrian * calibration timer. 2221250003Sadrian */ 2222250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 2223250003Sadrian "%s: *** TIMEOUT while waiting for nf to load: " 2224250003Sadrian "AR_PHY_AGC_CONTROL=0x%x ***\n", 2225250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); 2226250003Sadrian return AH_FALSE; 2227250003Sadrian } 2228250003Sadrian 2229250003Sadrian /* 2230250003Sadrian * Restore max_cca_power register parameter again so that we're not capped 2231250003Sadrian * by the median we just loaded. This will be initial (and max) value 2232250003Sadrian * of next noise floor calibration the baseband does. 2233250003Sadrian */ 2234250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) { 2235250003Sadrian if (chainmask & (1 << i)) { 2236250003Sadrian val = OS_REG_READ(ah, ar9300_cca_regs[i]); 2237250003Sadrian val &= 0xFFFFFE00; 2238250003Sadrian val |= (((u_int32_t)(-50) << 1) & 0x1ff); 2239250003Sadrian OS_REG_WRITE(ah, ar9300_cca_regs[i], val); 2240250003Sadrian } 2241250003Sadrian } 2242250003Sadrian return AH_TRUE; 2243250003Sadrian} 2244250003Sadrian 2245250003Sadrian/* ar9300_per_calibration 2246250003Sadrian * Generic calibration routine. 2247250003Sadrian * Recalibrate the lower PHY chips to account for temperature/environment 2248250003Sadrian * changes. 2249250003Sadrian */ 2250250003Sadrianinline static void 2251250003Sadrianar9300_per_calibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, 2252250003Sadrian u_int8_t rxchainmask, HAL_CAL_LIST *curr_cal, HAL_BOOL *is_cal_done) 2253250003Sadrian{ 2254250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2255250003Sadrian 2256250003Sadrian /* Cal is assumed not done until explicitly set below */ 2257250003Sadrian *is_cal_done = AH_FALSE; 2258250003Sadrian 2259250003Sadrian /* Calibration in progress. */ 2260250003Sadrian if (curr_cal->cal_state == CAL_RUNNING) { 2261250003Sadrian /* Check to see if it has finished. */ 2262250003Sadrian if (!(OS_REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { 2263250003Sadrian int i, num_chains = 0; 2264250003Sadrian for (i = 0; i < AR9300_MAX_CHAINS; i++) { 2265250003Sadrian if (rxchainmask & (1 << i)) { 2266250003Sadrian num_chains++; 2267250003Sadrian } 2268250003Sadrian } 2269250003Sadrian 2270250003Sadrian /* 2271250003Sadrian * Accumulate cal measures for active chains 2272250003Sadrian */ 2273250003Sadrian curr_cal->cal_data->cal_collect(ah, num_chains); 2274250003Sadrian 2275250003Sadrian ahp->ah_cal_samples++; 2276250003Sadrian 2277250003Sadrian if (ahp->ah_cal_samples >= curr_cal->cal_data->cal_num_samples) { 2278250003Sadrian /* 2279250003Sadrian * Process accumulated data 2280250003Sadrian */ 2281250003Sadrian curr_cal->cal_data->cal_post_proc(ah, num_chains); 2282250003Sadrian 2283250003Sadrian /* Calibration has finished. */ 2284250008Sadrian ichan->calValid |= curr_cal->cal_data->cal_type; 2285250003Sadrian curr_cal->cal_state = CAL_DONE; 2286250003Sadrian *is_cal_done = AH_TRUE; 2287250003Sadrian } else { 2288250003Sadrian /* Set-up collection of another sub-sample until we 2289250003Sadrian * get desired number 2290250003Sadrian */ 2291250003Sadrian ar9300_setup_calibration(ah, curr_cal); 2292250003Sadrian } 2293250003Sadrian } 2294250008Sadrian } else if (!(ichan->calValid & curr_cal->cal_data->cal_type)) { 2295250003Sadrian /* If current cal is marked invalid in channel, kick it off */ 2296250003Sadrian ar9300_reset_calibration(ah, curr_cal); 2297250003Sadrian } 2298250003Sadrian} 2299250003Sadrian 2300250003Sadrianstatic void 2301250003Sadrianar9300_start_nf_cal(struct ath_hal *ah) 2302250003Sadrian{ 2303250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); 2304250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 2305250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 2306250003Sadrian AH9300(ah)->nf_tsf32 = ar9300_get_tsf32(ah); 2307250003Sadrian} 2308250003Sadrian 2309250003Sadrian/* ar9300_calibration 2310250003Sadrian * Wrapper for a more generic Calibration routine. Primarily to abstract to 2311250003Sadrian * upper layers whether there is 1 or more calibrations to be run. 2312250003Sadrian */ 2313250003SadrianHAL_BOOL 2314250008Sadrianar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask, 2315250003Sadrian HAL_BOOL do_nf_cal, HAL_BOOL *is_cal_done, int is_scan, 2316250003Sadrian u_int32_t *sched_cals) 2317250003Sadrian{ 2318250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2319250003Sadrian HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr; 2320250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2321250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 2322250003Sadrian 2323250003Sadrian *is_cal_done = AH_TRUE; 2324250003Sadrian 2325250003Sadrian 2326250003Sadrian /* XXX: For initial wasp bringup - disable periodic calibration */ 2327250003Sadrian /* Invalid channel check */ 2328250003Sadrian if (ichan == AH_NULL) { 2329250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 2330250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 2331250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 2332250003Sadrian return AH_FALSE; 2333250003Sadrian } 2334250003Sadrian 2335250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2336250003Sadrian "%s: Entering, Doing NF Cal = %d\n", __func__, do_nf_cal); 2337250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 0 Rx IQ Cal Correction 0x%08x\n", 2338250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 2339250003Sadrian if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) { 2340250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2341250003Sadrian "%s: Chain 1 Rx IQ Cal Correction 0x%08x\n", 2342250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B1)); 2343250003Sadrian if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { 2344250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2345250003Sadrian "%s: Chain 2 Rx IQ Cal Correction 0x%08x\n", 2346250003Sadrian __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B2)); 2347250003Sadrian } 2348250003Sadrian } 2349250003Sadrian 2350250008Sadrian OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq); 2351250003Sadrian 2352250003Sadrian /* For given calibration: 2353250003Sadrian * 1. Call generic cal routine 2354250003Sadrian * 2. When this cal is done (is_cal_done) if we have more cals waiting 2355250003Sadrian * (eg after reset), mask this to upper layers by not propagating 2356250003Sadrian * is_cal_done if it is set to TRUE. 2357250003Sadrian * Instead, change is_cal_done to FALSE and setup the waiting cal(s) 2358250003Sadrian * to be run. 2359250003Sadrian */ 2360250003Sadrian if (curr_cal && (curr_cal->cal_data->cal_type & *sched_cals) && 2361250003Sadrian (curr_cal->cal_state == CAL_RUNNING || 2362250003Sadrian curr_cal->cal_state == CAL_WAITING)) 2363250003Sadrian { 2364250003Sadrian ar9300_per_calibration(ah, ichan, rxchainmask, curr_cal, is_cal_done); 2365250003Sadrian 2366250003Sadrian if (*is_cal_done == AH_TRUE) { 2367250003Sadrian ahp->ah_cal_list_curr = curr_cal = curr_cal->cal_next; 2368250003Sadrian 2369250003Sadrian if (curr_cal && curr_cal->cal_state == CAL_WAITING) { 2370250003Sadrian *is_cal_done = AH_FALSE; 2371250003Sadrian ar9300_reset_calibration(ah, curr_cal); 2372250003Sadrian } else { 2373250003Sadrian *sched_cals &= ~IQ_MISMATCH_CAL; 2374250003Sadrian } 2375250003Sadrian } 2376250003Sadrian } 2377250003Sadrian 2378250003Sadrian /* Do NF cal only at longer intervals */ 2379250003Sadrian if (do_nf_cal) { 2380250003Sadrian int nf_done; 2381250003Sadrian 2382250003Sadrian /* Get the value from the previous NF cal and update history buffer */ 2383250008Sadrian nf_done = ar9300_store_new_nf(ah, chan, is_scan); 2384250008Sadrian#if 0 2385250003Sadrian if (ichan->channel_flags & CHANNEL_CW_INT) { 2386250003Sadrian chan->channel_flags |= CHANNEL_CW_INT; 2387250003Sadrian } 2388250008Sadrian#endif 2389250008Sadrian chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; 2390250003Sadrian 2391250003Sadrian if (nf_done) { 2392250003Sadrian /* 2393250003Sadrian * Load the NF from history buffer of the current channel. 2394250003Sadrian * NF is slow time-variant, so it is OK to use a historical value. 2395250003Sadrian */ 2396250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 2397250003Sadrian ar9300_load_nf(ah, nf_buf); 2398250003Sadrian 2399250003Sadrian /* start NF calibration, without updating BB NF register*/ 2400250003Sadrian ar9300_start_nf_cal(ah); 2401250003Sadrian } 2402250003Sadrian } 2403250003Sadrian return AH_TRUE; 2404250003Sadrian} 2405250003Sadrian 2406250003Sadrian/* ar9300_iq_cal_collect 2407250003Sadrian * Collect data from HW to later perform IQ Mismatch Calibration 2408250003Sadrian */ 2409250003Sadrianvoid 2410250003Sadrianar9300_iq_cal_collect(struct ath_hal *ah, u_int8_t num_chains) 2411250003Sadrian{ 2412250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2413250003Sadrian int i; 2414250003Sadrian 2415250003Sadrian /* 2416250003Sadrian * Accumulate IQ cal measures for active chains 2417250003Sadrian */ 2418250003Sadrian for (i = 0; i < num_chains; i++) { 2419250003Sadrian ahp->ah_total_power_meas_i[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 2420250003Sadrian ahp->ah_total_power_meas_q[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 2421250003Sadrian ahp->ah_total_iq_corr_meas[i] = 2422250003Sadrian (int32_t) OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 2423250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2424250003Sadrian "%d: Chn %d " 2425250003Sadrian "Reg Offset(0x%04x)pmi=0x%08x; " 2426250003Sadrian "Reg Offset(0x%04x)pmq=0x%08x; " 2427250003Sadrian "Reg Offset (0x%04x)iqcm=0x%08x;\n", 2428250003Sadrian ahp->ah_cal_samples, 2429250003Sadrian i, 2430250003Sadrian (unsigned) AR_PHY_CAL_MEAS_0(i), 2431250003Sadrian ahp->ah_total_power_meas_i[i], 2432250003Sadrian (unsigned) AR_PHY_CAL_MEAS_1(i), 2433250003Sadrian ahp->ah_total_power_meas_q[i], 2434250003Sadrian (unsigned) AR_PHY_CAL_MEAS_2(i), 2435250003Sadrian ahp->ah_total_iq_corr_meas[i]); 2436250003Sadrian } 2437250003Sadrian} 2438250003Sadrian 2439250003Sadrian/* ar9300_iq_calibration 2440250003Sadrian * Use HW data to perform IQ Mismatch Calibration 2441250003Sadrian */ 2442250003Sadrianvoid 2443250003Sadrianar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains) 2444250003Sadrian{ 2445250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2446250003Sadrian u_int32_t power_meas_q, power_meas_i, iq_corr_meas; 2447250003Sadrian u_int32_t q_coff_denom, i_coff_denom; 2448250003Sadrian int32_t q_coff, i_coff; 2449250003Sadrian int iq_corr_neg, i; 2450250003Sadrian static const u_int32_t offset_array[3] = { 2451250003Sadrian AR_PHY_RX_IQCAL_CORR_B0, 2452250003Sadrian AR_PHY_RX_IQCAL_CORR_B1, 2453250003Sadrian AR_PHY_RX_IQCAL_CORR_B2, 2454250003Sadrian }; 2455250003Sadrian 2456250003Sadrian for (i = 0; i < num_chains; i++) { 2457250003Sadrian power_meas_i = ahp->ah_total_power_meas_i[i]; 2458250003Sadrian power_meas_q = ahp->ah_total_power_meas_q[i]; 2459250003Sadrian iq_corr_meas = ahp->ah_total_iq_corr_meas[i]; 2460250003Sadrian 2461250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2462250003Sadrian "Starting IQ Cal and Correction for Chain %d\n", i); 2463250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2464250003Sadrian "Orignal: Chn %diq_corr_meas = 0x%08x\n", 2465250003Sadrian i, ahp->ah_total_iq_corr_meas[i]); 2466250003Sadrian 2467250003Sadrian iq_corr_neg = 0; 2468250003Sadrian 2469250003Sadrian /* iq_corr_meas is always negative. */ 2470250003Sadrian if (iq_corr_meas > 0x80000000) { 2471250003Sadrian iq_corr_meas = (0xffffffff - iq_corr_meas) + 1; 2472250003Sadrian iq_corr_neg = 1; 2473250003Sadrian } 2474250003Sadrian 2475250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2476250003Sadrian "Chn %d pwr_meas_i = 0x%08x\n", i, power_meas_i); 2477250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2478250003Sadrian "Chn %d pwr_meas_q = 0x%08x\n", i, power_meas_q); 2479250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2480250003Sadrian "iq_corr_neg is 0x%08x\n", iq_corr_neg); 2481250003Sadrian 2482250003Sadrian i_coff_denom = (power_meas_i / 2 + power_meas_q / 2) / 256; 2483250003Sadrian q_coff_denom = power_meas_q / 64; 2484250003Sadrian 2485250003Sadrian /* Protect against divide-by-0 */ 2486250003Sadrian if ((i_coff_denom != 0) && (q_coff_denom != 0)) { 2487250003Sadrian /* IQ corr_meas is already negated if iqcorr_neg == 1 */ 2488250003Sadrian i_coff = iq_corr_meas / i_coff_denom; 2489250003Sadrian q_coff = power_meas_i / q_coff_denom - 64; 2490250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2491250003Sadrian "Chn %d i_coff = 0x%08x\n", i, i_coff); 2492250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2493250003Sadrian "Chn %d q_coff = 0x%08x\n", i, q_coff); 2494250003Sadrian 2495250003Sadrian /* Force bounds on i_coff */ 2496250003Sadrian if (i_coff >= 63) { 2497250003Sadrian i_coff = 63; 2498250003Sadrian } else if (i_coff <= -63) { 2499250003Sadrian i_coff = -63; 2500250003Sadrian } 2501250003Sadrian 2502250003Sadrian /* Negate i_coff if iq_corr_neg == 0 */ 2503250003Sadrian if (iq_corr_neg == 0x0) { 2504250003Sadrian i_coff = -i_coff; 2505250003Sadrian } 2506250003Sadrian 2507250003Sadrian /* Force bounds on q_coff */ 2508250003Sadrian if (q_coff >= 63) { 2509250003Sadrian q_coff = 63; 2510250003Sadrian } else if (q_coff <= -63) { 2511250003Sadrian q_coff = -63; 2512250003Sadrian } 2513250003Sadrian 2514250003Sadrian i_coff = i_coff & 0x7f; 2515250003Sadrian q_coff = q_coff & 0x7f; 2516250003Sadrian 2517250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2518250003Sadrian "Chn %d : i_coff = 0x%x q_coff = 0x%x\n", i, i_coff, q_coff); 2519250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2520250003Sadrian "Register offset (0x%04x) before update = 0x%x\n", 2521250003Sadrian offset_array[i], OS_REG_READ(ah, offset_array[i])); 2522250003Sadrian 2523250003Sadrian OS_REG_RMW_FIELD(ah, offset_array[i], 2524250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff); 2525250003Sadrian OS_REG_RMW_FIELD(ah, offset_array[i], 2526250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff); 2527250003Sadrian 2528250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2529250003Sadrian "Register offset (0x%04x) QI COFF (bitfields 0x%08x) " 2530250003Sadrian "after update = 0x%x\n", 2531250003Sadrian offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 2532250003Sadrian OS_REG_READ(ah, offset_array[i])); 2533250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2534250003Sadrian "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) " 2535250003Sadrian "after update = 0x%x\n", 2536250003Sadrian offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 2537250003Sadrian OS_REG_READ(ah, offset_array[i])); 2538250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2539250003Sadrian "IQ Cal and Correction done for Chain %d\n", i); 2540250003Sadrian } 2541250003Sadrian } 2542250003Sadrian 2543250003Sadrian OS_REG_SET_BIT(ah, 2544250003Sadrian AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); 2545250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 2546250003Sadrian "IQ Cal and Correction (offset 0x%04x) enabled " 2547250003Sadrian "(bit position 0x%08x). New Value 0x%08x\n", 2548250003Sadrian (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), 2549250003Sadrian AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, 2550250003Sadrian OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 2551250003Sadrian} 2552250003Sadrian 2553250003Sadrian/* 2554250003Sadrian * Set a limit on the overall output power. Used for dynamic 2555250003Sadrian * transmit power control and the like. 2556250003Sadrian * 2557250003Sadrian * NB: limit is in units of 0.5 dbM. 2558250003Sadrian */ 2559250003SadrianHAL_BOOL 2560250003Sadrianar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit, 2561250003Sadrian u_int16_t extra_txpow, u_int16_t tpc_in_db) 2562250003Sadrian{ 2563250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2564250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 2565250008Sadrian const struct ieee80211_channel *chan = ahpriv->ah_curchan; 2566250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 2567250003Sadrian 2568250003Sadrian if (NULL == chan) { 2569250008Sadrian return AH_FALSE; 2570250008Sadrian } 2571250003Sadrian 2572250008Sadrian ahpriv->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); 2573250008Sadrian ahpriv->ah_extraTxPow = extra_txpow; 2574250008Sadrian 2575250003Sadrian if(chan == NULL) { 2576250003Sadrian return AH_FALSE; 2577250003Sadrian } 2578250008Sadrian if (ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan, 2579250003Sadrian ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), 2580250003Sadrian ath_hal_get_twice_max_regpower(ahpriv, ichan, chan), 2581250008Sadrian AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)) != HAL_OK) 2582250003Sadrian { 2583250003Sadrian return AH_FALSE; 2584250003Sadrian } 2585250003Sadrian return AH_TRUE; 2586250003Sadrian} 2587250003Sadrian 2588250003Sadrian/* 2589250003Sadrian * Exported call to check for a recent gain reading and return 2590250003Sadrian * the current state of the thermal calibration gain engine. 2591250003Sadrian */ 2592250003SadrianHAL_RFGAIN 2593250003Sadrianar9300_get_rfgain(struct ath_hal *ah) 2594250003Sadrian{ 2595250003Sadrian return HAL_RFGAIN_INACTIVE; 2596250003Sadrian} 2597250003Sadrian 2598250003Sadrian#define HAL_GREEN_AP_RX_MASK 0x1 2599250003Sadrian 2600250003Sadrianstatic inline void 2601250003Sadrianar9300_init_chain_masks(struct ath_hal *ah, int rx_chainmask, int tx_chainmask) 2602250003Sadrian{ 2603250008Sadrian if (AH9300(ah)->green_ap_ps_on) { 2604250003Sadrian rx_chainmask = HAL_GREEN_AP_RX_MASK; 2605250003Sadrian } 2606250003Sadrian if (rx_chainmask == 0x5) { 2607250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); 2608250003Sadrian } 2609250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 2610250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 2611250003Sadrian 2612250003Sadrian /* 2613250003Sadrian * Adaptive Power Management: 2614250003Sadrian * Some 3 stream chips exceed the PCIe power requirements. 2615250003Sadrian * This workaround will reduce power consumption by using 2 tx chains 2616250003Sadrian * for 1 and 2 stream rates (5 GHz only). 2617250003Sadrian * 2618250003Sadrian * Set the self gen mask to 2 tx chains when APM is enabled. 2619250003Sadrian * 2620250003Sadrian */ 2621250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halApmEnable && (tx_chainmask == 0x7)) { 2622250003Sadrian OS_REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); 2623250003Sadrian } 2624250003Sadrian else { 2625250003Sadrian OS_REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); 2626250003Sadrian } 2627250003Sadrian 2628250003Sadrian if (tx_chainmask == 0x5) { 2629250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); 2630250003Sadrian } 2631250003Sadrian} 2632250003Sadrian 2633250003Sadrian/* 2634250003Sadrian * Override INI values with chip specific configuration. 2635250003Sadrian */ 2636250003Sadrianstatic inline void 2637250008Sadrianar9300_override_ini(struct ath_hal *ah, struct ieee80211_channel *chan) 2638250003Sadrian{ 2639250003Sadrian u_int32_t val; 2640250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 2641250003Sadrian 2642250003Sadrian /* 2643250003Sadrian * Set the RX_ABORT and RX_DIS and clear it only after 2644250003Sadrian * RXE is set for MAC. This prevents frames with 2645250003Sadrian * corrupted descriptor status. 2646250003Sadrian */ 2647250003Sadrian OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); 2648250003Sadrian /* 2649250003Sadrian * For Merlin and above, there is a new feature that allows Multicast 2650250003Sadrian * search based on both MAC Address and Key ID. 2651250003Sadrian * By default, this feature is enabled. 2652250003Sadrian * But since the driver is not using this feature, we switch it off; 2653250003Sadrian * otherwise multicast search based on MAC addr only will fail. 2654250003Sadrian */ 2655250003Sadrian val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE); 2656250003Sadrian OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, 2657250003Sadrian val | AR_BUG_58603_FIX_ENABLE | AR_AGG_WEP_ENABLE); 2658250003Sadrian 2659250003Sadrian 2660250003Sadrian /* Osprey revision specific configuration */ 2661250003Sadrian 2662250003Sadrian /* Osprey 2.0+ - if SW RAC support is disabled, must also disable 2663250003Sadrian * the Osprey 2.0 hardware RAC fix. 2664250003Sadrian */ 2665250008Sadrian if (p_cap->halIsrRacSupport == AH_FALSE) { 2666250003Sadrian OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_MISSING_TX_INTR_FIX_ENABLE); 2667250003Sadrian } 2668250003Sadrian 2669250003Sadrian /* try to enable old pal if it is needed for h/w green tx */ 2670250003Sadrian ar9300_hwgreentx_set_pal_spare(ah, 1); 2671250003Sadrian} 2672250003Sadrian 2673250003Sadrianstatic inline void 2674250003Sadrianar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, 2675250003Sadrian int column) 2676250003Sadrian{ 2677250003Sadrian int i, reg_writes = 0; 2678250003Sadrian 2679250003Sadrian /* New INI format: Array may be undefined (pre, core, post arrays) */ 2680250003Sadrian if (ini_arr->ia_array == NULL) { 2681250003Sadrian return; 2682250003Sadrian } 2683250003Sadrian 2684250003Sadrian /* 2685250003Sadrian * New INI format: Pre, core, and post arrays for a given subsystem may be 2686250003Sadrian * modal (> 2 columns) or non-modal (2 columns). 2687250003Sadrian * Determine if the array is non-modal and force the column to 1. 2688250003Sadrian */ 2689250003Sadrian if (column >= ini_arr->ia_columns) { 2690250003Sadrian column = 1; 2691250003Sadrian } 2692250003Sadrian 2693250003Sadrian for (i = 0; i < ini_arr->ia_rows; i++) { 2694250003Sadrian u_int32_t reg = INI_RA(ini_arr, i, 0); 2695250003Sadrian u_int32_t val = INI_RA(ini_arr, i, column); 2696250003Sadrian 2697250003Sadrian /* 2698250003Sadrian ** Determine if this is a shift register value 2699250003Sadrian ** (reg >= 0x16000 && reg < 0x17000 for Osprey) , 2700250003Sadrian ** and insert the configured delay if so. 2701250003Sadrian ** -this delay is not required for Osprey (EV#71410) 2702250003Sadrian */ 2703250003Sadrian OS_REG_WRITE(ah, reg, val); 2704250003Sadrian WAR_6773(reg_writes); 2705250003Sadrian 2706250003Sadrian } 2707250003Sadrian} 2708250003Sadrian 2709250003Sadrianstatic inline HAL_STATUS 2710250008Sadrianar9300_process_ini(struct ath_hal *ah, struct ieee80211_channel *chan, 2711250003Sadrian HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode) 2712250003Sadrian{ 2713250003Sadrian int reg_writes = 0; 2714250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 2715250003Sadrian u_int modes_index, modes_txgaintable_index = 0; 2716250003Sadrian int i; 2717250003Sadrian HAL_STATUS status; 2718250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 2719250003Sadrian /* Setup the indices for the next set of register array writes */ 2720250003Sadrian /* TODO: 2721250003Sadrian * If the channel marker is indicative of the current mode rather 2722250003Sadrian * than capability, we do not need to check the phy mode below. 2723250003Sadrian */ 2724250008Sadrian#if 0 2725250003Sadrian switch (chan->channel_flags & CHANNEL_ALL) { 2726250003Sadrian case CHANNEL_A: 2727250003Sadrian case CHANNEL_A_HT20: 2728250003Sadrian if (AR_SREV_SCORPION(ah)){ 2729250003Sadrian if (chan->channel <= 5350){ 2730250003Sadrian modes_txgaintable_index = 1; 2731250003Sadrian }else if ((chan->channel > 5350) && (chan->channel <= 5600)){ 2732250003Sadrian modes_txgaintable_index = 3; 2733250003Sadrian }else if (chan->channel > 5600){ 2734250003Sadrian modes_txgaintable_index = 5; 2735250003Sadrian } 2736250003Sadrian } 2737250003Sadrian modes_index = 1; 2738250003Sadrian break; 2739250003Sadrian 2740250003Sadrian case CHANNEL_A_HT40PLUS: 2741250003Sadrian case CHANNEL_A_HT40MINUS: 2742250003Sadrian if (AR_SREV_SCORPION(ah)){ 2743250003Sadrian if (chan->channel <= 5350){ 2744250003Sadrian modes_txgaintable_index = 2; 2745250003Sadrian }else if ((chan->channel > 5350) && (chan->channel <= 5600)){ 2746250003Sadrian modes_txgaintable_index = 4; 2747250003Sadrian }else if (chan->channel > 5600){ 2748250003Sadrian modes_txgaintable_index = 6; 2749250003Sadrian } 2750250003Sadrian } 2751250003Sadrian modes_index = 2; 2752250003Sadrian break; 2753250003Sadrian 2754250003Sadrian case CHANNEL_PUREG: 2755250003Sadrian case CHANNEL_G_HT20: 2756250003Sadrian case CHANNEL_B: 2757250003Sadrian if (AR_SREV_SCORPION(ah)){ 2758250003Sadrian modes_txgaintable_index = 8; 2759250003Sadrian } 2760250003Sadrian modes_index = 4; 2761250003Sadrian break; 2762250003Sadrian 2763250003Sadrian case CHANNEL_G_HT40PLUS: 2764250003Sadrian case CHANNEL_G_HT40MINUS: 2765250003Sadrian if (AR_SREV_SCORPION(ah)){ 2766250003Sadrian modes_txgaintable_index = 7; 2767250003Sadrian } 2768250003Sadrian modes_index = 3; 2769250003Sadrian break; 2770250003Sadrian 2771250003Sadrian case CHANNEL_108G: 2772250003Sadrian modes_index = 5; 2773250003Sadrian break; 2774250003Sadrian 2775250003Sadrian default: 2776250003Sadrian HALASSERT(0); 2777250003Sadrian return HAL_EINVAL; 2778250003Sadrian } 2779250008Sadrian#endif 2780250003Sadrian 2781250008Sadrian /* FreeBSD */ 2782250008Sadrian if (IS_CHAN_5GHZ(ichan)) { 2783250008Sadrian if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) { 2784250008Sadrian if (AR_SREV_SCORPION(ah)){ 2785250008Sadrian if (ichan->channel <= 5350){ 2786250008Sadrian modes_txgaintable_index = 2; 2787250008Sadrian }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){ 2788250008Sadrian modes_txgaintable_index = 4; 2789250008Sadrian }else if (ichan->channel > 5600){ 2790250008Sadrian modes_txgaintable_index = 6; 2791250008Sadrian } 2792250008Sadrian } 2793250008Sadrian modes_index = 2; 2794250008Sadrian } else if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_HT20(chan)) { 2795250008Sadrian if (AR_SREV_SCORPION(ah)){ 2796250008Sadrian if (ichan->channel <= 5350){ 2797250008Sadrian modes_txgaintable_index = 1; 2798250008Sadrian }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){ 2799250008Sadrian modes_txgaintable_index = 3; 2800250008Sadrian }else if (ichan->channel > 5600){ 2801250008Sadrian modes_txgaintable_index = 5; 2802250008Sadrian } 2803250008Sadrian } 2804250008Sadrian modes_index = 1; 2805250008Sadrian } else 2806250008Sadrian return HAL_EINVAL; 2807250008Sadrian } else if (IS_CHAN_2GHZ(ichan)) { 2808250008Sadrian if (IEEE80211_IS_CHAN_108G(chan)) { 2809250008Sadrian modes_index = 5; 2810250008Sadrian } else if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) { 2811250008Sadrian if (AR_SREV_SCORPION(ah)){ 2812250008Sadrian modes_txgaintable_index = 7; 2813250008Sadrian } 2814250008Sadrian modes_index = 3; 2815250008Sadrian } else if (IEEE80211_IS_CHAN_HT20(chan) || IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_PUREG(chan)) { 2816250008Sadrian if (AR_SREV_SCORPION(ah)){ 2817250008Sadrian modes_txgaintable_index = 8; 2818250008Sadrian } 2819250008Sadrian modes_index = 4; 2820250008Sadrian } else 2821250008Sadrian return HAL_EINVAL; 2822250008Sadrian } else 2823250008Sadrian return HAL_EINVAL; 2824250008Sadrian 2825250003Sadrian#if 0 2826250003Sadrian /* Set correct Baseband to analog shift setting to access analog chips. */ 2827250003Sadrian OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); 2828250003Sadrian#endif 2829250003Sadrian 2830250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2831250003Sadrian "ar9300_process_ini: " 2832250003Sadrian "Skipping OS-REG-WRITE(ah, AR-PHY(0), 0x00000007)\n"); 2833250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2834250003Sadrian "ar9300_process_ini: no ADDac programming\n"); 2835250003Sadrian 2836250003Sadrian 2837250003Sadrian /* 2838250003Sadrian * Osprey 2.0+ - new INI format. 2839250003Sadrian * Each subsystem has a pre, core, and post array. 2840250003Sadrian */ 2841250003Sadrian for (i = 0; i < ATH_INI_NUM_SPLIT; i++) { 2842250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_soc[i], modes_index); 2843250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_mac[i], modes_index); 2844250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_bb[i], modes_index); 2845250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_radio[i], modes_index); 2846250003Sadrian if ((i == ATH_INI_POST) && (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah))) { 2847250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_radio_post_sys2ant, modes_index); 2848250003Sadrian } 2849250003Sadrian 2850250003Sadrian } 2851250003Sadrian 2852250003Sadrian if (!(AR_SREV_SOC(ah))) { 2853250003Sadrian /* Doubler issue : Some board doesn't work well with MCS15. Turn off doubler after freq locking is complete*/ 2854250003Sadrian //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)); 2855250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2856250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2857250003Sadrian //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)); 2858250003Sadrian 2859250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2860250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2861250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2862250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ 2863250003Sadrian OS_DELAY(200); 2864250003Sadrian 2865250003Sadrian //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)); 2866250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 2867250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 2868250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ 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_DELAY(1); 2872250003Sadrian 2873250003Sadrian //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)); 2874250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2875250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2876250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ 2877250003Sadrian //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)); 2878250003Sadrian 2879250003Sadrian OS_DELAY(200); 2880250003Sadrian 2881250003Sadrian //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)); 2882250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf); 2883250003Sadrian //OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_SYNTH12, 1<< 16); /* clr charge pump */ 2884250003Sadrian //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)); 2885250003Sadrian 2886250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2887250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 2888250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2889250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 2890250003Sadrian OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 2891250003Sadrian 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ 2892250003Sadrian //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)); 2893250003Sadrian } 2894250003Sadrian 2895250003Sadrian /* Write rxgain Array Parameters */ 2896250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain, 1, reg_writes); 2897250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain programming\n"); 2898250003Sadrian 2899250003Sadrian if (AR_SREV_SCORPION(ah)) { 2900250003Sadrian /* Write rxgain bounds Array */ 2901250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, modes_index, reg_writes); 2902250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain table bounds programming\n"); 2903250003Sadrian } 2904250003Sadrian /* UB124 xLNA settings */ 2905250003Sadrian if (AR_SREV_WASP(ah) && ar9300_rx_gain_index_get(ah) == 2) { 2906250003Sadrian#define REG_WRITE(_reg,_val) *((volatile u_int32_t *)(_reg)) = (_val); 2907250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 2908250003Sadrian u_int32_t val; 2909250003Sadrian /* B8040000: bit[0]=0, bit[3]=0; */ 2910250003Sadrian val = REG_READ(0xB8040000); 2911250003Sadrian val &= 0xfffffff6; 2912250003Sadrian REG_WRITE(0xB8040000, val); 2913250003Sadrian /* B804002c: bit[31:24]=0x2e; bit[7:0]=0x2f; */ 2914250003Sadrian val = REG_READ(0xB804002c); 2915250003Sadrian val &= 0x00ffff00; 2916250003Sadrian val |= 0x2e00002f; 2917250003Sadrian REG_WRITE(0xB804002c, val); 2918250003Sadrian /* B804006c: bit[1]=1; */ 2919250003Sadrian val = REG_READ(0xB804006c); 2920250003Sadrian val |= 0x2; 2921250003Sadrian REG_WRITE(0xB804006c, val); 2922250003Sadrian#undef REG_READ 2923250003Sadrian#undef REG_WRITE 2924250003Sadrian } 2925250003Sadrian 2926250003Sadrian 2927250003Sadrian /* Write txgain Array Parameters */ 2928250003Sadrian if (AR_SREV_SCORPION(ah)) { 2929250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_txgaintable_index, 2930250003Sadrian reg_writes); 2931250003Sadrian }else{ 2932250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_index, reg_writes); 2933250003Sadrian } 2934250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Tx Gain programming\n"); 2935250003Sadrian 2936250003Sadrian 2937250003Sadrian /* For 5GHz channels requiring Fast Clock, apply different modal values */ 2938250003Sadrian if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { 2939250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2940250003Sadrian "%s: Fast clock enabled, use special ini values\n", __func__); 2941250003Sadrian REG_WRITE_ARRAY(&ahp->ah_ini_modes_additional, modes_index, reg_writes); 2942250003Sadrian } 2943250003Sadrian 2944250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 2945250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 2946250003Sadrian "%s: use xtal ini for AH9300(ah)->clk_25mhz: %d\n", 2947250003Sadrian __func__, AH9300(ah)->clk_25mhz); 2948250003Sadrian REG_WRITE_ARRAY( 2949250003Sadrian &ahp->ah_ini_modes_additional, 1/*modes_index*/, reg_writes); 2950250003Sadrian } 2951250003Sadrian 2952250003Sadrian if (AR_SREV_WASP(ah) && (AH9300(ah)->clk_25mhz == 0)) { 2953250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Apply 40MHz ini settings\n", __func__); 2954250003Sadrian REG_WRITE_ARRAY( 2955250003Sadrian &ahp->ah_ini_modes_additional_40mhz, 1/*modesIndex*/, reg_writes); 2956250003Sadrian } 2957250003Sadrian 2958250008Sadrian /* Handle Japan Channel 14 channel spreading */ 2959250008Sadrian if (2484 == ichan->channel) { 2960250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_japan2484, 1); 2961250003Sadrian } 2962250003Sadrian 2963250003Sadrian#if 0 2964250003Sadrian if (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah)) { 2965250003Sadrian ar9300_prog_ini(ah, &ahp->ah_ini_BTCOEX_MAX_TXPWR, 1); 2966250003Sadrian } 2967250003Sadrian#endif 2968250003Sadrian 2969250003Sadrian /* Override INI with chip specific configuration */ 2970250003Sadrian ar9300_override_ini(ah, chan); 2971250003Sadrian 2972250003Sadrian /* Setup 11n MAC/Phy mode registers */ 2973250003Sadrian ar9300_set_11n_regs(ah, chan, macmode); 2974250003Sadrian 2975250003Sadrian /* 2976250003Sadrian * Moved ar9300_init_chain_masks() here to ensure the swap bit is set before 2977250003Sadrian * the pdadc table is written. Swap must occur before any radio dependent 2978250003Sadrian * replicated register access. The pdadc curve addressing in particular 2979250003Sadrian * depends on the consistent setting of the swap bit. 2980250003Sadrian */ 2981250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask); 2982250003Sadrian 2983250003Sadrian /* 2984250003Sadrian * Setup the transmit power values. 2985250003Sadrian * 2986250003Sadrian * After the public to private hal channel mapping, ichan contains the 2987250003Sadrian * valid regulatory power value. 2988250003Sadrian * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan. 2989250003Sadrian */ 2990250008Sadrian status = ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan, 2991250003Sadrian ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), 2992250003Sadrian ath_hal_get_twice_max_regpower(ahpriv, ichan, chan), 2993250008Sadrian AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)); 2994250003Sadrian if (status != HAL_OK) { 2995250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 2996250003Sadrian "%s: error init'ing transmit power\n", __func__); 2997250003Sadrian return HAL_EIO; 2998250003Sadrian } 2999250003Sadrian 3000250003Sadrian 3001250003Sadrian return HAL_OK; 3002250003Sadrian#undef N 3003250003Sadrian} 3004250003Sadrian 3005250003Sadrian/* ar9300_is_cal_supp 3006250003Sadrian * Determine if calibration is supported by device and channel flags 3007250003Sadrian */ 3008250003Sadrianinline static HAL_BOOL 3009250008Sadrianar9300_is_cal_supp(struct ath_hal *ah, const struct ieee80211_channel *chan, 3010250003Sadrian HAL_CAL_TYPES cal_type) 3011250003Sadrian{ 3012250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3013250003Sadrian HAL_BOOL retval = AH_FALSE; 3014250003Sadrian 3015250003Sadrian switch (cal_type & ahp->ah_supp_cals) { 3016250003Sadrian case IQ_MISMATCH_CAL: 3017250003Sadrian /* Run IQ Mismatch for non-CCK only */ 3018250008Sadrian if (!IEEE80211_IS_CHAN_B(chan)) { 3019250003Sadrian retval = AH_TRUE; 3020250003Sadrian } 3021250003Sadrian break; 3022250003Sadrian case TEMP_COMP_CAL: 3023250003Sadrian retval = AH_TRUE; 3024250003Sadrian break; 3025250003Sadrian } 3026250003Sadrian 3027250003Sadrian return retval; 3028250003Sadrian} 3029250003Sadrian 3030250003Sadrian 3031250003Sadrian#if 0 3032250003Sadrian/* ar9285_pa_cal 3033250003Sadrian * PA Calibration for Kite 1.1 and later versions of Kite. 3034250003Sadrian * - from system's team. 3035250003Sadrian */ 3036250003Sadrianstatic inline void 3037250003Sadrianar9285_pa_cal(struct ath_hal *ah) 3038250003Sadrian{ 3039250003Sadrian u_int32_t reg_val; 3040250003Sadrian int i, lo_gn, offs_6_1, offs_0; 3041250003Sadrian u_int8_t reflo; 3042250003Sadrian u_int32_t phy_test2_reg_val, phy_adc_ctl_reg_val; 3043250003Sadrian u_int32_t an_top2_reg_val, phy_tst_dac_reg_val; 3044250003Sadrian 3045250003Sadrian 3046250003Sadrian /* Kite 1.1 WAR for Bug 35666 3047250003Sadrian * Increase the LDO value to 1.28V before accessing analog Reg */ 3048250003Sadrian if (AR_SREV_KITE_11(ah)) { 3049250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14) ); 3050250003Sadrian } 3051250003Sadrian an_top2_reg_val = OS_REG_READ(ah, AR9285_AN_TOP2); 3052250003Sadrian 3053250003Sadrian /* set pdv2i pdrxtxbb */ 3054250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1); 3055250003Sadrian reg_val |= ((0x1 << 5) | (0x1 << 7)); 3056250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val); 3057250003Sadrian 3058250003Sadrian /* clear pwddb */ 3059250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G7); 3060250003Sadrian reg_val &= 0xfffffffd; 3061250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G7, reg_val); 3062250003Sadrian 3063250003Sadrian /* clear enpacal */ 3064250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3065250003Sadrian reg_val &= 0xfffff7ff; 3066250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3067250003Sadrian 3068250003Sadrian /* set offcal */ 3069250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2); 3070250003Sadrian reg_val |= (0x1 << 12); 3071250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val); 3072250003Sadrian 3073250003Sadrian /* set pdpadrv1=pdpadrv2=pdpaout=1 */ 3074250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3075250003Sadrian reg_val |= (0x7 << 23); 3076250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3077250003Sadrian 3078250003Sadrian /* Read back reflo, increase it by 1 and write it. */ 3079250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3080250003Sadrian reflo = ((reg_val >> 26) & 0x7); 3081250003Sadrian 3082250003Sadrian if (reflo < 0x7) { 3083250003Sadrian reflo++; 3084250003Sadrian } 3085250003Sadrian reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26)); 3086250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3087250003Sadrian 3088250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3089250003Sadrian reflo = ((reg_val >> 26) & 0x7); 3090250003Sadrian 3091250003Sadrian /* use TX single carrier to transmit 3092250003Sadrian * dac const 3093250003Sadrian * reg. 15 3094250003Sadrian */ 3095250003Sadrian phy_tst_dac_reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST); 3096250003Sadrian OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, ((0x7ff << 11) | 0x7ff)); 3097250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST); 3098250003Sadrian 3099250003Sadrian /* source is dac const 3100250003Sadrian * reg. 2 3101250003Sadrian */ 3102250003Sadrian phy_test2_reg_val = OS_REG_READ(ah, AR_PHY_TEST2); 3103250003Sadrian OS_REG_WRITE(ah, AR_PHY_TEST2, ((0x1 << 7) | (0x1 << 1))); 3104250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_TEST2); 3105250003Sadrian 3106250003Sadrian /* set dac on 3107250003Sadrian * reg. 11 3108250003Sadrian */ 3109250003Sadrian phy_adc_ctl_reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL); 3110250003Sadrian OS_REG_WRITE(ah, AR_PHY_ADC_CTL, 0x80008000); 3111250003Sadrian reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL); 3112250003Sadrian 3113250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP2, (0x1 << 27) | (0x1 << 17) | (0x1 << 16) | 3114250003Sadrian (0x1 << 14) | (0x1 << 12) | (0x1 << 11) | 3115250003Sadrian (0x1 << 7) | (0x1 << 5)); 3116250003Sadrian 3117250003Sadrian OS_DELAY(10); /* 10 usec */ 3118250003Sadrian 3119250003Sadrian /* clear off[6:0] */ 3120250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3121250003Sadrian reg_val &= 0xfc0fffff; 3122250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3123250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3124250003Sadrian reg_val &= 0xfdffffff; 3125250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3126250003Sadrian 3127250003Sadrian offs_6_1 = 0; 3128250003Sadrian for (i = 6; i > 0; i--) { 3129250003Sadrian /* sef off[$k]==1 */ 3130250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3131250003Sadrian reg_val &= 0xfc0fffff; 3132250003Sadrian reg_val = reg_val | (0x1 << (19 + i)) | ((offs_6_1) << 20); 3133250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3134250003Sadrian lo_gn = (OS_REG_READ(ah, AR9285_AN_RF2G9)) & 0x1; 3135250003Sadrian offs_6_1 = offs_6_1 | (lo_gn << (i - 1)); 3136250003Sadrian } 3137250003Sadrian 3138250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); 3139250003Sadrian reg_val &= 0xfc0fffff; 3140250003Sadrian reg_val = reg_val | ((offs_6_1 - 1) << 20); 3141250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); 3142250003Sadrian 3143250003Sadrian /* set off_0=1; */ 3144250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3145250003Sadrian reg_val &= 0xfdffffff; 3146250003Sadrian reg_val = reg_val | (0x1 << 25); 3147250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3148250003Sadrian 3149250003Sadrian lo_gn = OS_REG_READ(ah, AR9285_AN_RF2G9) & 0x1; 3150250003Sadrian offs_0 = lo_gn; 3151250003Sadrian 3152250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3153250003Sadrian reg_val &= 0xfdffffff; 3154250003Sadrian reg_val = reg_val | (offs_0 << 25); 3155250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3156250003Sadrian 3157250003Sadrian /* clear pdv2i */ 3158250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1); 3159250003Sadrian reg_val &= 0xffffff5f; 3160250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val); 3161250003Sadrian 3162250003Sadrian /* set enpacal */ 3163250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3164250003Sadrian reg_val |= (0x1 << 11); 3165250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3166250003Sadrian 3167250003Sadrian /* clear offcal */ 3168250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2); 3169250003Sadrian reg_val &= 0xffffefff; 3170250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val); 3171250003Sadrian 3172250003Sadrian /* set pdpadrv1=pdpadrv2=pdpaout=0 */ 3173250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); 3174250003Sadrian reg_val &= 0xfc7fffff; 3175250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); 3176250003Sadrian 3177250003Sadrian /* Read back reflo, decrease it by 1 and write it. */ 3178250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3179250003Sadrian reflo = (reg_val >> 26) & 0x7; 3180250003Sadrian if (reflo) { 3181250003Sadrian reflo--; 3182250003Sadrian } 3183250003Sadrian reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26)); 3184250003Sadrian OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); 3185250003Sadrian reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); 3186250003Sadrian reflo = (reg_val >> 26) & 0x7; 3187250003Sadrian 3188250003Sadrian /* write back registers */ 3189250003Sadrian OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, phy_tst_dac_reg_val); 3190250003Sadrian OS_REG_WRITE(ah, AR_PHY_TEST2, phy_test2_reg_val); 3191250003Sadrian OS_REG_WRITE(ah, AR_PHY_ADC_CTL, phy_adc_ctl_reg_val); 3192250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP2, an_top2_reg_val); 3193250003Sadrian 3194250003Sadrian /* Kite 1.1 WAR for Bug 35666 3195250003Sadrian * Decrease the LDO value back to 1.20V */ 3196250003Sadrian if (AR_SREV_KITE_11(ah)) { 3197250003Sadrian OS_REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); 3198250003Sadrian } 3199250003Sadrian} 3200250003Sadrian#endif 3201250003Sadrian 3202250003Sadrian/* ar9300_run_init_cals 3203250003Sadrian * Runs non-periodic calibrations 3204250003Sadrian */ 3205250003Sadrianinline static HAL_BOOL 3206250003Sadrianar9300_run_init_cals(struct ath_hal *ah, int init_cal_count) 3207250003Sadrian{ 3208250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3209250003Sadrian HAL_CHANNEL_INTERNAL ichan; /* bogus */ 3210250003Sadrian HAL_BOOL is_cal_done; 3211250003Sadrian HAL_CAL_LIST *curr_cal; 3212250008Sadrian const HAL_PERCAL_DATA *cal_data; 3213250003Sadrian int i; 3214250003Sadrian 3215250003Sadrian curr_cal = ahp->ah_cal_list_curr; 3216250003Sadrian if (curr_cal == AH_NULL) { 3217250003Sadrian return AH_FALSE; 3218250003Sadrian } 3219250008Sadrian cal_data = curr_cal->cal_data; 3220250008Sadrian ichan.calValid = 0; 3221250003Sadrian 3222250003Sadrian for (i = 0; i < init_cal_count; i++) { 3223250003Sadrian /* Reset this Cal */ 3224250003Sadrian ar9300_reset_calibration(ah, curr_cal); 3225250003Sadrian /* Poll for offset calibration complete */ 3226250003Sadrian if (!ath_hal_wait( 3227250008Sadrian ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL, 0)) 3228250003Sadrian { 3229250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3230250003Sadrian "%s: Cal %d failed to complete in 100ms.\n", 3231250003Sadrian __func__, curr_cal->cal_data->cal_type); 3232250003Sadrian /* Re-initialize list pointers for periodic cals */ 3233250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr 3234250003Sadrian = AH_NULL; 3235250003Sadrian return AH_FALSE; 3236250003Sadrian } 3237250003Sadrian /* Run this cal */ 3238250003Sadrian ar9300_per_calibration( 3239250003Sadrian ah, &ichan, ahp->ah_rx_chainmask, curr_cal, &is_cal_done); 3240250003Sadrian if (is_cal_done == AH_FALSE) { 3241250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3242250003Sadrian "%s: Not able to run Init Cal %d.\n", __func__, 3243250003Sadrian curr_cal->cal_data->cal_type); 3244250003Sadrian } 3245250003Sadrian if (curr_cal->cal_next) { 3246250003Sadrian curr_cal = curr_cal->cal_next; 3247250003Sadrian } 3248250003Sadrian } 3249250003Sadrian 3250250003Sadrian /* Re-initialize list pointers for periodic cals */ 3251250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; 3252250003Sadrian return AH_TRUE; 3253250003Sadrian} 3254250003Sadrian 3255250003Sadrian#if 0 3256250003Sadrianstatic void 3257250003Sadrianar9300_tx_carrier_leak_war(struct ath_hal *ah) 3258250003Sadrian{ 3259250003Sadrian unsigned long tx_gain_table_max; 3260250003Sadrian unsigned long reg_bb_cl_map_0_b0 = 0xffffffff; 3261250003Sadrian unsigned long reg_bb_cl_map_1_b0 = 0xffffffff; 3262250003Sadrian unsigned long reg_bb_cl_map_2_b0 = 0xffffffff; 3263250003Sadrian unsigned long reg_bb_cl_map_3_b0 = 0xffffffff; 3264250003Sadrian unsigned long tx_gain, cal_run = 0; 3265250003Sadrian unsigned long cal_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3266250003Sadrian unsigned long cal_gain_index[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3267250003Sadrian unsigned long new_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; 3268250003Sadrian int i, j; 3269250003Sadrian 3270250003Sadrian OS_MEMSET(new_gain, 0, sizeof(new_gain)); 3271250003Sadrian /*printf(" Running TxCarrierLeakWAR\n");*/ 3272250003Sadrian 3273250003Sadrian /* process tx gain table, we use cl_map_hw_gen=0. */ 3274250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_MAP_HW_GEN, 0); 3275250003Sadrian 3276250003Sadrian //the table we used is txbb_gc[2:0], 1dB[2:1]. 3277250003Sadrian tx_gain_table_max = OS_REG_READ_FIELD(ah, 3278250003Sadrian AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX); 3279250003Sadrian 3280250003Sadrian for (i = 0; i <= tx_gain_table_max; i++) { 3281250003Sadrian tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4); 3282250003Sadrian cal_gain[i] = (((tx_gain >> 5)& 0x7) << 2) | 3283250003Sadrian (((tx_gain >> 1) & 0x3) << 0); 3284250003Sadrian if (i == 0) { 3285250003Sadrian cal_gain_index[i] = cal_run; 3286250003Sadrian new_gain[i] = 1; 3287250003Sadrian cal_run++; 3288250003Sadrian } else { 3289250003Sadrian new_gain[i] = 1; 3290250003Sadrian for (j = 0; j < i; j++) { 3291250003Sadrian /* 3292250003Sadrian printf("i=%d, j=%d cal_gain[$i]=0x%04x\n", i, j, cal_gain[i]); 3293250003Sadrian */ 3294250003Sadrian if (new_gain[i]) { 3295250003Sadrian if ((cal_gain[i] != cal_gain[j])) { 3296250003Sadrian new_gain[i] = 1; 3297250003Sadrian } else { 3298250003Sadrian /* if old gain found, use old cal_run value. */ 3299250003Sadrian new_gain[i] = 0; 3300250003Sadrian cal_gain_index[i] = cal_gain_index[j]; 3301250003Sadrian } 3302250003Sadrian } 3303250003Sadrian } 3304250003Sadrian /* if new gain found, increase cal_run */ 3305250003Sadrian if (new_gain[i] == 1) { 3306250003Sadrian cal_gain_index[i] = cal_run; 3307250003Sadrian cal_run++; 3308250003Sadrian } 3309250003Sadrian } 3310250003Sadrian 3311250003Sadrian reg_bb_cl_map_0_b0 = (reg_bb_cl_map_0_b0 & ~(0x1 << i)) | 3312250003Sadrian ((cal_gain_index[i] >> 0 & 0x1) << i); 3313250003Sadrian reg_bb_cl_map_1_b0 = (reg_bb_cl_map_1_b0 & ~(0x1 << i)) | 3314250003Sadrian ((cal_gain_index[i] >> 1 & 0x1) << i); 3315250003Sadrian reg_bb_cl_map_2_b0 = (reg_bb_cl_map_2_b0 & ~(0x1 << i)) | 3316250003Sadrian ((cal_gain_index[i] >> 2 & 0x1) << i); 3317250003Sadrian reg_bb_cl_map_3_b0 = (reg_bb_cl_map_3_b0 & ~(0x1 << i)) | 3318250003Sadrian ((cal_gain_index[i] >> 3 & 0x1) << i); 3319250003Sadrian 3320250003Sadrian /* 3321250003Sadrian printf("i=%2d, cal_gain[$i]= 0x%04x, cal_run= %d, " 3322250003Sadrian "cal_gain_index[i]=%d, new_gain[i] = %d\n", 3323250003Sadrian i, cal_gain[i], cal_run, cal_gain_index[i], new_gain[i]); 3324250003Sadrian */ 3325250003Sadrian } 3326250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B0, reg_bb_cl_map_0_b0); 3327250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B0, reg_bb_cl_map_1_b0); 3328250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B0, reg_bb_cl_map_2_b0); 3329250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B0, reg_bb_cl_map_3_b0); 3330250003Sadrian if (AR_SREV_WASP(ah)) { 3331250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B1, reg_bb_cl_map_0_b0); 3332250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B1, reg_bb_cl_map_1_b0); 3333250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B1, reg_bb_cl_map_2_b0); 3334250003Sadrian OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B1, reg_bb_cl_map_3_b0); 3335250003Sadrian } 3336250003Sadrian} 3337250003Sadrian#endif 3338250003Sadrian 3339250003Sadrian 3340250003Sadrianstatic inline void 3341250003Sadrianar9300_invalidate_saved_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 3342250003Sadrian{ 3343250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3344250003Sadrian if (AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse & 3345250003Sadrian ATH_CAL_REUSE_REDO_IN_FULL_RESET) 3346250003Sadrian { 3347250003Sadrian ichan->one_time_txiqcal_done = AH_FALSE; 3348250003Sadrian ichan->one_time_txclcal_done = AH_FALSE; 3349250003Sadrian } 3350250003Sadrian#endif 3351250003Sadrian} 3352250003Sadrian 3353250003Sadrianstatic inline HAL_BOOL 3354250003Sadrianar9300_restore_rtt_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 3355250003Sadrian{ 3356250003Sadrian HAL_BOOL restore_status = AH_FALSE; 3357250003Sadrian 3358250003Sadrian return restore_status; 3359250003Sadrian} 3360250003Sadrian 3361250003Sadrian/* ar9300_init_cal 3362250003Sadrian * Initialize Calibration infrastructure 3363250003Sadrian */ 3364250003Sadrianstatic inline HAL_BOOL 3365250008Sadrianar9300_init_cal_internal(struct ath_hal *ah, struct ieee80211_channel *chan, 3366250008Sadrian HAL_CHANNEL_INTERNAL *ichan, 3367250008Sadrian HAL_BOOL enable_rtt, HAL_BOOL do_rtt_cal, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr) 3368250003Sadrian{ 3369250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3370250003Sadrian HAL_BOOL txiqcal_success_flag = AH_FALSE; 3371250003Sadrian HAL_BOOL cal_done = AH_FALSE; 3372250003Sadrian int iqcal_idx = 0; 3373250003Sadrian HAL_BOOL do_sep_iq_cal = AH_FALSE; 3374250003Sadrian HAL_BOOL do_agc_cal = do_rtt_cal; 3375250003Sadrian HAL_BOOL is_cal_reusable = AH_TRUE; 3376250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3377250003Sadrian HAL_BOOL cal_reuse_enable = AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse & 3378250003Sadrian ATH_CAL_REUSE_ENABLE; 3379250003Sadrian HAL_BOOL clc_success = AH_FALSE; 3380250003Sadrian int32_t ch_idx, j, cl_tab_reg; 3381250003Sadrian u_int32_t BB_cl_tab_entry = MAX_BB_CL_TABLE_ENTRY; 3382250003Sadrian u_int32_t BB_cl_tab_b[AR9300_MAX_CHAINS] = { 3383250003Sadrian AR_PHY_CL_TAB_0, 3384250003Sadrian AR_PHY_CL_TAB_1, 3385250003Sadrian AR_PHY_CL_TAB_2 3386250003Sadrian }; 3387250003Sadrian#endif 3388250003Sadrian 3389250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 3390250003Sadrian /* Hornet: 1 x 1 */ 3391250003Sadrian ahp->ah_rx_cal_chainmask = 0x1; 3392250003Sadrian ahp->ah_tx_cal_chainmask = 0x1; 3393250003Sadrian } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { 3394250003Sadrian /* Wasp/Jupiter: 2 x 2 */ 3395250003Sadrian ahp->ah_rx_cal_chainmask = 0x3; 3396250003Sadrian ahp->ah_tx_cal_chainmask = 0x3; 3397250003Sadrian } else { 3398250003Sadrian /* 3399250003Sadrian * Osprey needs to be configured for the correct chain mode 3400250003Sadrian * before running AGC/TxIQ cals. 3401250003Sadrian */ 3402250003Sadrian if (ahp->ah_enterprise_mode & AR_ENT_OTP_CHAIN2_DISABLE) { 3403250003Sadrian /* chain 2 disabled - 2 chain mode */ 3404250003Sadrian ahp->ah_rx_cal_chainmask = 0x3; 3405250003Sadrian ahp->ah_tx_cal_chainmask = 0x3; 3406250003Sadrian } else { 3407250003Sadrian ahp->ah_rx_cal_chainmask = 0x7; 3408250003Sadrian ahp->ah_tx_cal_chainmask = 0x7; 3409250003Sadrian } 3410250003Sadrian } 3411250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_cal_chainmask, ahp->ah_tx_cal_chainmask); 3412250003Sadrian 3413250003Sadrian 3414250003Sadrian if (ahp->tx_cl_cal_enable) { 3415250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3416250003Sadrian /* disable Carrie Leak or set do_agc_cal accordingly */ 3417250003Sadrian if (cal_reuse_enable && ichan->one_time_txclcal_done) 3418250003Sadrian { 3419250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 3420250003Sadrian } else 3421250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3422250003Sadrian { 3423250003Sadrian OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 3424250003Sadrian do_agc_cal = AH_TRUE; 3425250003Sadrian } 3426250003Sadrian } 3427250003Sadrian 3428250003Sadrian /* Do Tx IQ Calibration here for osprey hornet and wasp */ 3429250003Sadrian /* XXX: For initial wasp bringup - check and enable this */ 3430250003Sadrian /* EV 74233: Tx IQ fails to complete for half/quarter rates */ 3431250008Sadrian if (!(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { 3432250003Sadrian if (ahp->tx_iq_cal_enable) { 3433250003Sadrian /* this should be eventually moved to INI file */ 3434250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah), 3435250003Sadrian AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); 3436250003Sadrian 3437250003Sadrian /* 3438250003Sadrian * For poseidon and later chips, 3439250003Sadrian * Tx IQ cal HW run will be a part of AGC calibration 3440250003Sadrian */ 3441250003Sadrian if (ahp->tx_iq_cal_during_agc_cal) { 3442250003Sadrian /* 3443250003Sadrian * txiqcal_success_flag always set to 1 to run 3444250003Sadrian * ar9300_tx_iq_cal_post_proc 3445250003Sadrian * if following AGC cal passes 3446250003Sadrian */ 3447250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3448250003Sadrian if (!cal_reuse_enable || !ichan->one_time_txiqcal_done) 3449250003Sadrian { 3450250003Sadrian txiqcal_success_flag = AH_TRUE; 3451250003Sadrian OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3452250003Sadrian OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) | 3453250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 3454250003Sadrian } else { 3455250003Sadrian OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3456250003Sadrian OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) & 3457250003Sadrian (~AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)); 3458250003Sadrian } 3459250003Sadrian#else 3460250003Sadrian if (OS_REG_READ_FIELD(ah, 3461250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0(ah), 3462250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)){ 3463250003Sadrian if (apply_last_iqcorr == AH_TRUE) { 3464250003Sadrian OS_REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 3465250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 3466250003Sadrian txiqcal_success_flag = AH_FALSE; 3467250003Sadrian } else { 3468250003Sadrian txiqcal_success_flag = AH_TRUE; 3469250003Sadrian } 3470250003Sadrian }else{ 3471250003Sadrian txiqcal_success_flag = AH_FALSE; 3472250003Sadrian } 3473250003Sadrian#endif 3474250003Sadrian if (txiqcal_success_flag) { 3475250003Sadrian do_agc_cal = AH_TRUE; 3476250003Sadrian } 3477250003Sadrian } else 3478250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3479250003Sadrian if (!cal_reuse_enable || !ichan->one_time_txiqcal_done) 3480250003Sadrian#endif 3481250003Sadrian { 3482250003Sadrian do_sep_iq_cal = AH_TRUE; 3483250003Sadrian do_agc_cal = AH_TRUE; 3484250003Sadrian } 3485250003Sadrian } 3486250003Sadrian } 3487250003Sadrian 3488250003Sadrian#if ATH_SUPPORT_MCI 3489250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 3490250003Sadrian IS_CHAN_2GHZ(ichan) && 3491250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 3492250003Sadrian do_agc_cal && 3493250008Sadrian !(ah->ah_config.ath_hal_mci_config & 3494250003Sadrian ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 3495250003Sadrian { 3496250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 3497250003Sadrian 3498250003Sadrian /* Send CAL_REQ only when BT is AWAKE. */ 3499250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_REQ 0x%X\n", 3500250003Sadrian __func__, ahp->ah_mci_wlan_cal_seq); 3501250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_REQ); 3502250003Sadrian payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_seq++; 3503250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 3504250003Sadrian 3505250003Sadrian /* Wait BT_CAL_GRANT for 50ms */ 3506250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3507250003Sadrian "(MCI) %s: Wait for BT_CAL_GRANT\n", __func__); 3508250003Sadrian if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) 3509250003Sadrian { 3510250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3511250003Sadrian "(MCI) %s: Got BT_CAL_GRANT.\n", __func__); 3512250003Sadrian } 3513250003Sadrian else { 3514250003Sadrian is_cal_reusable = AH_FALSE; 3515250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 3516250003Sadrian "(MCI) %s: BT is not responding.\n", __func__); 3517250003Sadrian } 3518250003Sadrian } 3519250003Sadrian#endif /* ATH_SUPPORT_MCI */ 3520250003Sadrian 3521250003Sadrian if (do_sep_iq_cal) 3522250003Sadrian { 3523250003Sadrian /* enable Tx IQ Calibration HW for osprey/hornet/wasp */ 3524250003Sadrian txiqcal_success_flag = ar9300_tx_iq_cal_hw_run(ah); 3525250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); 3526250003Sadrian OS_DELAY(5); 3527250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 3528250003Sadrian } 3529250003Sadrian#if 0 3530250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { 3531250003Sadrian ar9300_tx_carrier_leak_war(ah); 3532250003Sadrian } 3533250003Sadrian#endif 3534250003Sadrian /* 3535250003Sadrian * Calibrate the AGC 3536250003Sadrian * 3537250003Sadrian * Tx IQ cal is a part of AGC cal for Jupiter/Poseidon, etc. 3538250003Sadrian * please enable the bit of txiqcal_control_0[31] in INI file 3539250003Sadrian * for Jupiter/Poseidon/etc. 3540250003Sadrian */ 3541250003Sadrian if(!AR_SREV_SCORPION(ah)) { 3542250003Sadrian if (do_agc_cal || !skip_if_none) { 3543250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3544250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3545250003Sadrian 3546250003Sadrian /* Poll for offset calibration complete */ 3547250003Sadrian cal_done = ath_hal_wait(ah, 3548250008Sadrian AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0); 3549250003Sadrian if (!cal_done) { 3550250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3551250003Sadrian "(FCS) CAL NOT DONE!!! - %d\n", ichan->channel); 3552250003Sadrian } 3553250003Sadrian } else { 3554250003Sadrian cal_done = AH_TRUE; 3555250003Sadrian } 3556250003Sadrian /* 3557250003Sadrian * Tx IQ cal post-processing in SW 3558250003Sadrian * This part of code should be common to all chips, 3559250003Sadrian * no chip specific code for Jupiter/Posdeion except for register names. 3560250003Sadrian */ 3561250003Sadrian if (txiqcal_success_flag) { 3562251098Sadrian ar9300_tx_iq_cal_post_proc(ah,ichan, 1, 1,is_cal_reusable, AH_FALSE); 3563250003Sadrian } 3564250003Sadrian } else { 3565250003Sadrian if (!txiqcal_success_flag) { 3566250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3567250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3568250008Sadrian if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 3569250008Sadrian 0)) { 3570250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3571250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3572250003Sadrian "noisy environment?\n", __func__); 3573250003Sadrian return AH_FALSE; 3574250003Sadrian } 3575250003Sadrian if (apply_last_iqcorr == AH_TRUE) { 3576250003Sadrian ar9300_tx_iq_cal_post_proc(ah, ichan, 0, 0, is_cal_reusable, AH_TRUE); 3577250003Sadrian } 3578250003Sadrian } else { 3579250003Sadrian for (iqcal_idx=0;iqcal_idx<MAXIQCAL;iqcal_idx++) { 3580250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3581250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); 3582250003Sadrian 3583250003Sadrian /* Poll for offset calibration complete */ 3584250003Sadrian if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, 3585250008Sadrian AR_PHY_AGC_CONTROL_CAL, 0)) { 3586250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3587250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3588250003Sadrian "noisy environment?\n", __func__); 3589250003Sadrian return AH_FALSE; 3590250003Sadrian } 3591250003Sadrian /* 3592250003Sadrian * Tx IQ cal post-processing in SW 3593250003Sadrian * This part of code should be common to all chips, 3594250003Sadrian * no chip specific code for Jupiter/Posdeion except for register names. 3595250003Sadrian */ 3596250003Sadrian ar9300_tx_iq_cal_post_proc(ah, ichan, iqcal_idx+1, MAXIQCAL, is_cal_reusable, AH_FALSE); 3597250003Sadrian } 3598250003Sadrian } 3599250003Sadrian } 3600250003Sadrian 3601250003Sadrian 3602250003Sadrian#if ATH_SUPPORT_MCI 3603250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 3604250003Sadrian IS_CHAN_2GHZ(ichan) && 3605250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 3606250003Sadrian do_agc_cal && 3607250008Sadrian !(ah->ah_config.ath_hal_mci_config & 3608250003Sadrian ATH_MCI_CONFIG_DISABLE_MCI_CAL)) 3609250003Sadrian { 3610250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 3611250003Sadrian 3612250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_DONE 0x%X\n", 3613250003Sadrian __func__, ahp->ah_mci_wlan_cal_done); 3614250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); 3615250003Sadrian payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_done++; 3616250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 3617250003Sadrian } 3618250003Sadrian#endif /* ATH_SUPPORT_MCI */ 3619250003Sadrian 3620250003Sadrian 3621250003Sadrian if (!cal_done && !AR_SREV_SCORPION(ah) ) 3622250003Sadrian { 3623250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3624250003Sadrian "%s: offset calibration failed to complete in 1ms; " 3625250003Sadrian "noisy environment?\n", __func__); 3626250003Sadrian return AH_FALSE; 3627250003Sadrian } 3628250003Sadrian 3629250003Sadrian#if 0 3630250003Sadrian /* Beacon stuck fix, refer to EV 120056 */ 3631250003Sadrian if(IS_CHAN_2GHZ(chan) && AR_SREV_SCORPION(ah)) 3632250003Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING5, OS_REG_READ(ah,AR_PHY_TIMING5) & ~AR_PHY_TIMING5_CYCPWR_THR1_ENABLE); 3633250003Sadrian#endif 3634250003Sadrian 3635250003Sadrian#if 0 3636250003Sadrian /* Do PA Calibration */ 3637250003Sadrian if (AR_SREV_KITE(ah) && AR_SREV_KITE_11_OR_LATER(ah)) { 3638250003Sadrian ar9285_pa_cal(ah); 3639250003Sadrian } 3640250003Sadrian#endif 3641250003Sadrian 3642250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3643250003Sadrian if (ichan->one_time_txiqcal_done) { 3644250003Sadrian ar9300_tx_iq_cal_apply(ah, ichan); 3645250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3646250003Sadrian "(FCS) TXIQCAL applied - %d\n", ichan->channel); 3647250003Sadrian } 3648250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3649250003Sadrian 3650250003Sadrian#if ATH_SUPPORT_CAL_REUSE 3651250003Sadrian if (cal_reuse_enable && ahp->tx_cl_cal_enable) 3652250003Sadrian { 3653250003Sadrian clc_success = (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & 3654250003Sadrian AR_PHY_AGC_CONTROL_CLC_SUCCESS) ? 1 : 0; 3655250003Sadrian 3656250003Sadrian if (ichan->one_time_txclcal_done) 3657250003Sadrian { 3658250003Sadrian /* reapply CL cal results */ 3659250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 3660250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 3661250003Sadrian continue; 3662250003Sadrian } 3663250003Sadrian cl_tab_reg = BB_cl_tab_b[ch_idx]; 3664250003Sadrian for (j = 0; j < BB_cl_tab_entry; j++) { 3665250003Sadrian OS_REG_WRITE(ah, cl_tab_reg, ichan->tx_clcal[ch_idx][j]); 3666250003Sadrian cl_tab_reg += 4;; 3667250003Sadrian } 3668250003Sadrian } 3669250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3670250003Sadrian "(FCS) TX CL CAL applied - %d\n", ichan->channel); 3671250003Sadrian } 3672250003Sadrian else if (is_cal_reusable && clc_success) { 3673250003Sadrian /* save CL cal results */ 3674250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 3675250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 3676250003Sadrian continue; 3677250003Sadrian } 3678250003Sadrian cl_tab_reg = BB_cl_tab_b[ch_idx]; 3679250003Sadrian for (j = 0; j < BB_cl_tab_entry; j++) { 3680250003Sadrian ichan->tx_clcal[ch_idx][j] = OS_REG_READ(ah, cl_tab_reg); 3681250003Sadrian cl_tab_reg += 4; 3682250003Sadrian } 3683250003Sadrian } 3684250003Sadrian ichan->one_time_txclcal_done = AH_TRUE; 3685250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 3686250003Sadrian "(FCS) TX CL CAL saved - %d\n", ichan->channel); 3687250003Sadrian } 3688250003Sadrian } 3689250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */ 3690250003Sadrian 3691250003Sadrian /* Revert chainmasks to their original values before NF cal */ 3692250003Sadrian ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask); 3693250003Sadrian 3694250003Sadrian#if !FIX_NOISE_FLOOR 3695250003Sadrian /* 3696250003Sadrian * Do NF calibration after DC offset and other CALs. 3697250003Sadrian * Per system engineers, noise floor value can sometimes be 20 dB 3698250003Sadrian * higher than normal value if DC offset and noise floor cal are 3699250003Sadrian * triggered at the same time. 3700250003Sadrian */ 3701250003Sadrian OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 3702250003Sadrian OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); 3703250003Sadrian#endif 3704250003Sadrian 3705250003Sadrian /* Initialize list pointers */ 3706250003Sadrian ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; 3707250003Sadrian 3708250003Sadrian /* 3709250003Sadrian * Enable IQ, ADC Gain, ADC DC Offset Cals 3710250003Sadrian */ 3711250003Sadrian /* Setup all non-periodic, init time only calibrations */ 3712250003Sadrian /* XXX: Init DC Offset not working yet */ 3713250003Sadrian#ifdef not_yet 3714250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, ADC_DC_INIT_CAL)) { 3715250003Sadrian INIT_CAL(&ahp->ah_adc_dc_cal_init_data); 3716250003Sadrian INSERT_CAL(ahp, &ahp->ah_adc_dc_cal_init_data); 3717250003Sadrian } 3718250003Sadrian 3719250003Sadrian /* Initialize current pointer to first element in list */ 3720250003Sadrian ahp->ah_cal_list_curr = ahp->ah_cal_list; 3721250003Sadrian 3722250003Sadrian if (ahp->ah_cal_list_curr) { 3723250003Sadrian if (ar9300_run_init_cals(ah, 0) == AH_FALSE) { 3724250003Sadrian return AH_FALSE; 3725250003Sadrian } 3726250003Sadrian } 3727250003Sadrian#endif 3728250003Sadrian /* end - Init time calibrations */ 3729250003Sadrian 3730250003Sadrian /* If Cals are supported, add them to list via INIT/INSERT_CAL */ 3731250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, IQ_MISMATCH_CAL)) { 3732250003Sadrian INIT_CAL(&ahp->ah_iq_cal_data); 3733250003Sadrian INSERT_CAL(ahp, &ahp->ah_iq_cal_data); 3734250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3735250003Sadrian "%s: enabling IQ Calibration.\n", __func__); 3736250003Sadrian } 3737250003Sadrian if (AH_TRUE == ar9300_is_cal_supp(ah, chan, TEMP_COMP_CAL)) { 3738250003Sadrian INIT_CAL(&ahp->ah_temp_comp_cal_data); 3739250003Sadrian INSERT_CAL(ahp, &ahp->ah_temp_comp_cal_data); 3740250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3741250003Sadrian "%s: enabling Temperature Compensation Calibration.\n", __func__); 3742250003Sadrian } 3743250003Sadrian 3744250003Sadrian /* Initialize current pointer to first element in list */ 3745250003Sadrian ahp->ah_cal_list_curr = ahp->ah_cal_list; 3746250003Sadrian 3747250003Sadrian /* Reset state within current cal */ 3748250003Sadrian if (ahp->ah_cal_list_curr) { 3749250003Sadrian ar9300_reset_calibration(ah, ahp->ah_cal_list_curr); 3750250003Sadrian } 3751250003Sadrian 3752250003Sadrian /* Mark all calibrations on this channel as being invalid */ 3753250008Sadrian ichan->calValid = 0; 3754250003Sadrian 3755250003Sadrian return AH_TRUE; 3756250003Sadrian} 3757250003Sadrian 3758250003Sadrianstatic inline HAL_BOOL 3759250008Sadrianar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr) 3760250003Sadrian{ 3761250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 3762250003Sadrian HAL_BOOL do_rtt_cal = AH_TRUE; 3763250003Sadrian HAL_BOOL enable_rtt = AH_FALSE; 3764250003Sadrian 3765250003Sadrian HALASSERT(ichan); 3766250003Sadrian 3767250003Sadrian return ar9300_init_cal_internal(ah, chan, ichan, enable_rtt, do_rtt_cal, skip_if_none, apply_last_iqcorr); 3768250003Sadrian} 3769250003Sadrian 3770250003Sadrian/* ar9300_reset_cal_valid 3771250003Sadrian * Entry point for upper layers to restart current cal. 3772250003Sadrian * Reset the calibration valid bit in channel. 3773250003Sadrian */ 3774250003Sadrianvoid 3775250008Sadrianar9300_reset_cal_valid(struct ath_hal *ah, const struct ieee80211_channel *chan, 3776250003Sadrian HAL_BOOL *is_cal_done, u_int32_t cal_type) 3777250003Sadrian{ 3778250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3779250003Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 3780250003Sadrian HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr; 3781250003Sadrian 3782250003Sadrian *is_cal_done = AH_TRUE; 3783250003Sadrian 3784250003Sadrian if (curr_cal == AH_NULL) { 3785250003Sadrian return; 3786250003Sadrian } 3787250003Sadrian if (ichan == AH_NULL) { 3788250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3789250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 3790250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 3791250003Sadrian return; 3792250003Sadrian } 3793250003Sadrian 3794250003Sadrian if (!(cal_type & IQ_MISMATCH_CAL)) { 3795250003Sadrian *is_cal_done = AH_FALSE; 3796250003Sadrian return; 3797250003Sadrian } 3798250003Sadrian 3799250003Sadrian /* Expected that this calibration has run before, post-reset. 3800250003Sadrian * Current state should be done 3801250003Sadrian */ 3802250003Sadrian if (curr_cal->cal_state != CAL_DONE) { 3803250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3804250003Sadrian "%s: Calibration state incorrect, %d\n", 3805250003Sadrian __func__, curr_cal->cal_state); 3806250003Sadrian return; 3807250003Sadrian } 3808250003Sadrian 3809250003Sadrian /* Verify Cal is supported on this channel */ 3810250003Sadrian if (ar9300_is_cal_supp(ah, chan, curr_cal->cal_data->cal_type) == AH_FALSE) { 3811250003Sadrian return; 3812250003Sadrian } 3813250003Sadrian 3814250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 3815250003Sadrian "%s: Resetting Cal %d state for channel %u/0x%x\n", __func__, 3816250008Sadrian curr_cal->cal_data->cal_type, chan->ic_freq, chan->ic_flags); 3817250003Sadrian 3818250003Sadrian /* Disable cal validity in channel */ 3819250008Sadrian ichan->calValid &= ~curr_cal->cal_data->cal_type; 3820250003Sadrian curr_cal->cal_state = CAL_WAITING; 3821250003Sadrian /* Indicate to upper layers that we need polling */ 3822250003Sadrian *is_cal_done = AH_FALSE; 3823250003Sadrian} 3824250003Sadrian 3825250003Sadrianstatic inline void 3826250003Sadrianar9300_set_dma(struct ath_hal *ah) 3827250003Sadrian{ 3828250003Sadrian u_int32_t regval; 3829250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3830250003Sadrian 3831250003Sadrian#if 0 3832250003Sadrian /* 3833250003Sadrian * set AHB_MODE not to do cacheline prefetches 3834250003Sadrian */ 3835250003Sadrian regval = OS_REG_READ(ah, AR_AHB_MODE); 3836250003Sadrian OS_REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); 3837250003Sadrian#endif 3838250003Sadrian 3839250003Sadrian /* 3840250003Sadrian * let mac dma reads be in 128 byte chunks 3841250003Sadrian */ 3842250003Sadrian regval = OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; 3843250003Sadrian OS_REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); 3844250003Sadrian 3845250003Sadrian /* 3846250003Sadrian * Restore TX Trigger Level to its pre-reset value. 3847250003Sadrian * The initial value depends on whether aggregation is enabled, and is 3848250003Sadrian * adjusted whenever underruns are detected. 3849250003Sadrian */ 3850250003Sadrian /* 3851250003Sadrian OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, AH_PRIVATE(ah)->ah_tx_trig_level); 3852250003Sadrian */ 3853250003Sadrian /* 3854250003Sadrian * Osprey 1.0 bug (EV 61936). Don't change trigger level from .ini default. 3855250003Sadrian * Osprey 2.0 - hardware recommends using the default INI settings. 3856250003Sadrian */ 3857250003Sadrian#if 0 3858250003Sadrian OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, 0x3f); 3859250003Sadrian#endif 3860250003Sadrian /* 3861250003Sadrian * let mac dma writes be in 128 byte chunks 3862250003Sadrian */ 3863250003Sadrian regval = OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; 3864250003Sadrian OS_REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); 3865250003Sadrian 3866250003Sadrian /* 3867250003Sadrian * Setup receive FIFO threshold to hold off TX activities 3868250003Sadrian */ 3869250003Sadrian OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); 3870250003Sadrian 3871250003Sadrian /* 3872250003Sadrian * reduce the number of usable entries in PCU TXBUF to avoid 3873250003Sadrian * wrap around bugs. (bug 20428) 3874250003Sadrian */ 3875250003Sadrian 3876250003Sadrian if (AR_SREV_WASP(ah) && 3877250003Sadrian (AH_PRIVATE((ah))->ah_macRev > AR_SREV_REVISION_WASP_12)) { 3878250003Sadrian /* Wasp 1.3 fix for EV#85395 requires usable entries 3879250003Sadrian * to be set to 0x500 3880250003Sadrian */ 3881250003Sadrian OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, 0x500); 3882250003Sadrian } else { 3883250003Sadrian OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); 3884250003Sadrian } 3885250003Sadrian 3886250003Sadrian /* 3887250003Sadrian * Enable HPQ for UAPSD 3888250003Sadrian */ 3889250003Sadrian if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { 3890250003Sadrian OS_REG_WRITE(ah, AR_HP_Q_CONTROL, 3891250003Sadrian AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN); 3892250003Sadrian } 3893250003Sadrian 3894250003Sadrian /* 3895250003Sadrian * set the transmit status ring 3896250003Sadrian */ 3897250003Sadrian ar9300_reset_tx_status_ring(ah); 3898250003Sadrian 3899250003Sadrian /* 3900250003Sadrian * set rxbp threshold. Must be non-zero for RX_EOL to occur. 3901250003Sadrian * For Osprey 2.0+, keep the original thresholds 3902250003Sadrian * otherwise performance is lost due to excessive RX EOL interrupts. 3903250003Sadrian */ 3904250003Sadrian OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1); 3905250003Sadrian OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1); 3906250003Sadrian 3907250003Sadrian /* 3908250003Sadrian * set receive buffer size. 3909250003Sadrian */ 3910250003Sadrian if (ahp->rx_buf_size) { 3911250003Sadrian OS_REG_WRITE(ah, AR_DATABUF, ahp->rx_buf_size); 3912250003Sadrian } 3913250003Sadrian} 3914250003Sadrian 3915250003Sadrianstatic inline void 3916250008Sadrianar9300_init_bb(struct ath_hal *ah, struct ieee80211_channel *chan) 3917250003Sadrian{ 3918250003Sadrian u_int32_t synth_delay; 3919250003Sadrian 3920250003Sadrian /* 3921250003Sadrian * Wait for the frequency synth to settle (synth goes on 3922250003Sadrian * via AR_PHY_ACTIVE_EN). Read the phy active delay register. 3923250003Sadrian * Value is in 100ns increments. 3924250003Sadrian */ 3925250003Sadrian synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; 3926250008Sadrian if (IEEE80211_IS_CHAN_CCK(chan)) { 3927250003Sadrian synth_delay = (4 * synth_delay) / 22; 3928250003Sadrian } else { 3929250003Sadrian synth_delay /= 10; 3930250003Sadrian } 3931250003Sadrian 3932250003Sadrian /* Activate the PHY (includes baseband activate + synthesizer on) */ 3933250003Sadrian OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 3934250003Sadrian 3935250003Sadrian /* 3936250003Sadrian * There is an issue if the AP starts the calibration before 3937250003Sadrian * the base band timeout completes. This could result in the 3938250003Sadrian * rx_clear AH_FALSE triggering. As a workaround we add delay an 3939250003Sadrian * extra BASE_ACTIVATE_DELAY usecs to ensure this condition 3940250003Sadrian * does not happen. 3941250003Sadrian */ 3942250003Sadrian OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY); 3943250003Sadrian} 3944250003Sadrian 3945250003Sadrianstatic inline void 3946250003Sadrianar9300_init_interrupt_masks(struct ath_hal *ah, HAL_OPMODE opmode) 3947250003Sadrian{ 3948250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 3949250003Sadrian u_int32_t msi_cfg = 0; 3950250003Sadrian u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; 3951250003Sadrian 3952250003Sadrian /* 3953250003Sadrian * Setup interrupt handling. Note that ar9300_reset_tx_queue 3954250003Sadrian * manipulates the secondary IMR's as queues are enabled 3955250003Sadrian * and disabled. This is done with RMW ops to insure the 3956250003Sadrian * settings we make here are preserved. 3957250003Sadrian */ 3958250003Sadrian ahp->ah_mask_reg = 3959250003Sadrian AR_IMR_TXERR | AR_IMR_TXURN | 3960250003Sadrian AR_IMR_RXERR | AR_IMR_RXORN | 3961250003Sadrian AR_IMR_BCNMISC; 3962250003Sadrian 3963250003Sadrian if (ahp->ah_intr_mitigation_rx) { 3964250003Sadrian /* enable interrupt mitigation for rx */ 3965250003Sadrian ahp->ah_mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR | AR_IMR_RXOK_HP; 3966250003Sadrian msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR; 3967250003Sadrian } else { 3968250003Sadrian ahp->ah_mask_reg |= AR_IMR_RXOK_LP | AR_IMR_RXOK_HP; 3969250003Sadrian msi_cfg |= AR_INTCFG_MSI_RXOK; 3970250003Sadrian } 3971250003Sadrian if (ahp->ah_intr_mitigation_tx) { 3972250003Sadrian /* enable interrupt mitigation for tx */ 3973250003Sadrian ahp->ah_mask_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR; 3974250003Sadrian msi_cfg |= AR_INTCFG_MSI_TXINTM | AR_INTCFG_MSI_TXMINTR; 3975250003Sadrian } else { 3976250003Sadrian ahp->ah_mask_reg |= AR_IMR_TXOK; 3977250003Sadrian msi_cfg |= AR_INTCFG_MSI_TXOK; 3978250003Sadrian } 3979250003Sadrian if (opmode == HAL_M_HOSTAP) { 3980250003Sadrian ahp->ah_mask_reg |= AR_IMR_MIB; 3981250003Sadrian } 3982250003Sadrian 3983250003Sadrian OS_REG_WRITE(ah, AR_IMR, ahp->ah_mask_reg); 3984250003Sadrian OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); 3985250003Sadrian ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2); 3986250003Sadrian 3987250008Sadrian if (ah->ah_config.ath_hal_enable_msi) { 3988250003Sadrian /* Cache MSI register value */ 3989250003Sadrian ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI)); 3990250003Sadrian ahp->ah_msi_reg |= AR_PCIE_MSI_HW_DBI_WR_EN; 3991250003Sadrian if (AR_SREV_POSEIDON(ah)) { 3992250003Sadrian ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; 3993250003Sadrian } else { 3994250003Sadrian ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR; 3995250003Sadrian } 3996250003Sadrian /* Program MSI configuration */ 3997250003Sadrian OS_REG_WRITE(ah, AR_INTCFG, msi_cfg); 3998250003Sadrian } 3999250003Sadrian 4000250003Sadrian /* 4001250003Sadrian * debug - enable to see all synchronous interrupts status 4002250003Sadrian */ 4003250003Sadrian /* Clear any pending sync cause interrupts */ 4004250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE), 0xFFFFFFFF); 4005250003Sadrian 4006250003Sadrian /* Allow host interface sync interrupt sources to set cause bit */ 4007250003Sadrian if (AR_SREV_POSEIDON(ah)) { 4008250003Sadrian sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; 4009250003Sadrian } 4010250003Sadrian else if (AR_SREV_WASP(ah)) { 4011250003Sadrian sync_en_def = AR9340_INTR_SYNC_DEFAULT; 4012250003Sadrian } 4013250003Sadrian OS_REG_WRITE(ah, 4014250003Sadrian AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), sync_en_def); 4015250003Sadrian 4016250003Sadrian /* _Disable_ host interface sync interrupt when cause bits set */ 4017250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 0); 4018250003Sadrian 4019250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0); 4020250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 0); 4021250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE), 0); 4022250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK), 0); 4023250003Sadrian} 4024250003Sadrian 4025250003Sadrianstatic inline void 4026250003Sadrianar9300_init_qos(struct ath_hal *ah) 4027250003Sadrian{ 4028250003Sadrian OS_REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); /* XXX magic */ 4029250003Sadrian OS_REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); /* XXX magic */ 4030250003Sadrian 4031250003Sadrian /* Turn on NOACK Support for QoS packets */ 4032250003Sadrian OS_REG_WRITE(ah, AR_QOS_NO_ACK, 4033250003Sadrian SM(2, AR_QOS_NO_ACK_TWO_BIT) | 4034250003Sadrian SM(5, AR_QOS_NO_ACK_BIT_OFF) | 4035250003Sadrian SM(0, AR_QOS_NO_ACK_BYTE_OFF)); 4036250003Sadrian 4037250003Sadrian /* 4038250003Sadrian * initialize TXOP for all TIDs 4039250003Sadrian */ 4040250003Sadrian OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); 4041250003Sadrian OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); 4042250003Sadrian OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); 4043250003Sadrian OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); 4044250003Sadrian OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); 4045250003Sadrian} 4046250003Sadrian 4047250003Sadrianstatic inline void 4048250003Sadrianar9300_init_user_settings(struct ath_hal *ah) 4049250003Sadrian{ 4050250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4051250003Sadrian 4052250003Sadrian /* Restore user-specified settings */ 4053250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, 4054250003Sadrian "--AP %s ahp->ah_misc_mode 0x%x\n", __func__, ahp->ah_misc_mode); 4055250003Sadrian if (ahp->ah_misc_mode != 0) { 4056250003Sadrian OS_REG_WRITE(ah, 4057250003Sadrian AR_PCU_MISC, OS_REG_READ(ah, AR_PCU_MISC) | ahp->ah_misc_mode); 4058250003Sadrian } 4059250003Sadrian if (ahp->ah_get_plcp_hdr) { 4060250003Sadrian OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM); 4061250003Sadrian } 4062250003Sadrian if (ahp->ah_slot_time != (u_int) -1) { 4063250003Sadrian ar9300_set_slot_time(ah, ahp->ah_slot_time); 4064250003Sadrian } 4065250003Sadrian if (ahp->ah_ack_timeout != (u_int) -1) { 4066250003Sadrian ar9300_set_ack_timeout(ah, ahp->ah_ack_timeout); 4067250003Sadrian } 4068250003Sadrian if (AH_PRIVATE(ah)->ah_diagreg != 0) { 4069250003Sadrian OS_REG_SET_BIT(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 4070250003Sadrian } 4071250003Sadrian if (ahp->ah_beacon_rssi_threshold != 0) { 4072250003Sadrian ar9300_set_hw_beacon_rssi_threshold(ah, ahp->ah_beacon_rssi_threshold); 4073250003Sadrian } 4074250003Sadrian#ifdef ATH_SUPPORT_DFS 4075250003Sadrian if (ahp->ah_cac_quiet_enabled) { 4076250003Sadrian ar9300_cac_tx_quiet(ah, 1); 4077250003Sadrian } 4078250003Sadrian#endif /* ATH_SUPPORT_DFS */ 4079250003Sadrian} 4080250003Sadrian 4081250003Sadrianint 4082250003Sadrianar9300_get_spur_info(struct ath_hal * ah, int *enable, int len, u_int16_t *freq) 4083250003Sadrian{ 4084250008Sadrian// struct ath_hal_private *ap = AH_PRIVATE(ah); 4085250003Sadrian int i, j; 4086250003Sadrian 4087250003Sadrian for (i = 0; i < len; i++) { 4088250003Sadrian freq[i] = 0; 4089250003Sadrian } 4090250003Sadrian 4091250008Sadrian *enable = ah->ah_config.ath_hal_spur_mode; 4092250003Sadrian for (i = 0, j = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 4093250008Sadrian if (AH9300(ah)->ath_hal_spur_chans[i][0] != AR_NO_SPUR) { 4094250008Sadrian freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][0]; 4095250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 4096250008Sadrian "1. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][0]); 4097250003Sadrian } 4098250008Sadrian if (AH9300(ah)->ath_hal_spur_chans[i][1] != AR_NO_SPUR) { 4099250008Sadrian freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][1]; 4100250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, 4101250008Sadrian "2. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][1]); 4102250003Sadrian } 4103250003Sadrian } 4104250003Sadrian 4105250003Sadrian return 0; 4106250003Sadrian} 4107250003Sadrian 4108250003Sadrian#define ATH_HAL_2GHZ_FREQ_MIN 20000 4109250003Sadrian#define ATH_HAL_2GHZ_FREQ_MAX 29999 4110250003Sadrian#define ATH_HAL_5GHZ_FREQ_MIN 50000 4111250003Sadrian#define ATH_HAL_5GHZ_FREQ_MAX 59999 4112250003Sadrian 4113250008Sadrian#if 0 4114250003Sadrianint 4115250003Sadrianar9300_set_spur_info(struct ath_hal * ah, int enable, int len, u_int16_t *freq) 4116250003Sadrian{ 4117250003Sadrian struct ath_hal_private *ap = AH_PRIVATE(ah); 4118250003Sadrian int i, j, k; 4119250003Sadrian 4120250003Sadrian ap->ah_config.ath_hal_spur_mode = enable; 4121250003Sadrian 4122250003Sadrian if (ap->ah_config.ath_hal_spur_mode == SPUR_ENABLE_IOCTL) { 4123250003Sadrian for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 4124250008Sadrian AH9300(ah)->ath_hal_spur_chans[i][0] = AR_NO_SPUR; 4125250008Sadrian AH9300(ah)->ath_hal_spur_chans[i][1] = AR_NO_SPUR; 4126250003Sadrian } 4127250003Sadrian for (i = 0, j = 0, k = 0; i < len; i++) { 4128250003Sadrian if (freq[i] > ATH_HAL_2GHZ_FREQ_MIN && 4129250003Sadrian freq[i] < ATH_HAL_2GHZ_FREQ_MAX) 4130250003Sadrian { 4131250003Sadrian /* 2GHz Spur */ 4132250003Sadrian if (j < AR_EEPROM_MODAL_SPURS) { 4133250008Sadrian AH9300(ah)->ath_hal_spur_chans[j++][1] = freq[i]; 4134250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "1 set spur %d\n", freq[i]); 4135250003Sadrian } 4136250003Sadrian } else if (freq[i] > ATH_HAL_5GHZ_FREQ_MIN && 4137250003Sadrian freq[i] < ATH_HAL_5GHZ_FREQ_MAX) 4138250003Sadrian { 4139250003Sadrian /* 5Ghz Spur */ 4140250003Sadrian if (k < AR_EEPROM_MODAL_SPURS) { 4141250008Sadrian AH9300(ah)->ath_hal_spur_chans[k++][0] = freq[i]; 4142250003Sadrian HALDEBUG(ah, HAL_DEBUG_ANI, "2 set spur %d\n", freq[i]); 4143250003Sadrian } 4144250003Sadrian } 4145250003Sadrian } 4146250003Sadrian } 4147250003Sadrian 4148250003Sadrian return 0; 4149250003Sadrian} 4150250008Sadrian#endif 4151250003Sadrian 4152250003Sadrian#define ar9300_check_op_mode(_opmode) \ 4153250003Sadrian ((_opmode == HAL_M_STA) || (_opmode == HAL_M_IBSS) ||\ 4154250003Sadrian (_opmode == HAL_M_HOSTAP) || (_opmode == HAL_M_MONITOR)) 4155250003Sadrian 4156250003Sadrian 4157250003Sadrian 4158250003Sadrian 4159250003Sadrian#ifndef ATH_NF_PER_CHAN 4160250003Sadrian/* 4161250003Sadrian* To fixed first reset noise floor value not correct issue 4162250003Sadrian* For ART need it to fixed low rate sens too low issue 4163250003Sadrian*/ 4164250003Sadrianstatic int 4165250003SadrianFirst_NFCal(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, 4166250008Sadrian int is_scan, struct ieee80211_channel *chan) 4167250003Sadrian{ 4168250003Sadrian HAL_NFCAL_HIST_FULL *nfh; 4169250003Sadrian int i, j, k; 4170250008Sadrian int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; 4171250003Sadrian int is_2g = 0; 4172250003Sadrian int nf_hist_len; 4173250003Sadrian int stats = 0; 4174250003Sadrian 4175250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 4176250003Sadrian#define IS(_c, _f) (((_c)->channel_flags & _f) || 0) 4177250003Sadrian 4178250003Sadrian 4179250003Sadrian if ((!is_scan) && 4180250008Sadrian chan->ic_freq == AH_PRIVATE(ah)->ah_curchan->ic_freq) 4181250003Sadrian { 4182250003Sadrian nfh = &AH_PRIVATE(ah)->nf_cal_hist; 4183250003Sadrian } else { 4184250003Sadrian nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 4185250003Sadrian } 4186250008Sadrian 4187250003Sadrian ar9300_start_nf_cal(ah); 4188250003Sadrian for (j = 0; j < 10000; j++) { 4189250003Sadrian if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){ 4190250003Sadrian break; 4191250003Sadrian } 4192250003Sadrian OS_DELAY(10); 4193250003Sadrian } 4194250003Sadrian if (j < 10000) { 4195250008Sadrian is_2g = IEEE80211_IS_CHAN_2GHZ(chan); 4196250003Sadrian ar9300_upload_noise_floor(ah, is_2g, nfarray); 4197250003Sadrian 4198250003Sadrian if (is_scan) { 4199250003Sadrian /* 4200250003Sadrian * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct 4201250003Sadrian * rather than a HAL_NFCAL_HIST_FULL struct. 4202250003Sadrian * As long as we only use the first history element of nf_cal_buffer 4203250008Sadrian * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use 4204250003Sadrian * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably. 4205250003Sadrian */ 4206250003Sadrian nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; 4207250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; 4208250003Sadrian } else { 4209250003Sadrian nfh = &AH_PRIVATE(ah)->nf_cal_hist; 4210250003Sadrian nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; 4211250003Sadrian } 4212250003Sadrian 4213250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i ++) { 4214250003Sadrian for (k = 0; k < HAL_NF_CAL_HIST_LEN_FULL; k++) { 4215250003Sadrian nfh->nf_cal_buffer[k][i] = nfarray[i]; 4216250003Sadrian } 4217250003Sadrian nfh->base.priv_nf[i] = ar9300_limit_nf_range(ah, 4218250003Sadrian ar9300_get_nf_hist_mid(ah, nfh, i, nf_hist_len)); 4219250003Sadrian } 4220250003Sadrian 4221250003Sadrian 4222250003Sadrian //ar9300StoreNewNf(ah, ichan, is_scan); 4223250003Sadrian 4224250003Sadrian /* 4225250003Sadrian * See if the NF value from the old channel should be 4226250003Sadrian * retained when switching to a new channel. 4227250003Sadrian * TBD: this may need to be changed, as it wipes out the 4228250003Sadrian * purpose of saving NF values for each channel. 4229250003Sadrian */ 4230250008Sadrian for (i = 0; i < HAL_NUM_NF_READINGS; i++) 4231250003Sadrian { 4232250008Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) 4233250003Sadrian { 4234250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4235250003Sadrian AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ) 4236250003Sadrian { 4237250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4238250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4239250003Sadrian } 4240250003Sadrian } else { 4241250003Sadrian if (AR_SREV_AR9580(ah)) { 4242250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4243250003Sadrian AR_PHY_CCA_NOM_VAL_PEACOCK_5GHZ) 4244250003Sadrian { 4245250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4246250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4247250003Sadrian } 4248250003Sadrian } else { 4249250003Sadrian if (nfh->nf_cal_buffer[0][i] < 4250250003Sadrian AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ) 4251250003Sadrian { 4252250003Sadrian ichan->nf_cal_hist.nf_cal_buffer[0][i] = 4253250003Sadrian AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; 4254250003Sadrian } 4255250003Sadrian } 4256250003Sadrian } 4257250003Sadrian } 4258250003Sadrian /* 4259250003Sadrian * Copy the channel's NF buffer, which may have been modified 4260250003Sadrian * just above here, to the full NF history buffer. 4261250003Sadrian */ 4262250003Sadrian ar9300_reset_nf_hist_buff(ah, ichan); 4263250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 4264250003Sadrian ar9300_load_nf(ah, nf_buf); 4265250003Sadrian stats = 0; 4266250003Sadrian } else { 4267250003Sadrian stats = 1; 4268250003Sadrian } 4269250003Sadrian#undef IS 4270250003Sadrian return stats; 4271250003Sadrian} 4272250003Sadrian#endif 4273250003Sadrian 4274250003Sadrian 4275250003Sadrian/* 4276250003Sadrian * Places the device in and out of reset and then places sane 4277250003Sadrian * values in the registers based on EEPROM config, initialization 4278250003Sadrian * vectors (as determined by the mode), and station configuration 4279250003Sadrian * 4280250003Sadrian * b_channel_change is used to preserve DMA/PCU registers across 4281250003Sadrian * a HW Reset during channel change. 4282250003Sadrian */ 4283250003SadrianHAL_BOOL 4284250008Sadrianar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, 4285250003Sadrian HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask, 4286250003Sadrian HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change, 4287250003Sadrian HAL_STATUS *status, int is_scan) 4288250003Sadrian{ 4289250003Sadrian#define FAIL(_code) do { ecode = _code; goto bad; } while (0) 4290250003Sadrian u_int32_t save_led_state; 4291250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 4292250003Sadrian struct ath_hal_private *ap = AH_PRIVATE(ah); 4293250003Sadrian HAL_CHANNEL_INTERNAL *ichan; 4294250008Sadrian //const struct ieee80211_channel *curchan = ap->ah_curchan; 4295250003Sadrian#if ATH_SUPPORT_MCI 4296250003Sadrian HAL_BOOL save_full_sleep = ahp->ah_chip_full_sleep; 4297250003Sadrian#endif 4298250003Sadrian u_int32_t save_def_antenna; 4299250003Sadrian u_int32_t mac_sta_id1; 4300250003Sadrian HAL_STATUS ecode; 4301250003Sadrian int i, rx_chainmask; 4302250003Sadrian int nf_hist_buff_reset = 0; 4303250008Sadrian int16_t nf_buf[HAL_NUM_NF_READINGS]; 4304250003Sadrian#ifdef ATH_FORCE_PPM 4305250003Sadrian u_int32_t save_force_val, tmp_reg; 4306250003Sadrian#endif 4307250003Sadrian HAL_BOOL stopped, cal_ret; 4308250003Sadrian HAL_BOOL apply_last_iqcorr = AH_FALSE; 4309250003Sadrian 4310250003Sadrian if (OS_REG_READ(ah, AR_IER) == AR_IER_ENABLE) { 4311250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "** Reset called with WLAN " 4312250003Sadrian "interrupt enabled %08x **\n", ar9300_get_interrupts(ah)); 4313250003Sadrian } 4314250003Sadrian 4315250003Sadrian /* 4316250003Sadrian * Set the status to "ok" by default to cover the cases 4317250003Sadrian * where we return AH_FALSE without going to "bad" 4318250003Sadrian */ 4319250003Sadrian HALASSERT(status); 4320250003Sadrian *status = HAL_OK; 4321250008Sadrian if ((ah->ah_config.ath_hal_sta_update_tx_pwr_enable)) { 4322250008Sadrian AH9300(ah)->green_tx_status = HAL_RSSI_TX_POWER_NONE; 4323250003Sadrian } 4324250003Sadrian 4325250003Sadrian#if ATH_SUPPORT_MCI 4326250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && 4327250003Sadrian (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah))) 4328250003Sadrian { 4329250008Sadrian ar9300_mci_2g5g_changed(ah, IEEE80211_IS_CHAN_2GHZ(chan)); 4330250003Sadrian } 4331250003Sadrian#endif 4332250003Sadrian 4333250003Sadrian ahp->ah_ext_prot_spacing = extprotspacing; 4334250008Sadrian ahp->ah_tx_chainmask = txchainmask & ap->ah_caps.halTxChainMask; 4335250008Sadrian ahp->ah_rx_chainmask = rxchainmask & ap->ah_caps.halRxChainMask; 4336250008Sadrian ahp->ah_tx_cal_chainmask = ap->ah_caps.halTxChainMask; 4337250008Sadrian ahp->ah_rx_cal_chainmask = ap->ah_caps.halRxChainMask; 4338250003Sadrian HALASSERT(ar9300_check_op_mode(opmode)); 4339250003Sadrian 4340250003Sadrian OS_MARK(ah, AH_MARK_RESET, b_channel_change); 4341250003Sadrian 4342250003Sadrian /* 4343250003Sadrian * Map public channel to private. 4344250003Sadrian */ 4345250003Sadrian ichan = ar9300_check_chan(ah, chan); 4346250003Sadrian if (ichan == AH_NULL) { 4347250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 4348250003Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 4349250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 4350250003Sadrian FAIL(HAL_EINVAL); 4351250003Sadrian } 4352250003Sadrian 4353250003Sadrian ichan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */ 4354250008Sadrian#if 0 4355250003Sadrian chan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */ 4356250008Sadrian#endif 4357250003Sadrian 4358250003Sadrian if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) { 4359250003Sadrian /* Need to stop RX DMA before reset otherwise chip might hang */ 4360250003Sadrian stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */ 4361250003Sadrian ar9300_set_rx_filter(ah, 0); 4362250003Sadrian stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */ 4363250003Sadrian if (!stopped) { 4364250003Sadrian /* 4365250003Sadrian * During the transition from full sleep to reset, 4366250003Sadrian * recv DMA regs are not available to be read 4367250003Sadrian */ 4368250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 4369250003Sadrian "%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__); 4370250003Sadrian b_channel_change = AH_FALSE; 4371250003Sadrian } 4372250003Sadrian } else { 4373250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 4374250003Sadrian "%s[%d]: Chip is already in full sleep\n", __func__, __LINE__); 4375250003Sadrian } 4376250003Sadrian 4377250003Sadrian#if ATH_SUPPORT_MCI 4378250008Sadrian if ((AH_PRIVATE(ah)->ah_caps.halMciSupport) && 4379250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_CAL_START)) 4380250003Sadrian { 4381250003Sadrian u_int32_t payload[4] = {0, 0, 0, 0}; 4382250003Sadrian 4383250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4384250003Sadrian "(MCI) %s: Stop rx for BT cal.\n", __func__); 4385250003Sadrian ahp->ah_mci_bt_state = MCI_BT_CAL; 4386250003Sadrian 4387250003Sadrian /* 4388250003Sadrian * MCIFIX: disable mci interrupt here. This is to avoid SW_MSG_DONE or 4389250003Sadrian * RX_MSG bits to trigger MCI_INT and lead to mci_intr reentry. 4390250003Sadrian */ 4391250003Sadrian ar9300_mci_disable_interrupt(ah); 4392250003Sadrian 4393250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4394250003Sadrian "(MCI) %s: Send WLAN_CAL_GRANT\n", __func__); 4395250003Sadrian MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); 4396250003Sadrian ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); 4397250003Sadrian 4398250003Sadrian /* Wait BT calibration to be completed for 25ms */ 4399250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4400250003Sadrian "(MCI) %s: BT is calibrating.\n", __func__); 4401250003Sadrian if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) { 4402250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4403250003Sadrian "(MCI) %s: Got BT_CAL_DONE.\n", __func__); 4404250003Sadrian } 4405250003Sadrian else { 4406250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4407250003Sadrian "(MCI) %s: ### BT cal takes too long. Force bt_state to be bt_awake.\n", 4408250003Sadrian __func__); 4409250003Sadrian } 4410250003Sadrian ahp->ah_mci_bt_state = MCI_BT_AWAKE; 4411250003Sadrian /* MCIFIX: enable mci interrupt here */ 4412250003Sadrian ar9300_mci_enable_interrupt(ah); 4413250003Sadrian 4414250003Sadrian return AH_TRUE; 4415250003Sadrian } 4416250003Sadrian#endif 4417250003Sadrian 4418250003Sadrian /* Bring out of sleep mode */ 4419250003Sadrian if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { 4420250003Sadrian *status = HAL_INV_PMODE; 4421250003Sadrian return AH_FALSE; 4422250003Sadrian } 4423250003Sadrian 4424250003Sadrian /* Check the Rx mitigation config again, it might have changed 4425250003Sadrian * during attach in ath_vap_attach. 4426250003Sadrian */ 4427250008Sadrian if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) { 4428250003Sadrian ahp->ah_intr_mitigation_rx = AH_TRUE; 4429250003Sadrian } else { 4430250003Sadrian ahp->ah_intr_mitigation_rx = AH_FALSE; 4431250003Sadrian } 4432250003Sadrian 4433250008Sadrian /* 4434250008Sadrian * XXX TODO FreeBSD: 4435250008Sadrian * 4436250008Sadrian * This is painful because we don't have a non-const channel pointer 4437250008Sadrian * at this stage. 4438250008Sadrian * 4439250008Sadrian * Make sure this gets fixed! 4440250008Sadrian */ 4441250008Sadrian#if 0 4442250003Sadrian /* Get the value from the previous NF cal and update history buffer */ 4443250003Sadrian if (curchan && (ahp->ah_chip_full_sleep != AH_TRUE)) { 4444250003Sadrian ar9300_store_new_nf(ah, curchan, is_scan); 4445250003Sadrian } 4446250008Sadrian#endif 4447250003Sadrian 4448250003Sadrian /* 4449250003Sadrian * Account for the effect of being in either the 2 GHz or 5 GHz band 4450250003Sadrian * on the nominal, max allowable, and min allowable noise floor values. 4451250003Sadrian */ 4452250008Sadrian AH9300(ah)->nfp = IS_CHAN_2GHZ(ichan) ? &ahp->nf_2GHz : &ahp->nf_5GHz; 4453250003Sadrian 4454250008Sadrian /* 4455250008Sadrian * XXX For now, don't apply the last IQ correction. 4456250008Sadrian * 4457250008Sadrian * This should be done when scorpion is enabled on FreeBSD; just be 4458250008Sadrian * sure to fix this channel match code so it uses net80211 flags 4459250008Sadrian * instead. 4460250008Sadrian */ 4461250008Sadrian#if 0 4462250003Sadrian if (AR_SREV_SCORPION(ah) && curchan && (chan->channel == curchan->channel) && 4463250003Sadrian ((chan->channel_flags & (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)) == 4464250003Sadrian (curchan->channel_flags & 4465250003Sadrian (CHANNEL_ALL | CHANNEL_HALF | CHANNEL_QUARTER)))) { 4466250003Sadrian apply_last_iqcorr = AH_TRUE; 4467250003Sadrian } 4468250008Sadrian#endif 4469250008Sadrian apply_last_iqcorr = AH_FALSE; 4470250008Sadrian 4471250003Sadrian 4472250003Sadrian#ifndef ATH_NF_PER_CHAN 4473250003Sadrian /* 4474250003Sadrian * If there's only one full-size home-channel NF history buffer 4475250003Sadrian * rather than a full-size NF history buffer per channel, decide 4476250003Sadrian * whether to (re)initialize the home-channel NF buffer. 4477250003Sadrian * If this is just a channel change for a scan, or if the channel 4478250003Sadrian * is not being changed, don't mess up the home channel NF history 4479250003Sadrian * buffer with NF values from this scanned channel. If we're 4480250003Sadrian * changing the home channel to a new channel, reset the home-channel 4481250003Sadrian * NF history buffer with the most accurate NF known for the new channel. 4482250003Sadrian */ 4483250003Sadrian if (!is_scan && (!ap->ah_curchan || 4484250008Sadrian ap->ah_curchan->ic_freq != chan->ic_freq)) // || 4485250008Sadrian// ap->ah_curchan->channel_flags != chan->channel_flags)) 4486250003Sadrian { 4487250003Sadrian nf_hist_buff_reset = 1; 4488250003Sadrian ar9300_reset_nf_hist_buff(ah, ichan); 4489250003Sadrian } 4490250003Sadrian#endif 4491250003Sadrian /* 4492250003Sadrian * Fast channel change (Change synthesizer based on channel freq 4493250003Sadrian * without resetting chip) 4494250003Sadrian * Don't do it when 4495250003Sadrian * - Flag is not set 4496250003Sadrian * - Chip is just coming out of full sleep 4497250003Sadrian * - Channel to be set is same as current channel 4498250003Sadrian * - Channel flags are different, like when moving from 2GHz to 5GHz 4499250003Sadrian * channels 4500250003Sadrian * - Merlin: Switching in/out of fast clock enabled channels 4501250003Sadrian * (not currently coded, since fast clock is enabled 4502250003Sadrian * across the 5GHz band 4503250003Sadrian * and we already do a full reset when switching in/out 4504250003Sadrian * of 5GHz channels) 4505250003Sadrian */ 4506250008Sadrian#if 0 4507250003Sadrian if (b_channel_change && 4508250003Sadrian (ahp->ah_chip_full_sleep != AH_TRUE) && 4509250003Sadrian (AH_PRIVATE(ah)->ah_curchan != AH_NULL) && 4510250003Sadrian ((chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) && 4511250003Sadrian (((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & chan->channel_flags) == 4512250003Sadrian ((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & AH_PRIVATE(ah)->ah_curchan->channel_flags)))) 4513250003Sadrian { 4514250003Sadrian if (ar9300_channel_change(ah, chan, ichan, macmode)) { 4515250003Sadrian chan->channel_flags = ichan->channel_flags; 4516250003Sadrian chan->priv_flags = ichan->priv_flags; 4517250003Sadrian AH_PRIVATE(ah)->ah_curchan->ah_channel_time = 0; 4518250003Sadrian AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar9300_get_tsf64(ah); 4519250003Sadrian 4520250003Sadrian /* 4521250003Sadrian * Load the NF from history buffer of the current channel. 4522250003Sadrian * NF is slow time-variant, so it is OK to use a historical value. 4523250003Sadrian */ 4524250003Sadrian ar9300_get_nf_hist_base(ah, 4525250003Sadrian AH_PRIVATE(ah)->ah_curchan, is_scan, nf_buf); 4526250003Sadrian ar9300_load_nf(ah, nf_buf); 4527250003Sadrian 4528250003Sadrian /* start NF calibration, without updating BB NF register*/ 4529250003Sadrian ar9300_start_nf_cal(ah); 4530250003Sadrian 4531250003Sadrian /* 4532250003Sadrian * If channel_change completed and DMA was stopped 4533250003Sadrian * successfully - skip the rest of reset 4534250003Sadrian */ 4535250003Sadrian if (AH9300(ah)->ah_dma_stuck != AH_TRUE) { 4536250003Sadrian WAR_USB_DISABLE_PLL_LOCK_DETECT(ah); 4537250003Sadrian#if ATH_SUPPORT_MCI 4538250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) 4539250003Sadrian { 4540250003Sadrian ar9300_mci_2g5g_switch(ah, AH_TRUE); 4541250003Sadrian } 4542250003Sadrian#endif 4543250008Sadrian return HAL_OK; 4544250003Sadrian } 4545250003Sadrian } 4546250003Sadrian } 4547250008Sadrian#endif /* #if 0 */ 4548250003Sadrian 4549250003Sadrian#if ATH_SUPPORT_MCI 4550250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4551250003Sadrian ar9300_mci_disable_interrupt(ah); 4552250003Sadrian if (ahp->ah_mci_ready && !save_full_sleep) { 4553250003Sadrian ar9300_mci_mute_bt(ah); 4554250003Sadrian OS_DELAY(20); 4555250003Sadrian OS_REG_WRITE(ah, AR_BTCOEX_CTRL, 0); 4556250003Sadrian } 4557250003Sadrian 4558250003Sadrian ahp->ah_mci_bt_state = MCI_BT_SLEEP; 4559250003Sadrian ahp->ah_mci_ready = AH_FALSE; 4560250003Sadrian } 4561250003Sadrian#endif 4562250003Sadrian 4563250003Sadrian AH9300(ah)->ah_dma_stuck = AH_FALSE; 4564250003Sadrian#ifdef ATH_FORCE_PPM 4565250003Sadrian /* Preserve force ppm state */ 4566250003Sadrian save_force_val = 4567250003Sadrian OS_REG_READ(ah, AR_PHY_TIMING2) & 4568250003Sadrian (AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL); 4569250003Sadrian#endif 4570250003Sadrian /* 4571250003Sadrian * Preserve the antenna on a channel change 4572250003Sadrian */ 4573250003Sadrian save_def_antenna = OS_REG_READ(ah, AR_DEF_ANTENNA); 4574250003Sadrian if (0 == ahp->ah_smartantenna_enable ) 4575250003Sadrian { 4576250003Sadrian if (save_def_antenna == 0) { 4577250003Sadrian save_def_antenna = 1; 4578250003Sadrian } 4579250003Sadrian } 4580250003Sadrian 4581250003Sadrian /* Save hardware flag before chip reset clears the register */ 4582250003Sadrian mac_sta_id1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; 4583250003Sadrian 4584250003Sadrian /* Save led state from pci config register */ 4585250003Sadrian save_led_state = OS_REG_READ(ah, AR_CFG_LED) & 4586250003Sadrian (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | 4587250003Sadrian AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW); 4588250003Sadrian 4589250003Sadrian /* Mark PHY inactive prior to reset, to be undone in ar9300_init_bb () */ 4590250003Sadrian ar9300_mark_phy_inactive(ah); 4591250003Sadrian 4592250003Sadrian if (!ar9300_chip_reset(ah, chan)) { 4593250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: chip reset failed\n", __func__); 4594250003Sadrian FAIL(HAL_EIO); 4595250003Sadrian } 4596250003Sadrian 4597250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4598250003Sadrian 4599250003Sadrian 4600250003Sadrian /* Disable JTAG */ 4601250003Sadrian OS_REG_SET_BIT(ah, 4602250003Sadrian AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE); 4603250003Sadrian 4604250003Sadrian /* 4605250003Sadrian * Note that ar9300_init_chain_masks() is called from within 4606250003Sadrian * ar9300_process_ini() to ensure the swap bit is set before 4607250003Sadrian * the pdadc table is written. 4608250003Sadrian */ 4609250003Sadrian ecode = ar9300_process_ini(ah, chan, ichan, macmode); 4610250003Sadrian if (ecode != HAL_OK) { 4611250003Sadrian goto bad; 4612250003Sadrian } 4613250003Sadrian 4614250003Sadrian ahp->ah_immunity_on = AH_FALSE; 4615250003Sadrian 4616250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 4617250003Sadrian ahp->tx_iq_cal_enable = OS_REG_READ_FIELD(ah, 4618250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0(ah), 4619250003Sadrian AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL) ? 4620250003Sadrian 1 : 0; 4621250003Sadrian } 4622250003Sadrian ahp->tx_cl_cal_enable = (OS_REG_READ(ah, AR_PHY_CL_CAL_CTL) & 4623250003Sadrian AR_PHY_CL_CAL_ENABLE) ? 1 : 0; 4624250003Sadrian 4625250003Sadrian /* For devices with full HW RIFS Rx support (Sowl/Howl/Merlin, etc), 4626250003Sadrian * restore register settings from prior to reset. 4627250003Sadrian */ 4628250003Sadrian if ((AH_PRIVATE(ah)->ah_curchan != AH_NULL) && 4629250003Sadrian (ar9300_get_capability(ah, HAL_CAP_LDPCWAR, 0, AH_NULL) == HAL_OK)) 4630250003Sadrian { 4631250003Sadrian /* Re-program RIFS Rx policy after reset */ 4632250003Sadrian ar9300_set_rifs_delay(ah, ahp->ah_rifs_enabled); 4633250003Sadrian } 4634250003Sadrian 4635250003Sadrian#if ATH_SUPPORT_MCI 4636250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4637250008Sadrian ar9300_mci_reset(ah, AH_FALSE, IS_CHAN_2GHZ(ichan), save_full_sleep); 4638250003Sadrian } 4639250003Sadrian#endif 4640250003Sadrian 4641250003Sadrian /* Initialize Management Frame Protection */ 4642250003Sadrian ar9300_init_mfp(ah); 4643250003Sadrian 4644250003Sadrian ahp->ah_immunity_vals[0] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4645250003Sadrian AR_PHY_SFCORR_LOW_M1_THRESH_LOW); 4646250003Sadrian ahp->ah_immunity_vals[1] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4647250003Sadrian AR_PHY_SFCORR_LOW_M2_THRESH_LOW); 4648250003Sadrian ahp->ah_immunity_vals[2] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4649250003Sadrian AR_PHY_SFCORR_M1_THRESH); 4650250003Sadrian ahp->ah_immunity_vals[3] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4651250003Sadrian AR_PHY_SFCORR_M2_THRESH); 4652250003Sadrian ahp->ah_immunity_vals[4] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, 4653250003Sadrian AR_PHY_SFCORR_M2COUNT_THR); 4654250003Sadrian ahp->ah_immunity_vals[5] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, 4655250003Sadrian AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW); 4656250003Sadrian 4657250003Sadrian /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ 4658250008Sadrian if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) { 4659250008Sadrian ar9300_set_delta_slope(ah, chan); 4660250003Sadrian } 4661250003Sadrian 4662250003Sadrian ar9300_spur_mitigate(ah, chan); 4663250008Sadrian if (!ar9300_eeprom_set_board_values(ah, chan)) { 4664250003Sadrian HALDEBUG(ah, HAL_DEBUG_EEPROM, 4665250003Sadrian "%s: error setting board options\n", __func__); 4666250003Sadrian FAIL(HAL_EIO); 4667250003Sadrian } 4668250003Sadrian 4669250003Sadrian#ifdef ATH_HAL_WAR_REG16284_APH128 4670250003Sadrian /* temp work around, will be removed. */ 4671250003Sadrian if (AR_SREV_WASP(ah)) { 4672250003Sadrian OS_REG_WRITE(ah, 0x16284, 0x1553e000); 4673250003Sadrian } 4674250003Sadrian#endif 4675250003Sadrian 4676250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4677250003Sadrian 4678250003Sadrian OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); 4679250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) 4680250003Sadrian | mac_sta_id1 4681250003Sadrian | AR_STA_ID1_RTS_USE_DEF 4682250008Sadrian | (ah->ah_config.ath_hal_6mb_ack ? AR_STA_ID1_ACKCTS_6MB : 0) 4683250003Sadrian | ahp->ah_sta_id1_defaults 4684250003Sadrian ); 4685250003Sadrian ar9300_set_operating_mode(ah, opmode); 4686250003Sadrian 4687250003Sadrian /* Set Venice BSSID mask according to current state */ 4688250003Sadrian OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssid_mask)); 4689250003Sadrian OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssid_mask + 4)); 4690250003Sadrian 4691250003Sadrian /* Restore previous antenna */ 4692250003Sadrian OS_REG_WRITE(ah, AR_DEF_ANTENNA, save_def_antenna); 4693250003Sadrian#ifdef ATH_FORCE_PPM 4694250003Sadrian /* Restore force ppm state */ 4695250003Sadrian tmp_reg = OS_REG_READ(ah, AR_PHY_TIMING2) & 4696250003Sadrian ~(AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL); 4697250003Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING2, tmp_reg | save_force_val); 4698250003Sadrian#endif 4699250003Sadrian 4700250003Sadrian /* then our BSSID and assocID */ 4701250003Sadrian OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 4702250003Sadrian OS_REG_WRITE(ah, AR_BSS_ID1, 4703250003Sadrian LE_READ_2(ahp->ah_bssid + 4) | 4704250003Sadrian ((ahp->ah_assoc_id & 0x3fff) << AR_BSS_ID1_AID_S)); 4705250003Sadrian 4706250003Sadrian OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ 4707250003Sadrian 4708250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR); 4709250003Sadrian 4710250003Sadrian /* HW beacon processing */ 4711250008Sadrian /* 4712250008Sadrian * XXX what happens if I just leave filter_interval=0? 4713250008Sadrian * it stays disabled? 4714250008Sadrian */ 4715250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_BCN_WEIGHT, 4716250003Sadrian INIT_RSSI_BEACON_WEIGHT); 4717250003Sadrian OS_REG_SET_BIT(ah, AR_HWBCNPROC1, AR_HWBCNPROC1_CRC_ENABLE | 4718250003Sadrian AR_HWBCNPROC1_EXCLUDE_TIM_ELM); 4719250008Sadrian if (ah->ah_config.ath_hal_beacon_filter_interval) { 4720250003Sadrian OS_REG_RMW_FIELD(ah, AR_HWBCNPROC2, AR_HWBCNPROC2_FILTER_INTERVAL, 4721250008Sadrian ah->ah_config.ath_hal_beacon_filter_interval); 4722250003Sadrian OS_REG_SET_BIT(ah, AR_HWBCNPROC2, 4723250003Sadrian AR_HWBCNPROC2_FILTER_INTERVAL_ENABLE); 4724250003Sadrian } 4725250003Sadrian 4726250003Sadrian 4727250003Sadrian /* 4728250003Sadrian * Set Channel now modifies bank 6 parameters for FOWL workaround 4729250003Sadrian * to force rf_pwd_icsyndiv bias current as function of synth 4730250003Sadrian * frequency.Thus must be called after ar9300_process_ini() to ensure 4731250003Sadrian * analog register cache is valid. 4732250003Sadrian */ 4733250008Sadrian if (!ahp->ah_rf_hal.set_channel(ah, chan)) { 4734250003Sadrian FAIL(HAL_EIO); 4735250003Sadrian } 4736250003Sadrian 4737250003Sadrian 4738250003Sadrian OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 4739250003Sadrian 4740250003Sadrian /* Set 1:1 QCU to DCU mapping for all queues */ 4741250003Sadrian for (i = 0; i < AR_NUM_DCU; i++) { 4742250003Sadrian OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); 4743250003Sadrian } 4744250003Sadrian 4745250003Sadrian ahp->ah_intr_txqs = 0; 4746250008Sadrian for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) { 4747250003Sadrian ar9300_reset_tx_queue(ah, i); 4748250003Sadrian } 4749250003Sadrian 4750250003Sadrian ar9300_init_interrupt_masks(ah, opmode); 4751250003Sadrian 4752250003Sadrian /* Reset ier reference count to disabled */ 4753250008Sadrian// OS_ATOMIC_SET(&ahp->ah_ier_ref_count, 1); 4754250003Sadrian if (ath_hal_isrfkillenabled(ah)) { 4755250003Sadrian ar9300_enable_rf_kill(ah); 4756250003Sadrian } 4757250003Sadrian 4758250003Sadrian /* must be called AFTER ini is processed */ 4759250003Sadrian ar9300_ani_init_defaults(ah, macmode); 4760250003Sadrian 4761250003Sadrian ar9300_init_qos(ah); 4762250003Sadrian 4763250003Sadrian ar9300_init_user_settings(ah); 4764250003Sadrian 4765250003Sadrian 4766250003Sadrian AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ 4767250003Sadrian 4768250003Sadrian OS_MARK(ah, AH_MARK_RESET_DONE, 0); 4769250003Sadrian 4770250003Sadrian /* 4771250003Sadrian * disable seq number generation in hw 4772250003Sadrian */ 4773250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, 4774250003Sadrian OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); 4775250003Sadrian 4776250003Sadrian ar9300_set_dma(ah); 4777250003Sadrian 4778250003Sadrian /* 4779250003Sadrian * program OBS bus to see MAC interrupts 4780250003Sadrian */ 4781250003Sadrian#if ATH_SUPPORT_MCI 4782250008Sadrian if (!AH_PRIVATE(ah)->ah_caps.halMciSupport) { 4783250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8); 4784250003Sadrian } 4785250003Sadrian#else 4786250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8); 4787250003Sadrian#endif 4788250003Sadrian 4789250003Sadrian 4790250003Sadrian /* enabling AR_GTTM_IGNORE_IDLE in GTTM register so that 4791250003Sadrian GTT timer will not increment if the channel idle indicates 4792250003Sadrian the air is busy or NAV is still counting down */ 4793250003Sadrian OS_REG_WRITE(ah, AR_GTTM, AR_GTTM_IGNORE_IDLE); 4794250003Sadrian 4795250003Sadrian /* 4796250003Sadrian * GTT debug mode setting 4797250003Sadrian */ 4798250003Sadrian /* 4799250003Sadrian OS_REG_WRITE(ah, 0x64, 0x00320000); 4800250003Sadrian OS_REG_WRITE(ah, 0x68, 7); 4801250003Sadrian OS_REG_WRITE(ah, 0x4080, 0xC); 4802250003Sadrian */ 4803250003Sadrian /* 4804250003Sadrian * Disable general interrupt mitigation by setting MIRT = 0x0 4805250003Sadrian * Rx and tx interrupt mitigation are conditionally enabled below. 4806250003Sadrian */ 4807250003Sadrian OS_REG_WRITE(ah, AR_MIRT, 0); 4808250003Sadrian if (ahp->ah_intr_mitigation_rx) { 4809250003Sadrian /* 4810250003Sadrian * Enable Interrupt Mitigation for Rx. 4811250003Sadrian * If no build-specific limits for the rx interrupt mitigation 4812250003Sadrian * timer have been specified, use conservative defaults. 4813250003Sadrian */ 4814250003Sadrian #ifndef AH_RIMT_VAL_LAST 4815250003Sadrian #define AH_RIMT_LAST_MICROSEC 500 4816250003Sadrian #endif 4817250003Sadrian #ifndef AH_RIMT_VAL_FIRST 4818250003Sadrian #define AH_RIMT_FIRST_MICROSEC 2000 4819250003Sadrian #endif 4820250003Sadrian#ifndef HOST_OFFLOAD 4821250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, AH_RIMT_LAST_MICROSEC); 4822250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, AH_RIMT_FIRST_MICROSEC); 4823250003Sadrian#else 4824250003Sadrian /* lower mitigation level to reduce latency for offload arch. */ 4825250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 4826250003Sadrian (AH_RIMT_LAST_MICROSEC >> 2)); 4827250003Sadrian OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 4828250003Sadrian (AH_RIMT_FIRST_MICROSEC >> 2)); 4829250003Sadrian#endif 4830250003Sadrian } 4831250003Sadrian 4832250003Sadrian if (ahp->ah_intr_mitigation_tx) { 4833250003Sadrian /* 4834250003Sadrian * Enable Interrupt Mitigation for Tx. 4835250003Sadrian * If no build-specific limits for the tx interrupt mitigation 4836250003Sadrian * timer have been specified, use the values preferred for 4837250003Sadrian * the carrier group's products. 4838250003Sadrian */ 4839250003Sadrian #ifndef AH_TIMT_LAST 4840250003Sadrian #define AH_TIMT_LAST_MICROSEC 300 4841250003Sadrian #endif 4842250003Sadrian #ifndef AH_TIMT_FIRST 4843250003Sadrian #define AH_TIMT_FIRST_MICROSEC 750 4844250003Sadrian #endif 4845250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, AH_TIMT_LAST_MICROSEC); 4846250003Sadrian OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, AH_TIMT_FIRST_MICROSEC); 4847250003Sadrian } 4848250003Sadrian 4849250003Sadrian rx_chainmask = ahp->ah_rx_chainmask; 4850250003Sadrian 4851250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 4852250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 4853250003Sadrian 4854250003Sadrian ar9300_init_bb(ah, chan); 4855250003Sadrian 4856250003Sadrian /* BB Step 7: Calibration */ 4857250003Sadrian ar9300_invalidate_saved_cals(ah, ichan); 4858250003Sadrian cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); 4859250003Sadrian 4860250003Sadrian#if ATH_SUPPORT_MCI 4861250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { 4862250008Sadrian if (IS_CHAN_2GHZ(ichan) && 4863250003Sadrian (ahp->ah_mci_bt_state == MCI_BT_SLEEP)) 4864250003Sadrian { 4865250003Sadrian if (ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || 4866250003Sadrian ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) 4867250003Sadrian { 4868250003Sadrian /* 4869250003Sadrian * BT is sleeping. Check if BT wakes up duing WLAN 4870250003Sadrian * calibration. If BT wakes up during WLAN calibration, need 4871250003Sadrian * to go through all message exchanges again and recal. 4872250003Sadrian */ 4873250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 4874250003Sadrian "(MCI) ### %s: BT wakes up during WLAN calibration.\n", 4875250003Sadrian __func__); 4876250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, 4877250003Sadrian AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | 4878250003Sadrian AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); 4879250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) send REMOTE_RESET\n"); 4880250003Sadrian ar9300_mci_remote_reset(ah, AH_TRUE); 4881250003Sadrian ar9300_mci_send_sys_waking(ah, AH_TRUE); 4882250003Sadrian OS_DELAY(1); 4883250008Sadrian if (IS_CHAN_2GHZ(ichan)) { 4884250003Sadrian ar9300_mci_send_lna_transfer(ah, AH_TRUE); 4885250003Sadrian } 4886250003Sadrian ahp->ah_mci_bt_state = MCI_BT_AWAKE; 4887250003Sadrian 4888250003Sadrian /* Redo calibration */ 4889250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Re-calibrate.\n", 4890250003Sadrian __func__); 4891250003Sadrian ar9300_invalidate_saved_cals(ah, ichan); 4892250008Sadrian cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); 4893250003Sadrian } 4894250003Sadrian } 4895250003Sadrian ar9300_mci_enable_interrupt(ah); 4896250003Sadrian } 4897250003Sadrian#endif 4898250003Sadrian 4899250003Sadrian if (!cal_ret) { 4900250003Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Init Cal Failed\n", __func__); 4901250003Sadrian FAIL(HAL_ESELFTEST); 4902250003Sadrian } 4903250003Sadrian 4904250003Sadrian ar9300_init_txbf(ah); 4905250003Sadrian#if 0 4906250003Sadrian /* 4907250003Sadrian * WAR for owl 1.0 - restore chain mask for 2-chain cfgs after cal 4908250003Sadrian */ 4909250003Sadrian rx_chainmask = ahp->ah_rx_chainmask; 4910250003Sadrian if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { 4911250003Sadrian OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); 4912250003Sadrian OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); 4913250003Sadrian } 4914250003Sadrian#endif 4915250003Sadrian 4916250003Sadrian /* Restore previous led state */ 4917250003Sadrian OS_REG_WRITE(ah, AR_CFG_LED, save_led_state | AR_CFG_SCLK_32KHZ); 4918250003Sadrian 4919250008Sadrian#if ATH_BT_COEX 4920250003Sadrian if (ahp->ah_bt_coex_config_type != HAL_BT_COEX_CFG_NONE) { 4921250003Sadrian ar9300_init_bt_coex(ah); 4922250003Sadrian 4923250003Sadrian#if ATH_SUPPORT_MCI 4924250008Sadrian if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { 4925250003Sadrian /* Check BT state again to make sure it's not changed. */ 4926250003Sadrian ar9300_mci_sync_bt_state(ah); 4927250003Sadrian ar9300_mci_2g5g_switch(ah, AH_TRUE); 4928250003Sadrian 4929250003Sadrian if ((ahp->ah_mci_bt_state == MCI_BT_AWAKE) && 4930250003Sadrian (ahp->ah_mci_query_bt == AH_TRUE)) 4931250003Sadrian { 4932250003Sadrian ahp->ah_mci_need_flush_btinfo = AH_TRUE; 4933250003Sadrian } 4934250003Sadrian } 4935250003Sadrian#endif 4936250003Sadrian } 4937250003Sadrian#endif 4938250003Sadrian 4939250003Sadrian /* Start TSF2 for generic timer 8-15. */ 4940250003Sadrian ar9300_start_tsf2(ah); 4941250003Sadrian 4942250003Sadrian /* MIMO Power save setting */ 4943250003Sadrian if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) == HAL_OK) { 4944250003Sadrian ar9300_set_sm_power_mode(ah, ahp->ah_sm_power_mode); 4945250003Sadrian } 4946250003Sadrian 4947250003Sadrian /* 4948250003Sadrian * For big endian systems turn on swapping for descriptors 4949250003Sadrian */ 4950250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN 4951250003Sadrian if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 4952250003Sadrian OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB, 0); 4953250003Sadrian } else { 4954250003Sadrian ar9300_init_cfg_reg(ah); 4955250003Sadrian } 4956250003Sadrian#endif 4957250003Sadrian 4958250003Sadrian if ( AR_SREV_OSPREY(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { 4959250003Sadrian OS_REG_RMW(ah, AR_CFG_LED, AR_CFG_LED_ASSOC_CTL, AR_CFG_LED_ASSOC_CTL); 4960250003Sadrian } 4961250003Sadrian 4962250003Sadrian#if !(defined(ART_BUILD)) && defined(ATH_SUPPORT_LED) 4963250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); 4964250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 4965250003Sadrian#define ATH_GPIO_OUT_FUNCTION3 0xB8040038 4966250003Sadrian#define ATH_GPIO_OE 0xB8040000 4967250003Sadrian if ( AR_SREV_WASP(ah)) { 4968250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 4969250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x33 << 8) ); 4970250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) ))); 4971250003Sadrian } 4972250003Sadrian else { 4973250003Sadrian 4974250003Sadrian /* Disable 2G WLAN LED. During ath_open, reset function is called even before channel is set. 4975250003Sadrian So 2GHz is taken as default and it also blinks. Hence 4976250003Sadrian to avoid both from blinking, disable 2G led while in 5G mode */ 4977250003Sadrian 4978250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) | (1 << 13) )); 4979250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x33) ); 4980250003Sadrian REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) ))); 4981250003Sadrian } 4982250003Sadrian 4983250003Sadrian } 4984250003Sadrian else if (AR_SREV_SCORPION(ah)) { 4985250003Sadrian if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { 4986250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x2F << 8) ); 4987250003Sadrian REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )) | (0x1 << 12))); 4988250003Sadrian } else if (IS_CHAN_5GHZ((AH_PRIVATE(ah)->ah_curchan))) { 4989250003Sadrian REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x2F) ); 4990250003Sadrian REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )) | (0x1 << 13))); 4991250003Sadrian } 4992250003Sadrian } 4993250003Sadrian#undef REG_READ 4994250003Sadrian#undef REG_WRITE 4995250003Sadrian#endif 4996250003Sadrian 4997250008Sadrian /* XXX FreeBSD What's this? -adrian */ 4998250008Sadrian#if 0 4999250003Sadrian chan->channel_flags = ichan->channel_flags; 5000250003Sadrian chan->priv_flags = ichan->priv_flags; 5001250008Sadrian#endif 5002250003Sadrian 5003250003Sadrian#if FIX_NOISE_FLOOR 5004250008Sadrian /* XXX FreeBSD is ichan appropariate? It was curchan.. */ 5005250008Sadrian ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); 5006250003Sadrian ar9300_load_nf(ah, nf_buf); 5007250003Sadrian if (nf_hist_buff_reset == 1) 5008250003Sadrian { 5009250003Sadrian nf_hist_buff_reset = 0; 5010250003Sadrian #ifndef ATH_NF_PER_CHAN 5011250003Sadrian if (First_NFCal(ah, ichan, is_scan, chan)){ 5012250003Sadrian } 5013250003Sadrian #endif /* ATH_NF_PER_CHAN */ 5014250003Sadrian } 5015250003Sadrian else{ 5016250003Sadrian ar9300_start_nf_cal(ah); 5017250003Sadrian } 5018250003Sadrian#endif 5019250003Sadrian 5020250003Sadrian#ifdef AH_SUPPORT_AR9300 5021250003Sadrian /* BB Panic Watchdog */ 5022250003Sadrian if (ar9300_get_capability(ah, HAL_CAP_BB_PANIC_WATCHDOG, 0, AH_NULL) == 5023250003Sadrian HAL_OK) 5024250003Sadrian { 5025250003Sadrian ar9300_config_bb_panic_watchdog(ah); 5026250003Sadrian } 5027250003Sadrian#endif 5028250003Sadrian 5029250003Sadrian /* While receiving unsupported rate frame receive state machine 5030250003Sadrian * gets into a state 0xb and if phy_restart happens when rx 5031250003Sadrian * state machine is in 0xb state, BB would go hang, if we 5032250003Sadrian * see 0xb state after first bb panic, make sure that we 5033250003Sadrian * disable the phy_restart. 5034250003Sadrian * 5035250003Sadrian * There may be multiple panics, make sure that we always do 5036250003Sadrian * this if we see this panic at least once. This is required 5037250003Sadrian * because reset seems to be writing from INI file. 5038250003Sadrian */ 5039250003Sadrian if ((ar9300_get_capability(ah, HAL_CAP_PHYRESTART_CLR_WAR, 0, AH_NULL) 5040250008Sadrian == HAL_OK) && (((MS((AH9300(ah)->ah_bb_panic_last_status), 5041250003Sadrian AR_PHY_BB_WD_RX_OFDM_SM)) == 0xb) || 5042250008Sadrian AH9300(ah)->ah_phyrestart_disabled) ) 5043250003Sadrian { 5044250003Sadrian ar9300_disable_phy_restart(ah, 1); 5045250003Sadrian } 5046250003Sadrian 5047250003Sadrian 5048250003Sadrian 5049250003Sadrian ahp->ah_radar1 = MS(OS_REG_READ(ah, AR_PHY_RADAR_1), 5050250003Sadrian AR_PHY_RADAR_1_CF_BIN_THRESH); 5051250003Sadrian ahp->ah_dc_offset = MS(OS_REG_READ(ah, AR_PHY_TIMING2), 5052250003Sadrian AR_PHY_TIMING2_DC_OFFSET); 5053250003Sadrian ahp->ah_disable_cck = MS(OS_REG_READ(ah, AR_PHY_MODE), 5054250003Sadrian AR_PHY_MODE_DISABLE_CCK); 5055250003Sadrian 5056250008Sadrian if (AH9300(ah)->ah_enable_keysearch_always) { 5057250003Sadrian ar9300_enable_keysearch_always(ah, 1); 5058250003Sadrian } 5059250003Sadrian 5060250003Sadrian#if ATH_LOW_POWER_ENABLE 5061250003Sadrian#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val) 5062250003Sadrian#define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) 5063250003Sadrian if (AR_SREV_OSPREY(ah)) { 5064250003Sadrian REG_WRITE(0xb4000080, REG_READ(0xb4000080) | 3); 5065250003Sadrian OS_REG_WRITE(ah, AR_RTC_RESET, 1); 5066250003Sadrian OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), 5067250003Sadrian AR_PCIE_PM_CTRL_ENA); 5068250003Sadrian OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_SPARE), 0xffffffff); 5069250003Sadrian } 5070250003Sadrian#undef REG_READ 5071250003Sadrian#undef REG_WRITE 5072250003Sadrian#endif /* ATH_LOW_POWER_ENABLE */ 5073250003Sadrian 5074250003Sadrian WAR_USB_DISABLE_PLL_LOCK_DETECT(ah); 5075250003Sadrian 5076250003Sadrian /* H/W Green TX */ 5077250003Sadrian ar9300_control_signals_for_green_tx_mode(ah); 5078250003Sadrian /* Smart Antenna, only for 5GHz on Scropion */ 5079250008Sadrian if (IEEE80211_IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan)) && AR_SREV_SCORPION(ah)) { 5080250003Sadrian ahp->ah_smartantenna_enable = 0; 5081250003Sadrian } 5082250003Sadrian 5083250003Sadrian ar9300_set_smart_antenna(ah, ahp->ah_smartantenna_enable); 5084250003Sadrian 5085250003Sadrian 5086250003Sadrian return AH_TRUE; 5087250003Sadrianbad: 5088250003Sadrian OS_MARK(ah, AH_MARK_RESET_DONE, ecode); 5089250003Sadrian *status = ecode; 5090250003Sadrian 5091250003Sadrian return AH_FALSE; 5092250003Sadrian#undef FAIL 5093250003Sadrian} 5094250003Sadrian 5095250003Sadrianvoid 5096250003Sadrianar9300_green_ap_ps_on_off( struct ath_hal *ah, u_int16_t on_off) 5097250003Sadrian{ 5098250003Sadrian /* Set/reset the ps flag */ 5099250008Sadrian AH9300(ah)->green_ap_ps_on = !!on_off; 5100250003Sadrian} 5101250003Sadrian 5102250003Sadrian/* 5103250003Sadrian * This function returns 1, where it is possible to do 5104250003Sadrian * single-chain power save. 5105250003Sadrian */ 5106250003Sadrianu_int16_t 5107250003Sadrianar9300_is_single_ant_power_save_possible(struct ath_hal *ah) 5108250003Sadrian{ 5109250003Sadrian return AH_TRUE; 5110250003Sadrian} 5111250003Sadrian 5112250003Sadrian/* To avoid compilation warnings. Functions not used when EMULATION. */ 5113250003Sadrian/* 5114250003Sadrian * ar9300_find_mag_approx() 5115250003Sadrian */ 5116250003Sadrianstatic int32_t 5117250003Sadrianar9300_find_mag_approx(struct ath_hal *ah, int32_t in_re, int32_t in_im) 5118250003Sadrian{ 5119250003Sadrian int32_t abs_i = abs(in_re); 5120250003Sadrian int32_t abs_q = abs(in_im); 5121250003Sadrian int32_t max_abs, min_abs; 5122250003Sadrian 5123250003Sadrian if (abs_i > abs_q) { 5124250003Sadrian max_abs = abs_i; 5125250003Sadrian min_abs = abs_q; 5126250003Sadrian } else { 5127250003Sadrian max_abs = abs_q; 5128250003Sadrian min_abs = abs_i; 5129250003Sadrian } 5130250003Sadrian 5131250003Sadrian return (max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4)); 5132250003Sadrian} 5133250003Sadrian 5134250003Sadrian/* 5135250003Sadrian * ar9300_solve_iq_cal() 5136250003Sadrian * solve 4x4 linear equation used in loopback iq cal. 5137250003Sadrian */ 5138250003Sadrianstatic HAL_BOOL 5139250003Sadrianar9300_solve_iq_cal( 5140250003Sadrian struct ath_hal *ah, 5141250003Sadrian int32_t sin_2phi_1, 5142250003Sadrian int32_t cos_2phi_1, 5143250003Sadrian int32_t sin_2phi_2, 5144250003Sadrian int32_t cos_2phi_2, 5145250003Sadrian int32_t mag_a0_d0, 5146250003Sadrian int32_t phs_a0_d0, 5147250003Sadrian int32_t mag_a1_d0, 5148250003Sadrian int32_t phs_a1_d0, 5149250003Sadrian int32_t solved_eq[]) 5150250003Sadrian{ 5151250003Sadrian int32_t f1 = cos_2phi_1 - cos_2phi_2; 5152250003Sadrian int32_t f3 = sin_2phi_1 - sin_2phi_2; 5153250003Sadrian int32_t f2; 5154250003Sadrian int32_t mag_tx, phs_tx, mag_rx, phs_rx; 5155250003Sadrian const int32_t result_shift = 1 << 15; 5156250003Sadrian 5157250003Sadrian f2 = (((int64_t)f1 * (int64_t)f1) / result_shift) + (((int64_t)f3 * (int64_t)f3) / result_shift); 5158250003Sadrian 5159250003Sadrian if (0 == f2) { 5160250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d).\n", 5161250003Sadrian __func__, __LINE__); 5162250003Sadrian return AH_FALSE; 5163250003Sadrian } 5164250003Sadrian 5165250003Sadrian /* magnitude mismatch, tx */ 5166250003Sadrian mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0); 5167250003Sadrian /* phase mismatch, tx */ 5168250003Sadrian phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0); 5169250003Sadrian 5170250003Sadrian mag_tx = (mag_tx / f2); 5171250003Sadrian phs_tx = (phs_tx / f2); 5172250003Sadrian 5173250003Sadrian /* magnitude mismatch, rx */ 5174250003Sadrian mag_rx = 5175250003Sadrian mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / result_shift; 5176250003Sadrian /* phase mismatch, rx */ 5177250003Sadrian phs_rx = 5178250003Sadrian phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / result_shift; 5179250003Sadrian 5180250003Sadrian solved_eq[0] = mag_tx; 5181250003Sadrian solved_eq[1] = phs_tx; 5182250003Sadrian solved_eq[2] = mag_rx; 5183250003Sadrian solved_eq[3] = phs_rx; 5184250003Sadrian 5185250003Sadrian return AH_TRUE; 5186250003Sadrian} 5187250003Sadrian 5188250003Sadrian/* 5189250003Sadrian * ar9300_calc_iq_corr() 5190250003Sadrian */ 5191250003Sadrianstatic HAL_BOOL 5192250003Sadrianar9300_calc_iq_corr(struct ath_hal *ah, int32_t chain_idx, 5193250003Sadrian const int32_t iq_res[], int32_t iqc_coeff[]) 5194250003Sadrian{ 5195250003Sadrian int32_t i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0; 5196250003Sadrian int32_t i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1; 5197250003Sadrian int32_t i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0; 5198250003Sadrian int32_t i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1; 5199250003Sadrian int32_t mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1; 5200250003Sadrian int32_t phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1; 5201250003Sadrian int32_t sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2; 5202250003Sadrian int32_t mag_tx, phs_tx, mag_rx, phs_rx; 5203250003Sadrian int32_t solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx; 5204250003Sadrian int32_t q_q_coff, q_i_coff; 5205250003Sadrian const int32_t res_scale = 1 << 15; 5206250003Sadrian const int32_t delpt_shift = 1 << 8; 5207250003Sadrian int32_t mag1, mag2; 5208250003Sadrian 5209250003Sadrian i2_m_q2_a0_d0 = iq_res[0] & 0xfff; 5210250003Sadrian i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff; 5211250003Sadrian iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8); 5212250003Sadrian 5213250003Sadrian if (i2_m_q2_a0_d0 > 0x800) { 5214250003Sadrian i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1); 5215250003Sadrian } 5216250003Sadrian if (iq_corr_a0_d0 > 0x800) { 5217250003Sadrian iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1); 5218250003Sadrian } 5219250003Sadrian 5220250003Sadrian i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff; 5221250003Sadrian i2_p_q2_a0_d1 = (iq_res[2] & 0xfff); 5222250003Sadrian iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff; 5223250003Sadrian 5224250003Sadrian if (i2_m_q2_a0_d1 > 0x800) { 5225250003Sadrian i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); 5226250003Sadrian } 5227250003Sadrian if (iq_corr_a0_d1 > 0x800) { 5228250003Sadrian iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); 5229250003Sadrian } 5230250003Sadrian 5231250003Sadrian i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8); 5232250003Sadrian i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff; 5233250003Sadrian iq_corr_a1_d0 = iq_res[4] & 0xfff; 5234250003Sadrian 5235250003Sadrian if (i2_m_q2_a1_d0 > 0x800) { 5236250003Sadrian i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1); 5237250003Sadrian } 5238250003Sadrian if (iq_corr_a1_d0 > 0x800) { 5239250003Sadrian iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1); 5240250003Sadrian } 5241250003Sadrian 5242250003Sadrian i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff; 5243250003Sadrian i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8); 5244250003Sadrian iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff; 5245250003Sadrian 5246250003Sadrian if (i2_m_q2_a1_d1 > 0x800) { 5247250003Sadrian i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1); 5248250003Sadrian } 5249250003Sadrian if (iq_corr_a1_d1 > 0x800) { 5250250003Sadrian iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1); 5251250003Sadrian } 5252250003Sadrian 5253250003Sadrian if ((i2_p_q2_a0_d0 == 0) || 5254250003Sadrian (i2_p_q2_a0_d1 == 0) || 5255250003Sadrian (i2_p_q2_a1_d0 == 0) || 5256250003Sadrian (i2_p_q2_a1_d1 == 0)) { 5257250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5258250003Sadrian "%s: Divide by 0(%d):\na0_d0=%d\na0_d1=%d\na2_d0=%d\na1_d1=%d\n", 5259250003Sadrian __func__, __LINE__, 5260250003Sadrian i2_p_q2_a0_d0, i2_p_q2_a0_d1, i2_p_q2_a1_d0, i2_p_q2_a1_d1); 5261250003Sadrian return AH_FALSE; 5262250003Sadrian } 5263250003Sadrian 5264250003Sadrian if ((i2_p_q2_a0_d0 <= 1024) || (i2_p_q2_a0_d0 > 2047) || 5265250003Sadrian (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) || 5266250003Sadrian (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) || 5267250003Sadrian (i2_p_q2_a0_d0 <= iq_corr_a0_d0) || 5268250003Sadrian (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) || 5269250003Sadrian (i2_p_q2_a0_d1 <= iq_corr_a0_d1) || 5270250003Sadrian (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) || 5271250003Sadrian (i2_p_q2_a1_d0 <= iq_corr_a1_d0) || 5272250003Sadrian (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) || 5273250003Sadrian (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) { 5274250003Sadrian return AH_FALSE; 5275250003Sadrian } 5276250003Sadrian 5277250003Sadrian mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; 5278250003Sadrian phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; 5279250003Sadrian 5280250003Sadrian mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1; 5281250003Sadrian phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1; 5282250003Sadrian 5283250003Sadrian mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0; 5284250003Sadrian phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0; 5285250003Sadrian 5286250003Sadrian mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1; 5287250003Sadrian phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1; 5288250003Sadrian 5289250003Sadrian /* without analog phase shift */ 5290250003Sadrian sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT); 5291250003Sadrian /* without analog phase shift */ 5292250003Sadrian cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT); 5293250003Sadrian /* with analog phase shift */ 5294250003Sadrian sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT); 5295250003Sadrian /* with analog phase shift */ 5296250003Sadrian cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT); 5297250003Sadrian 5298250003Sadrian /* force sin^2 + cos^2 = 1; */ 5299250003Sadrian /* find magnitude by approximation */ 5300250003Sadrian mag1 = ar9300_find_mag_approx(ah, cos_2phi_1, sin_2phi_1); 5301250003Sadrian mag2 = ar9300_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); 5302250003Sadrian 5303250003Sadrian if ((mag1 == 0) || (mag2 == 0)) { 5304250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5305250003Sadrian "%s: Divide by 0(%d): mag1=%d, mag2=%d\n", 5306250003Sadrian __func__, __LINE__, mag1, mag2); 5307250003Sadrian return AH_FALSE; 5308250003Sadrian } 5309250003Sadrian 5310250003Sadrian /* normalization sin and cos by mag */ 5311250003Sadrian sin_2phi_1 = (sin_2phi_1 * res_scale / mag1); 5312250003Sadrian cos_2phi_1 = (cos_2phi_1 * res_scale / mag1); 5313250003Sadrian sin_2phi_2 = (sin_2phi_2 * res_scale / mag2); 5314250003Sadrian cos_2phi_2 = (cos_2phi_2 * res_scale / mag2); 5315250003Sadrian 5316250003Sadrian /* calculate IQ mismatch */ 5317250008Sadrian if (AH_FALSE == ar9300_solve_iq_cal(ah, 5318250003Sadrian sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2, mag_a0_d0, 5319250003Sadrian phs_a0_d0, mag_a1_d0, phs_a1_d0, solved_eq)) 5320250003Sadrian { 5321250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5322250003Sadrian "%s: Call to ar9300_solve_iq_cal failed.\n", __func__); 5323250003Sadrian return AH_FALSE; 5324250003Sadrian } 5325250003Sadrian 5326250003Sadrian mag_tx = solved_eq[0]; 5327250003Sadrian phs_tx = solved_eq[1]; 5328250003Sadrian mag_rx = solved_eq[2]; 5329250003Sadrian phs_rx = solved_eq[3]; 5330250003Sadrian 5331250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5332250003Sadrian "%s: chain %d: mag mismatch=%d phase mismatch=%d\n", 5333250003Sadrian __func__, chain_idx, mag_tx / res_scale, phs_tx / res_scale); 5334250003Sadrian 5335250003Sadrian if (res_scale == mag_tx) { 5336250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5337250003Sadrian "%s: Divide by 0(%d): mag_tx=%d, res_scale=%d\n", 5338250003Sadrian __func__, __LINE__, mag_tx, res_scale); 5339250003Sadrian return AH_FALSE; 5340250003Sadrian } 5341250003Sadrian 5342250003Sadrian /* calculate and quantize Tx IQ correction factor */ 5343250003Sadrian mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx); 5344250003Sadrian phs_corr_tx = -phs_tx; 5345250003Sadrian 5346250003Sadrian q_q_coff = (mag_corr_tx * 128 / res_scale); 5347250003Sadrian q_i_coff = (phs_corr_tx * 256 / res_scale); 5348250003Sadrian 5349250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5350250003Sadrian "%s: tx chain %d: mag corr=%d phase corr=%d\n", 5351250003Sadrian __func__, chain_idx, q_q_coff, q_i_coff); 5352250003Sadrian 5353250003Sadrian if (q_i_coff < -63) { 5354250003Sadrian q_i_coff = -63; 5355250003Sadrian } 5356250003Sadrian if (q_i_coff > 63) { 5357250003Sadrian q_i_coff = 63; 5358250003Sadrian } 5359250003Sadrian if (q_q_coff < -63) { 5360250003Sadrian q_q_coff = -63; 5361250003Sadrian } 5362250003Sadrian if (q_q_coff > 63) { 5363250003Sadrian q_q_coff = 63; 5364250003Sadrian } 5365250003Sadrian 5366250003Sadrian iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); 5367250003Sadrian 5368250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: tx chain %d: iq corr coeff=%x\n", 5369250003Sadrian __func__, chain_idx, iqc_coeff[0]); 5370250003Sadrian 5371250003Sadrian if (-mag_rx == res_scale) { 5372250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5373250003Sadrian "%s: Divide by 0(%d): mag_rx=%d, res_scale=%d\n", 5374250003Sadrian __func__, __LINE__, mag_rx, res_scale); 5375250003Sadrian return AH_FALSE; 5376250003Sadrian } 5377250003Sadrian 5378250003Sadrian /* calculate and quantize Rx IQ correction factors */ 5379250003Sadrian mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx); 5380250003Sadrian phs_corr_rx = -phs_rx; 5381250003Sadrian 5382250003Sadrian q_q_coff = (mag_corr_rx * 128 / res_scale); 5383250003Sadrian q_i_coff = (phs_corr_rx * 256 / res_scale); 5384250003Sadrian 5385250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5386250003Sadrian "%s: rx chain %d: mag corr=%d phase corr=%d\n", 5387250003Sadrian __func__, chain_idx, q_q_coff, q_i_coff); 5388250003Sadrian 5389250003Sadrian if (q_i_coff < -63) { 5390250003Sadrian q_i_coff = -63; 5391250003Sadrian } 5392250003Sadrian if (q_i_coff > 63) { 5393250003Sadrian q_i_coff = 63; 5394250003Sadrian } 5395250003Sadrian if (q_q_coff < -63) { 5396250003Sadrian q_q_coff = -63; 5397250003Sadrian } 5398250003Sadrian if (q_q_coff > 63) { 5399250003Sadrian q_q_coff = 63; 5400250003Sadrian } 5401250003Sadrian 5402250003Sadrian iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); 5403250003Sadrian 5404250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: rx chain %d: iq corr coeff=%x\n", 5405250003Sadrian __func__, chain_idx, iqc_coeff[1]); 5406250003Sadrian 5407250003Sadrian return AH_TRUE; 5408250003Sadrian} 5409250003Sadrian 5410250003Sadrian#define MAX_MAG_DELTA 11 //maximum magnitude mismatch delta across gains 5411250003Sadrian#define MAX_PHS_DELTA 10 //maximum phase mismatch delta across gains 5412250003Sadrian#define ABS(x) ((x) >= 0 ? (x) : (-(x))) 5413250003Sadrian 5414250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5415250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5416250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5417250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5418250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5419250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5420250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5421250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5422250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5423250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5424250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5425250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5426250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5427250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5428250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5429250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5430250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5431250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5432250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5433250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5434250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5435250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5436250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5437250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5438250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5439250003Sadrian }; 5440250003Sadrian 5441250003Sadrianstatic void 5442250003Sadrianar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, u_int32_t num_chains, 5443250008Sadrian struct coeff_t *coeff, HAL_BOOL is_cal_reusable) 5444250003Sadrian{ 5445250003Sadrian int nmeasurement, ch_idx, im; 5446250003Sadrian int32_t magnitude, phase; 5447250003Sadrian int32_t magnitude_max, phase_max; 5448250003Sadrian int32_t magnitude_min, phase_min; 5449250003Sadrian 5450250003Sadrian int32_t magnitude_max_idx, phase_max_idx; 5451250003Sadrian int32_t magnitude_min_idx, phase_min_idx; 5452250003Sadrian 5453250003Sadrian int32_t magnitude_avg, phase_avg; 5454250003Sadrian int32_t outlier_mag_idx = 0; 5455250003Sadrian int32_t outlier_phs_idx = 0; 5456250003Sadrian 5457250003Sadrian 5458250003Sadrian if (AR_SREV_POSEIDON(ah)) { 5459250003Sadrian HALASSERT(num_chains == 0x1); 5460250003Sadrian 5461250003Sadrian tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5462250003Sadrian tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5463250003Sadrian tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5464250003Sadrian tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5465250003Sadrian tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5466250003Sadrian tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5467250003Sadrian tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5468250003Sadrian tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5469250003Sadrian } 5470250003Sadrian 5471250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5472250003Sadrian nmeasurement = OS_REG_READ_FIELD(ah, 5473250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); 5474250003Sadrian if (nmeasurement > MAX_MEASUREMENT) { 5475250003Sadrian nmeasurement = MAX_MEASUREMENT; 5476250003Sadrian } 5477250003Sadrian 5478250003Sadrian if (!AR_SREV_SCORPION(ah)) { 5479250003Sadrian /* 5480250003Sadrian * reset max/min variable to min/max values so that 5481250003Sadrian * we always start with 1st calibrated gain value 5482250003Sadrian */ 5483250003Sadrian magnitude_max = -64; 5484250003Sadrian phase_max = -64; 5485250003Sadrian magnitude_min = 63; 5486250003Sadrian phase_min = 63; 5487250003Sadrian magnitude_avg = 0; 5488250003Sadrian phase_avg = 0; 5489250003Sadrian magnitude_max_idx = 0; 5490250003Sadrian magnitude_min_idx = 0; 5491250003Sadrian phase_max_idx = 0; 5492250003Sadrian phase_min_idx = 0; 5493250003Sadrian 5494250003Sadrian /* detect outlier only if nmeasurement > 1 */ 5495250003Sadrian if (nmeasurement > 1) { 5496250003Sadrian /* printf("----------- start outlier detection -----------\n"); */ 5497250003Sadrian /* 5498250003Sadrian * find max/min and phase/mag mismatch across all calibrated gains 5499250003Sadrian */ 5500250003Sadrian for (im = 0; im < nmeasurement; im++) { 5501250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5502250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5503250003Sadrian 5504250003Sadrian magnitude_avg = magnitude_avg + magnitude; 5505250003Sadrian phase_avg = phase_avg + phase; 5506250003Sadrian if (magnitude > magnitude_max) { 5507250003Sadrian magnitude_max = magnitude; 5508250003Sadrian magnitude_max_idx = im; 5509250003Sadrian } 5510250003Sadrian if (magnitude < magnitude_min) { 5511250003Sadrian magnitude_min = magnitude; 5512250003Sadrian magnitude_min_idx = im; 5513250003Sadrian } 5514250003Sadrian if (phase > phase_max) { 5515250003Sadrian phase_max = phase; 5516250003Sadrian phase_max_idx = im; 5517250003Sadrian } 5518250003Sadrian if (phase < phase_min) { 5519250003Sadrian phase_min = phase; 5520250003Sadrian phase_min_idx = im; 5521250003Sadrian } 5522250003Sadrian } 5523250003Sadrian /* find average (exclude max abs value) */ 5524250003Sadrian for (im = 0; im < nmeasurement; im++) { 5525250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5526250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5527250003Sadrian if ((ABS(magnitude) < ABS(magnitude_max)) || 5528250003Sadrian (ABS(magnitude) < ABS(magnitude_min))) 5529250003Sadrian { 5530250003Sadrian magnitude_avg = magnitude_avg + magnitude; 5531250003Sadrian } 5532250003Sadrian if ((ABS(phase) < ABS(phase_max)) || 5533250003Sadrian (ABS(phase) < ABS(phase_min))) 5534250003Sadrian { 5535250003Sadrian phase_avg = phase_avg + phase; 5536250003Sadrian } 5537250003Sadrian } 5538250003Sadrian magnitude_avg = magnitude_avg / (nmeasurement - 1); 5539250003Sadrian phase_avg = phase_avg / (nmeasurement - 1); 5540250003Sadrian 5541250003Sadrian /* detect magnitude outlier */ 5542250003Sadrian if (ABS(magnitude_max - magnitude_min) > MAX_MAG_DELTA) { 5543250003Sadrian if (ABS(magnitude_max - magnitude_avg) > 5544250003Sadrian ABS(magnitude_min - magnitude_avg)) 5545250003Sadrian { 5546250003Sadrian /* max is outlier, force to avg */ 5547250003Sadrian outlier_mag_idx = magnitude_max_idx; 5548250003Sadrian } else { 5549250003Sadrian /* min is outlier, force to avg */ 5550250003Sadrian outlier_mag_idx = magnitude_min_idx; 5551250003Sadrian } 5552250003Sadrian coeff->mag_coeff[ch_idx][outlier_mag_idx][0] = magnitude_avg; 5553250003Sadrian coeff->phs_coeff[ch_idx][outlier_mag_idx][0] = phase_avg; 5554250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5555250003Sadrian "[ch%d][outlier mag gain%d]:: " 5556250003Sadrian "mag_avg = %d (/128), phase_avg = %d (/256)\n", 5557250003Sadrian ch_idx, outlier_mag_idx, magnitude_avg, phase_avg); 5558250003Sadrian } 5559250003Sadrian /* detect phase outlier */ 5560250003Sadrian if (ABS(phase_max - phase_min) > MAX_PHS_DELTA) { 5561250003Sadrian if (ABS(phase_max-phase_avg) > ABS(phase_min - phase_avg)) { 5562250003Sadrian /* max is outlier, force to avg */ 5563250003Sadrian outlier_phs_idx = phase_max_idx; 5564250003Sadrian } else{ 5565250003Sadrian /* min is outlier, force to avg */ 5566250003Sadrian outlier_phs_idx = phase_min_idx; 5567250003Sadrian } 5568250003Sadrian coeff->mag_coeff[ch_idx][outlier_phs_idx][0] = magnitude_avg; 5569250003Sadrian coeff->phs_coeff[ch_idx][outlier_phs_idx][0] = phase_avg; 5570250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5571250003Sadrian "[ch%d][outlier phs gain%d]:: " 5572250003Sadrian "mag_avg = %d (/128), phase_avg = %d (/256)\n", 5573250003Sadrian ch_idx, outlier_phs_idx, magnitude_avg, phase_avg); 5574250003Sadrian } 5575250003Sadrian } 5576250003Sadrian } 5577250003Sadrian 5578250003Sadrian /*printf("------------ after outlier detection -------------\n");*/ 5579250003Sadrian for (im = 0; im < nmeasurement; im++) { 5580250003Sadrian magnitude = coeff->mag_coeff[ch_idx][im][0]; 5581250003Sadrian phase = coeff->phs_coeff[ch_idx][im][0]; 5582250003Sadrian 5583250003Sadrian #if 0 5584250003Sadrian printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n", 5585250003Sadrian ch_idx, im, magnitude, phase); 5586250003Sadrian #endif 5587250003Sadrian 5588250003Sadrian coeff->iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7); 5589250003Sadrian 5590250003Sadrian if ((im % 2) == 0) { 5591250003Sadrian OS_REG_RMW_FIELD(ah, 5592250003Sadrian tx_corr_coeff[im][ch_idx], 5593250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 5594250003Sadrian coeff->iqc_coeff[0]); 5595250003Sadrian } else { 5596250003Sadrian OS_REG_RMW_FIELD(ah, 5597250003Sadrian tx_corr_coeff[im][ch_idx], 5598250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 5599250003Sadrian coeff->iqc_coeff[0]); 5600250003Sadrian } 5601250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5602250003Sadrian ichan->tx_corr_coeff[im][ch_idx] = coeff->iqc_coeff[0]; 5603250003Sadrian#endif 5604250003Sadrian } 5605250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5606250003Sadrian ichan->num_measures[ch_idx] = nmeasurement; 5607250003Sadrian#endif 5608250003Sadrian } 5609250003Sadrian 5610250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 5611250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 5612250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 5613250003Sadrian AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 5614250003Sadrian 5615250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5616250003Sadrian if (is_cal_reusable) { 5617250003Sadrian ichan->one_time_txiqcal_done = AH_TRUE; 5618250003Sadrian HALDEBUG(ah, HAL_DEBUG_FCS_RTT, 5619250003Sadrian "(FCS) TXIQCAL saved - %d\n", ichan->channel); 5620250003Sadrian } 5621250003Sadrian#endif 5622250003Sadrian} 5623250003Sadrian 5624250003Sadrian#if ATH_SUPPORT_CAL_REUSE 5625250003Sadrianstatic void 5626250003Sadrianar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 5627250003Sadrian{ 5628250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 5629250003Sadrian int nmeasurement, ch_idx, im; 5630250003Sadrian 5631250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5632250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5633250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5634250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5635250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5636250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5637250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5638250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5639250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5640250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5641250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5642250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5643250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5644250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5645250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5646250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5647250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5648250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5649250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5650250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5651250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5652250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5653250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5654250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5655250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5656250003Sadrian }; 5657250003Sadrian 5658250003Sadrian if (AR_SREV_POSEIDON(ah)) { 5659250003Sadrian HALASSERT(ahp->ah_tx_cal_chainmask == 0x1); 5660250003Sadrian 5661250003Sadrian tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5662250003Sadrian tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; 5663250003Sadrian tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5664250003Sadrian tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; 5665250003Sadrian tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5666250003Sadrian tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; 5667250003Sadrian tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5668250003Sadrian tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; 5669250003Sadrian } 5670250003Sadrian 5671250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 5672250003Sadrian if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { 5673250003Sadrian continue; 5674250003Sadrian } 5675250003Sadrian nmeasurement = ichan->num_measures[ch_idx]; 5676250003Sadrian 5677250003Sadrian for (im = 0; im < nmeasurement; im++) { 5678250003Sadrian if ((im % 2) == 0) { 5679250003Sadrian OS_REG_RMW_FIELD(ah, 5680250003Sadrian tx_corr_coeff[im][ch_idx], 5681250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 5682250003Sadrian ichan->tx_corr_coeff[im][ch_idx]); 5683250003Sadrian } else { 5684250003Sadrian OS_REG_RMW_FIELD(ah, 5685250003Sadrian tx_corr_coeff[im][ch_idx], 5686250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 5687250003Sadrian ichan->tx_corr_coeff[im][ch_idx]); 5688250003Sadrian } 5689250003Sadrian } 5690250003Sadrian } 5691250003Sadrian 5692250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 5693250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 5694250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 5695250003Sadrian AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 5696250003Sadrian} 5697250003Sadrian#endif 5698250003Sadrian 5699250003Sadrian/* 5700250003Sadrian * ar9300_tx_iq_cal_hw_run is only needed for osprey/wasp/hornet 5701250003Sadrian * It is not needed for jupiter/poseidon. 5702250003Sadrian */ 5703250003SadrianHAL_BOOL 5704250003Sadrianar9300_tx_iq_cal_hw_run(struct ath_hal *ah) 5705250003Sadrian{ 5706250003Sadrian int is_tx_gain_forced; 5707250003Sadrian 5708250003Sadrian is_tx_gain_forced = OS_REG_READ_FIELD(ah, 5709250003Sadrian AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE); 5710250003Sadrian if (is_tx_gain_forced) { 5711250003Sadrian /*printf("Tx gain can not be forced during tx I/Q cal!\n");*/ 5712250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0); 5713250003Sadrian } 5714250003Sadrian 5715250003Sadrian /* enable tx IQ cal */ 5716250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah), 5717250003Sadrian AR_PHY_TX_IQCAL_START_DO_CAL, AR_PHY_TX_IQCAL_START_DO_CAL); 5718250003Sadrian 5719250003Sadrian if (!ath_hal_wait(ah, 5720250008Sadrian AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 0)) 5721250003Sadrian { 5722250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5723250003Sadrian "%s: Tx IQ Cal is never completed.\n", __func__); 5724250003Sadrian return AH_FALSE; 5725250003Sadrian } 5726250003Sadrian return AH_TRUE; 5727250003Sadrian} 5728250003Sadrian 5729250003Sadrianstatic void 5730250003Sadrianar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, 5731250003Sadrian int iqcal_idx, int max_iqcal,HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr) 5732250003Sadrian{ 5733250003Sadrian int nmeasurement=0, im, ix, iy, temp; 5734250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 5735250003Sadrian u_int32_t txiqcal_status[AR9300_MAX_CHAINS] = { 5736250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), 5737250003Sadrian AR_PHY_TX_IQCAL_STATUS_B1, 5738250003Sadrian AR_PHY_TX_IQCAL_STATUS_B2, 5739250003Sadrian }; 5740250003Sadrian const u_int32_t chan_info_tab[] = { 5741250003Sadrian AR_PHY_CHAN_INFO_TAB_0, 5742250003Sadrian AR_PHY_CHAN_INFO_TAB_1, 5743250003Sadrian AR_PHY_CHAN_INFO_TAB_2, 5744250003Sadrian }; 5745250003Sadrian int32_t iq_res[6]; 5746250003Sadrian int32_t ch_idx, j; 5747250003Sadrian u_int32_t num_chains = 0; 5748250003Sadrian static struct coeff_t coeff; 5749250003Sadrian txiqcal_status[0] = AR_PHY_TX_IQCAL_STATUS_B0(ah); 5750250003Sadrian 5751250003Sadrian for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { 5752250003Sadrian if (ahp->ah_tx_chainmask & (1 << ch_idx)) { 5753250003Sadrian num_chains++; 5754250003Sadrian } 5755250003Sadrian } 5756250003Sadrian 5757250003Sadrian if (apply_last_corr) { 5758250003Sadrian if (coeff.last_cal == AH_TRUE) { 5759250003Sadrian int32_t magnitude, phase; 5760250003Sadrian int ch_idx, im; 5761250003Sadrian u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { 5762250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5763250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5764250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5765250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, 5766250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, 5767250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, 5768250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5769250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5770250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5771250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, 5772250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, 5773250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, 5774250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5775250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5776250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5777250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, 5778250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, 5779250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, 5780250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5781250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5782250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5783250003Sadrian { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, 5784250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, 5785250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, 5786250003Sadrian }; 5787250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5788250003Sadrian for (im = 0; im < coeff.last_nmeasurement; im++) { 5789250003Sadrian magnitude = coeff.mag_coeff[ch_idx][im][0]; 5790250003Sadrian phase = coeff.phs_coeff[ch_idx][im][0]; 5791250003Sadrian 5792250003Sadrian#if 0 5793250003Sadrian printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n", 5794250003Sadrian ch_idx, im, magnitude, phase); 5795250003Sadrian#endif 5796250003Sadrian 5797250003Sadrian coeff.iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7); 5798250003Sadrian if ((im % 2) == 0) { 5799250003Sadrian OS_REG_RMW_FIELD(ah, 5800250003Sadrian tx_corr_coeff[im][ch_idx], 5801250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 5802250003Sadrian coeff.iqc_coeff[0]); 5803250003Sadrian } else { 5804250003Sadrian OS_REG_RMW_FIELD(ah, 5805250003Sadrian tx_corr_coeff[im][ch_idx], 5806250003Sadrian AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 5807250003Sadrian coeff.iqc_coeff[0]); 5808250003Sadrian } 5809250003Sadrian } 5810250003Sadrian } 5811250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 5812250003Sadrian AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 5813250003Sadrian } 5814250003Sadrian return; 5815250003Sadrian } 5816250003Sadrian 5817250003Sadrian 5818250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5819250003Sadrian nmeasurement = OS_REG_READ_FIELD(ah, 5820250003Sadrian AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); 5821250003Sadrian if (nmeasurement > MAX_MEASUREMENT) { 5822250003Sadrian nmeasurement = MAX_MEASUREMENT; 5823250003Sadrian } 5824250003Sadrian 5825250003Sadrian for (im = 0; im < nmeasurement; im++) { 5826250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5827250003Sadrian "%s: Doing Tx IQ Cal for chain %d.\n", __func__, ch_idx); 5828250003Sadrian if (OS_REG_READ(ah, txiqcal_status[ch_idx]) & 5829250003Sadrian AR_PHY_TX_IQCAL_STATUS_FAILED) 5830250003Sadrian { 5831250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5832250003Sadrian "%s: Tx IQ Cal failed for chain %d.\n", __func__, ch_idx); 5833250003Sadrian goto TX_IQ_CAL_FAILED_; 5834250003Sadrian } 5835250003Sadrian 5836250003Sadrian for (j = 0; j < 3; j++) { 5837250003Sadrian u_int32_t idx = 2 * j; 5838250003Sadrian /* 3 registers for each calibration result */ 5839250003Sadrian u_int32_t offset = 4 * (3 * im + j); 5840250003Sadrian 5841250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, 5842250003Sadrian AR_PHY_CHAN_INFO_TAB_S2_READ, 0); 5843250003Sadrian /* 32 bits */ 5844250003Sadrian iq_res[idx] = OS_REG_READ(ah, chan_info_tab[ch_idx] + offset); 5845250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, 5846250003Sadrian AR_PHY_CHAN_INFO_TAB_S2_READ, 1); 5847250003Sadrian /* 16 bits */ 5848250003Sadrian iq_res[idx + 1] = 0xffff & 5849250003Sadrian OS_REG_READ(ah, chan_info_tab[ch_idx] + offset); 5850250003Sadrian 5851250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5852250003Sadrian "%s: IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", 5853250003Sadrian __func__, idx, iq_res[idx], idx + 1, iq_res[idx + 1]); 5854250003Sadrian } 5855250003Sadrian 5856250008Sadrian if (AH_FALSE == ar9300_calc_iq_corr( 5857250003Sadrian ah, ch_idx, iq_res, coeff.iqc_coeff)) 5858250003Sadrian { 5859250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5860250003Sadrian "%s: Failed in calculation of IQ correction.\n", 5861250003Sadrian __func__); 5862250003Sadrian goto TX_IQ_CAL_FAILED_; 5863250003Sadrian } 5864250003Sadrian 5865250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1] = coeff.iqc_coeff[0] & 0x7f; 5866250003Sadrian coeff.mag_coeff[ch_idx][im][iqcal_idx-1] = (coeff.iqc_coeff[0] >> 7) & 0x7f; 5867250003Sadrian if (coeff.mag_coeff[ch_idx][im][iqcal_idx-1] > 63) { 5868250003Sadrian coeff.mag_coeff[ch_idx][im][iqcal_idx-1] -= 128; 5869250003Sadrian } 5870250003Sadrian if (coeff.phs_coeff[ch_idx][im][iqcal_idx-1] > 63) { 5871250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1] -= 128; 5872250003Sadrian } 5873250003Sadrian#if 0 5874250003Sadrian ath_hal_printf(ah, "IQCAL::[ch%d][gain%d]:: mag = %d phase = %d \n", 5875250003Sadrian ch_idx, im, coeff.mag_coeff[ch_idx][im][iqcal_idx-1], 5876250003Sadrian coeff.phs_coeff[ch_idx][im][iqcal_idx-1]); 5877250003Sadrian#endif 5878250003Sadrian } 5879250003Sadrian } 5880250003Sadrian //last iteration; calculate mag and phs 5881250003Sadrian if (iqcal_idx == max_iqcal) { 5882250003Sadrian if (max_iqcal>1) { 5883250003Sadrian for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { 5884250003Sadrian for (im = 0; im < nmeasurement; im++) { 5885250003Sadrian //sort mag and phs 5886250003Sadrian for( ix=0;ix<max_iqcal-1;ix++){ 5887250003Sadrian for( iy=ix+1;iy<=max_iqcal-1;iy++){ 5888250003Sadrian if(coeff.mag_coeff[ch_idx][im][iy] < 5889250003Sadrian coeff.mag_coeff[ch_idx][im][ix]) { 5890250003Sadrian //swap 5891250003Sadrian temp=coeff.mag_coeff[ch_idx][im][ix]; 5892250003Sadrian coeff.mag_coeff[ch_idx][im][ix] = coeff.mag_coeff[ch_idx][im][iy]; 5893250003Sadrian coeff.mag_coeff[ch_idx][im][iy] = temp; 5894250003Sadrian } 5895250003Sadrian if(coeff.phs_coeff[ch_idx][im][iy] < 5896250003Sadrian coeff.phs_coeff[ch_idx][im][ix]){ 5897250003Sadrian //swap 5898250003Sadrian temp=coeff.phs_coeff[ch_idx][im][ix]; 5899250003Sadrian coeff.phs_coeff[ch_idx][im][ix]=coeff.phs_coeff[ch_idx][im][iy]; 5900250003Sadrian coeff.phs_coeff[ch_idx][im][iy]=temp; 5901250003Sadrian } 5902250003Sadrian } 5903250003Sadrian } 5904250003Sadrian //select median; 3rd entry in the sorted array 5905250003Sadrian coeff.mag_coeff[ch_idx][im][0] = 5906250003Sadrian coeff.mag_coeff[ch_idx][im][max_iqcal/2]; 5907250003Sadrian coeff.phs_coeff[ch_idx][im][0] = 5908250003Sadrian coeff.phs_coeff[ch_idx][im][max_iqcal/2]; 5909250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, 5910250003Sadrian "IQCAL: Median [ch%d][gain%d]:: mag = %d phase = %d \n", 5911250003Sadrian ch_idx, im,coeff.mag_coeff[ch_idx][im][0], 5912250003Sadrian coeff.phs_coeff[ch_idx][im][0]); 5913250003Sadrian } 5914250003Sadrian } 5915250003Sadrian } 5916250003Sadrian ar9300_tx_iq_cal_outlier_detection(ah,ichan, num_chains, &coeff,is_cal_reusable); 5917250003Sadrian } 5918250003Sadrian 5919250003Sadrian 5920250003Sadrian coeff.last_nmeasurement = nmeasurement; 5921250003Sadrian coeff.last_cal = AH_TRUE; 5922250003Sadrian 5923250003Sadrian return; 5924250003Sadrian 5925250003SadrianTX_IQ_CAL_FAILED_: 5926250003Sadrian /* no need to print this, it is AGC failure not chip stuck */ 5927250003Sadrian /*ath_hal_printf(ah, "Tx IQ Cal failed(%d)\n", line);*/ 5928250003Sadrian coeff.last_cal = AH_FALSE; 5929250003Sadrian return; 5930250003Sadrian} 5931250003Sadrian 5932250003Sadrian 5933250003Sadrian/* 5934250003Sadrian * ar9300_disable_phy_restart 5935250003Sadrian * 5936250003Sadrian * In some BBpanics, we can disable the phyrestart 5937250003Sadrian * disable_phy_restart 5938250003Sadrian * != 0, disable the phy restart in h/w 5939250003Sadrian * == 0, enable the phy restart in h/w 5940250003Sadrian */ 5941250003Sadrianvoid ar9300_disable_phy_restart(struct ath_hal *ah, int disable_phy_restart) 5942250003Sadrian{ 5943250003Sadrian u_int32_t val; 5944250003Sadrian 5945250003Sadrian val = OS_REG_READ(ah, AR_PHY_RESTART); 5946250003Sadrian if (disable_phy_restart) { 5947250003Sadrian val &= ~AR_PHY_RESTART_ENA; 5948250008Sadrian AH9300(ah)->ah_phyrestart_disabled = 1; 5949250003Sadrian } else { 5950250003Sadrian val |= AR_PHY_RESTART_ENA; 5951250008Sadrian AH9300(ah)->ah_phyrestart_disabled = 0; 5952250003Sadrian } 5953250003Sadrian OS_REG_WRITE(ah, AR_PHY_RESTART, val); 5954250003Sadrian 5955250003Sadrian val = OS_REG_READ(ah, AR_PHY_RESTART); 5956250003Sadrian} 5957250003Sadrian 5958250003SadrianHAL_BOOL 5959250003Sadrianar9300_interference_is_present(struct ath_hal *ah) 5960250003Sadrian{ 5961250003Sadrian int i; 5962250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 5963250008Sadrian const struct ieee80211_channel *chan = ahpriv->ah_curchan; 5964250008Sadrian HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 5965250003Sadrian 5966250008Sadrian if (ichan == NULL) { 5967250008Sadrian ath_hal_printf(ah, "%s: called with ichan=NULL\n", __func__); 5968250008Sadrian return AH_FALSE; 5969250008Sadrian } 5970250008Sadrian 5971250003Sadrian /* This function is called after a stuck beacon, if EACS is enabled. 5972250003Sadrian * If CW interference is severe, then HW goes into a loop of continuous 5973250003Sadrian * stuck beacons and resets. On reset the NF cal history is cleared. 5974250003Sadrian * So the median value of the history cannot be used - 5975250003Sadrian * hence check if any value (Chain 0/Primary Channel) 5976250003Sadrian * is outside the bounds. 5977250003Sadrian */ 5978250008Sadrian HAL_NFCAL_HIST_FULL *h = AH_HOME_CHAN_NFCAL_HIST(ah, ichan); 5979250003Sadrian for (i = 0; i < HAL_NF_CAL_HIST_LEN_FULL; i++) { 5980250003Sadrian if (h->nf_cal_buffer[i][0] > 5981250008Sadrian AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta) 5982250003Sadrian { 5983250003Sadrian return AH_TRUE; 5984250003Sadrian } 5985250003Sadrian 5986250003Sadrian } 5987250003Sadrian return AH_FALSE; 5988250003Sadrian} 5989250003Sadrian 5990250003Sadrian#if ATH_SUPPORT_CRDC 5991250003Sadrianvoid 5992250003Sadrianar9300_crdc_rx_notify(struct ath_hal *ah, struct ath_rx_status *rxs) 5993250003Sadrian{ 5994250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 5995250003Sadrian int rssi_index; 5996250003Sadrian 5997250003Sadrian if ((!AR_SREV_WASP(ah)) || 5998250003Sadrian (!ahpriv->ah_config.ath_hal_crdc_enable)) { 5999250003Sadrian return; 6000250003Sadrian } 6001250003Sadrian 6002250003Sadrian if (rxs->rs_isaggr && rxs->rs_moreaggr) { 6003250003Sadrian return; 6004250003Sadrian } 6005250003Sadrian 6006250003Sadrian if ((rxs->rs_rssi_ctl0 >= HAL_RSSI_BAD) || 6007250003Sadrian (rxs->rs_rssi_ctl1 >= HAL_RSSI_BAD)) { 6008250003Sadrian return; 6009250003Sadrian } 6010250003Sadrian 6011250003Sadrian rssi_index = ah->ah_crdc_rssi_ptr % HAL_MAX_CRDC_RSSI_SAMPLE; 6012250003Sadrian 6013250003Sadrian ah->ah_crdc_rssi_sample[0][rssi_index] = rxs->rs_rssi_ctl0; 6014250003Sadrian ah->ah_crdc_rssi_sample[1][rssi_index] = rxs->rs_rssi_ctl1; 6015250003Sadrian 6016250003Sadrian ah->ah_crdc_rssi_ptr++; 6017250003Sadrian} 6018250003Sadrian 6019250003Sadrianstatic int 6020250003Sadrianar9300_crdc_avg_rssi(struct ath_hal *ah, int chain) 6021250003Sadrian{ 6022250003Sadrian int crdc_rssi_sum = 0; 6023250003Sadrian int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr, i; 6024250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6025250003Sadrian int crdc_window = ahpriv->ah_config.ath_hal_crdc_window; 6026250003Sadrian 6027250003Sadrian if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) { 6028250003Sadrian crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE; 6029250003Sadrian } 6030250003Sadrian 6031250003Sadrian for (i = 1; i <= crdc_window; i++) { 6032250003Sadrian crdc_rssi_sum += 6033250003Sadrian ah->ah_crdc_rssi_sample[chain] 6034250003Sadrian [(crdc_rssi_ptr - i) % HAL_MAX_CRDC_RSSI_SAMPLE]; 6035250003Sadrian } 6036250003Sadrian 6037250003Sadrian return crdc_rssi_sum / crdc_window; 6038250003Sadrian} 6039250003Sadrian 6040250003Sadrianstatic void 6041250003Sadrianar9300_crdc_activate(struct ath_hal *ah, int rssi_diff, int enable) 6042250003Sadrian{ 6043250003Sadrian int val, orig_val; 6044250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6045250003Sadrian int crdc_numerator = ahpriv->ah_config.ath_hal_crdc_numerator; 6046250003Sadrian int crdc_denominator = ahpriv->ah_config.ath_hal_crdc_denominator; 6047250003Sadrian int c = (rssi_diff * crdc_numerator) / crdc_denominator; 6048250003Sadrian 6049250003Sadrian val = orig_val = OS_REG_READ(ah, AR_PHY_MULTICHAIN_CTRL); 6050250003Sadrian val &= 0xffffff00; 6051250003Sadrian if (enable) { 6052250003Sadrian val |= 0x1; 6053250003Sadrian val |= ((c << 1) & 0xff); 6054250003Sadrian } 6055250003Sadrian OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_CTRL, val); 6056250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "diff: %02d comp: %02d reg: %08x %08x\n", 6057250003Sadrian rssi_diff, c, orig_val, val); 6058250003Sadrian} 6059250003Sadrian 6060250003Sadrian 6061250003Sadrianvoid ar9300_chain_rssi_diff_compensation(struct ath_hal *ah) 6062250003Sadrian{ 6063250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6064250003Sadrian int crdc_window = ahpriv->ah_config.ath_hal_crdc_window; 6065250003Sadrian int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr; 6066250003Sadrian int crdc_rssi_thresh = ahpriv->ah_config.ath_hal_crdc_rssithresh; 6067250003Sadrian int crdc_diff_thresh = ahpriv->ah_config.ath_hal_crdc_diffthresh; 6068250003Sadrian int avg_rssi[2], avg_rssi_diff; 6069250003Sadrian 6070250003Sadrian if ((!AR_SREV_WASP(ah)) || 6071250003Sadrian (!ahpriv->ah_config.ath_hal_crdc_enable)) { 6072250003Sadrian if (ah->ah_crdc_rssi_ptr) { 6073250003Sadrian ar9300_crdc_activate(ah, 0, 0); 6074250003Sadrian ah->ah_crdc_rssi_ptr = 0; 6075250003Sadrian } 6076250003Sadrian return; 6077250003Sadrian } 6078250003Sadrian 6079250003Sadrian if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) { 6080250003Sadrian crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE; 6081250003Sadrian } 6082250003Sadrian 6083250003Sadrian if (crdc_rssi_ptr < crdc_window) { 6084250003Sadrian return; 6085250003Sadrian } 6086250003Sadrian 6087250003Sadrian avg_rssi[0] = ar9300_crdc_avg_rssi(ah, 0); 6088250003Sadrian avg_rssi[1] = ar9300_crdc_avg_rssi(ah, 1); 6089250003Sadrian avg_rssi_diff = avg_rssi[1] - avg_rssi[0]; 6090250003Sadrian 6091250003Sadrian HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "crdc: avg: %02d %02d ", 6092250003Sadrian avg_rssi[0], avg_rssi[1]); 6093250003Sadrian 6094250003Sadrian if ((avg_rssi[0] < crdc_rssi_thresh) && 6095250003Sadrian (avg_rssi[1] < crdc_rssi_thresh)) { 6096250003Sadrian ar9300_crdc_activate(ah, 0, 0); 6097250003Sadrian } else { 6098250003Sadrian if (ABS(avg_rssi_diff) >= crdc_diff_thresh) { 6099250003Sadrian ar9300_crdc_activate(ah, avg_rssi_diff, 1); 6100250003Sadrian } else { 6101250003Sadrian ar9300_crdc_activate(ah, 0, 1); 6102250003Sadrian } 6103250003Sadrian } 6104250003Sadrian} 6105250003Sadrian#endif 6106250003Sadrian 6107250003Sadrian#if ATH_ANT_DIV_COMB 6108250003SadrianHAL_BOOL 6109250008Sadrianar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, const struct ieee80211_channel *chan) 6110250003Sadrian{ 6111250003Sadrian u_int32_t value; 6112250003Sadrian u_int32_t regval; 6113250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 6114250003Sadrian HAL_CHANNEL_INTERNAL *ichan; 6115250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 6116250003Sadrian HAL_CAPABILITIES *pcap = &ahpriv->ah_caps; 6117250003Sadrian 6118250003Sadrian if (AR_SREV_POSEIDON(ah)) { 6119250003Sadrian // Make sure this scheme is only used for WB225(Astra) 6120250003Sadrian ahp->ah_lna_div_use_bt_ant_enable = enable; 6121250003Sadrian 6122250003Sadrian ichan = ar9300_check_chan(ah, chan); 6123250003Sadrian if ( ichan == AH_NULL ) { 6124250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n", 6125250008Sadrian __func__, chan->ic_freq, chan->ic_flags); 6126250003Sadrian return AH_FALSE; 6127250003Sadrian } 6128250003Sadrian 6129250003Sadrian if ( enable == TRUE ) { 6130250008Sadrian pcap->halAntDivCombSupport = TRUE; 6131250003Sadrian } else { 6132250008Sadrian pcap->halAntDivCombSupport = pcap->halAntDivCombSupportOrg; 6133250003Sadrian } 6134250003Sadrian 6135250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) 6136250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL_S (0) 6137250003Sadrian value = ar9300_ant_ctrl_common2_get(ah, IS_CHAN_2GHZ(ichan)); 6138250003Sadrian if ( enable == TRUE ) { 6139250003Sadrian value &= ~AR_SWITCH_TABLE_COM2_ALL; 6140250008Sadrian value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable; 6141250003Sadrian } 6142250003Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); 6143250003Sadrian 6144250003Sadrian value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control); 6145250003Sadrian /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 6146250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 6147250003Sadrian regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */ 6148250003Sadrian regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S; 6149250003Sadrian /* enable_lnadiv */ 6150250003Sadrian regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK); 6151250003Sadrian regval |= ((value >> 6) & 0x1) << 6152250003Sadrian MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT; 6153250003Sadrian if ( enable == TRUE ) { 6154250003Sadrian regval |= ANT_DIV_ENABLE; 6155250003Sadrian } 6156250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 6157250003Sadrian 6158250003Sadrian /* enable fast_div */ 6159250003Sadrian regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 6160250003Sadrian regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); 6161250003Sadrian regval |= ((value >> 7) & 0x1) << 6162250003Sadrian BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT; 6163250003Sadrian if ( enable == TRUE ) { 6164250003Sadrian regval |= FAST_DIV_ENABLE; 6165250003Sadrian } 6166250003Sadrian OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); 6167250003Sadrian 6168250003Sadrian if ( AR_SREV_POSEIDON_11_OR_LATER(ah) ) { 6169250008Sadrian if (pcap->halAntDivCombSupport) { 6170250003Sadrian /* If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning */ 6171250003Sadrian regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); 6172250003Sadrian /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */ 6173250003Sadrian regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | 6174250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | 6175250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK | 6176250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK)); 6177250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA1 << 6178250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); 6179250003Sadrian regval |= (HAL_ANT_DIV_COMB_LNA2 << 6180250003Sadrian MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); 6181250003Sadrian OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); 6182250003Sadrian } 6183250003Sadrian } 6184250003Sadrian 6185250003Sadrian return AH_TRUE; 6186250003Sadrian } else { 6187250003Sadrian return AH_TRUE; 6188250003Sadrian } 6189250003Sadrian} 6190250003Sadrian#endif /* ATH_ANT_DIV_COMB */ 6191