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