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;
291291437Sadrian    } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(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);
1479291437Sadrian    } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(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
1495291437Sadrian            if (AR_SREV_HONEYBEE(ah)) {
1496291437Sadrian                pll2_divint = 0x1c;
1497291437Sadrian                pll2_divfrac = 0xa3d2;
1498291437Sadrian                refdiv = 1;
1499291437Sadrian            } else {
1500291437Sadrian                pll2_divint = 0x54;
1501291437Sadrian                pll2_divfrac = 0x1eb85;
1502291437Sadrian                refdiv = 3;
1503291437Sadrian            }
1504250003Sadrian#endif
1505250003Sadrian        } else {
1506250003Sadrian#ifndef SRIF_PLL
1507250003Sadrian            pll2_divint = 0x11;
1508250003Sadrian            pll2_divfrac = 0x26666;
1509250003Sadrian#else
1510250003Sadrian            if (AR_SREV_WASP(ah)) {
1511250003Sadrian                pll2_divint = 88;
1512250003Sadrian                pll2_divfrac = 0;
1513250003Sadrian                refdiv = 5;
1514250003Sadrian            } else {
1515250003Sadrian                pll2_divint = 0x11;
1516250003Sadrian                pll2_divfrac = 0x26666;
1517250003Sadrian                refdiv = 1;
1518250003Sadrian            }
1519250003Sadrian#endif
1520250003Sadrian        }
1521250003Sadrian#ifndef SRIF_PLL
1522250003Sadrian        pll2_clkmode = 0x3d;
1523250003Sadrian#endif
1524250003Sadrian        /* PLL programming through SRIF Local Mode */
1525250003Sadrian        OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); /* Bypass mode */
1526250003Sadrian        OS_DELAY(1000);
1527250003Sadrian        do {
1528250003Sadrian            regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);
1529291437Sadrian            if (AR_SREV_HONEYBEE(ah)) {
1530291437Sadrian                regdata = regdata | (0x1 << 22);
1531291437Sadrian            } else {
1532291437Sadrian                regdata = regdata | (0x1 << 16);
1533291437Sadrian            }
1534250003Sadrian            OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 1 */
1535250003Sadrian            OS_DELAY(100);
1536250003Sadrian            /* override int, frac, refdiv */
1537250003Sadrian#ifndef SRIF_PLL
1538250003Sadrian            OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL,
1539250003Sadrian                ((1 << 27) | (pll2_divint << 18) | pll2_divfrac));
1540250003Sadrian#else
1541250003Sadrian            OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL,
1542250003Sadrian                ((refdiv << 27) | (pll2_divint << 18) | pll2_divfrac));
1543250003Sadrian#endif
1544250003Sadrian            OS_DELAY(100);
1545250003Sadrian            regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);
1546250003Sadrian#ifndef SRIF_PLL
1547250003Sadrian            regdata = (regdata & 0x80071fff) |
1548250003Sadrian                (0x1 << 30) | (0x1 << 13) | (0x6 << 26) | (pll2_clkmode << 19);
1549250003Sadrian#else
1550250003Sadrian            if (AR_SREV_WASP(ah)) {
1551250003Sadrian                regdata = (regdata & 0x80071fff) |
1552250003Sadrian                    (0x1 << 30) | (0x1 << 13) | (0x4 << 26) | (0x18 << 19);
1553291437Sadrian            } else if (AR_SREV_HONEYBEE(ah)) {
1554291437Sadrian                /*
1555291437Sadrian                 * Kd=10, Ki=2, Outdiv=1, Local PLL=0, Phase Shift=4
1556291437Sadrian                 */
1557291437Sadrian                regdata = (regdata & 0x01c00fff) |
1558291437Sadrian                    (0x1 << 31) | (0x2 << 29) | (0xa << 25) | (0x1 << 19) | (0x6 << 12);
1559250003Sadrian            } else {
1560250003Sadrian                regdata = (regdata & 0x80071fff) |
1561250003Sadrian                    (0x3 << 30) | (0x1 << 13) | (0x4 << 26) | (0x60 << 19);
1562250003Sadrian            }
1563250003Sadrian#endif
1564250003Sadrian            /* Ki, Kd, Local PLL, Outdiv */
1565250003Sadrian            OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata);
1566250003Sadrian            regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);
1567291437Sadrian            if (AR_SREV_HONEYBEE(ah)) {
1568291437Sadrian                regdata = (regdata & 0xffbfffff);
1569291437Sadrian            } else {
1570291437Sadrian                regdata = (regdata & 0xfffeffff);
1571291437Sadrian            }
1572250003Sadrian            OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 0 */
1573250003Sadrian            OS_DELAY(1000);
1574250003Sadrian            if (AR_SREV_WASP(ah)) {
1575250003Sadrian                /* clear do measure */
1576250003Sadrian                regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);
1577250003Sadrian                regdata &= ~(1 << 30);
1578250003Sadrian                OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);
1579250003Sadrian                OS_DELAY(100);
1580250003Sadrian
1581250003Sadrian                /* set do measure */
1582250003Sadrian                regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);
1583250003Sadrian                regdata |= (1 << 30);
1584250003Sadrian                OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);
1585250003Sadrian
1586250003Sadrian                /* wait for measure done */
1587250003Sadrian                do {
1588250003Sadrian                    regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL4);
1589250003Sadrian                } while ((regdata & (1 << 3)) == 0);
1590250003Sadrian
1591250003Sadrian                /* clear do measure */
1592250003Sadrian                regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);
1593250003Sadrian                regdata &= ~(1 << 30);
1594250003Sadrian                OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);
1595250003Sadrian
1596250003Sadrian                /* get measure sqsum dvc */
1597250003Sadrian                regdata = (OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3) & 0x007FFFF8) >> 3;
1598250003Sadrian            } else {
1599250003Sadrian                break;
1600250003Sadrian            }
1601250003Sadrian        } while (regdata >= 0x40000);
1602250003Sadrian
1603250003Sadrian        /* Remove from Bypass mode */
1604250003Sadrian        OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
1605250003Sadrian        OS_DELAY(1000);
1606250003Sadrian    } else {
1607250003Sadrian        pll = SM(0x5, AR_RTC_PLL_REFDIV);
1608250003Sadrian
1609250003Sadrian        /* Supposedly not needed on Osprey */
1610250003Sadrian#if 0
1611250003Sadrian        if (chan && IS_CHAN_HALF_RATE(chan)) {
1612250003Sadrian            pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
1613250003Sadrian        } else if (chan && IS_CHAN_QUARTER_RATE(chan)) {
1614250003Sadrian            pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
1615250003Sadrian        }
1616250003Sadrian#endif
1617250008Sadrian        if (ichan && IS_CHAN_5GHZ(ichan)) {
1618250003Sadrian            pll |= SM(0x28, AR_RTC_PLL_DIV);
1619250003Sadrian            /*
1620250003Sadrian             * When doing fast clock, set PLL to 0x142c
1621250003Sadrian             */
1622250003Sadrian            if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {
1623250003Sadrian                pll = 0x142c;
1624250003Sadrian            }
1625250003Sadrian        } else {
1626250003Sadrian            pll |= SM(0x2c, AR_RTC_PLL_DIV);
1627250003Sadrian        }
1628250003Sadrian
1629250003Sadrian        OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
1630250003Sadrian    }
1631250003Sadrian
1632250003Sadrian    /* TODO:
1633250003Sadrian     * For multi-band owl, switch between bands by reiniting the PLL.
1634250003Sadrian     */
1635250003Sadrian    OS_DELAY(RTC_PLL_SETTLE_DELAY);
1636250003Sadrian
1637250003Sadrian    OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK,
1638250003Sadrian        AR_RTC_FORCE_DERIVED_CLK | AR_RTC_PCIE_RST_PWDN_EN);
1639250003Sadrian
1640291437Sadrian    /* XXX TODO: honeybee? */
1641250003Sadrian    if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {
1642250003Sadrian        if (clk_25mhz) {
1643250003Sadrian            OS_REG_WRITE(ah,
1644250003Sadrian                AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); /* 32KHz sleep clk */
1645250003Sadrian            OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
1646250003Sadrian            OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);
1647250003Sadrian        } else {
1648250003Sadrian            OS_REG_WRITE(ah,
1649250003Sadrian                AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); /* 32KHz sleep clk */
1650250003Sadrian            OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
1651250003Sadrian            OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);
1652250003Sadrian        }
1653250003Sadrian        OS_DELAY(100);
1654250003Sadrian    }
1655250003Sadrian}
1656250003Sadrian
1657250003Sadrianstatic inline HAL_BOOL
1658250003Sadrianar9300_set_reset(struct ath_hal *ah, int type)
1659250003Sadrian{
1660250003Sadrian    u_int32_t rst_flags;
1661250003Sadrian    u_int32_t tmp_reg;
1662278741Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
1663250003Sadrian
1664250003Sadrian    HALASSERT(type == HAL_RESET_WARM || type == HAL_RESET_COLD);
1665250003Sadrian
1666250003Sadrian    /*
1667250003Sadrian     * RTC Force wake should be done before resetting the MAC.
1668250003Sadrian     * MDK/ART does it that way.
1669250003Sadrian     */
1670250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);
1671250003Sadrian    OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */
1672250003Sadrian    OS_REG_WRITE(ah,
1673250003Sadrian        AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
1674250003Sadrian
1675250003Sadrian    /* Reset AHB */
1676250003Sadrian    /* Bug26871 */
1677250003Sadrian    tmp_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE));
1678250003Sadrian    if (AR_SREV_WASP(ah)) {
1679250003Sadrian        if (tmp_reg & (AR9340_INTR_SYNC_LOCAL_TIMEOUT)) {
1680250003Sadrian            OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0);
1681250003Sadrian            OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF);
1682250003Sadrian        }
1683250003Sadrian    } else {
1684250003Sadrian        if (tmp_reg & (AR9300_INTR_SYNC_LOCAL_TIMEOUT | AR9300_INTR_SYNC_RADM_CPL_TIMEOUT)) {
1685250003Sadrian            OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0);
1686250003Sadrian            OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF);
1687250003Sadrian        }
1688250003Sadrian        else {
1689250003Sadrian            /* NO AR_RC_AHB in Osprey */
1690250003Sadrian            /*OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_AHB);*/
1691250003Sadrian        }
1692250003Sadrian    }
1693250003Sadrian
1694250003Sadrian    rst_flags = AR_RTC_RC_MAC_WARM;
1695250003Sadrian    if (type == HAL_RESET_COLD) {
1696250003Sadrian        rst_flags |= AR_RTC_RC_MAC_COLD;
1697250003Sadrian    }
1698250003Sadrian
1699250003Sadrian#ifdef AH_SUPPORT_HORNET
1700250003Sadrian    /* Hornet WAR: trigger SoC to reset WMAC if ...
1701250003Sadrian     * (1) doing cold reset. Ref: EV 69254
1702250003Sadrian     * (2) beacon pending. Ref: EV 70983
1703250003Sadrian     */
1704250003Sadrian    if (AR_SREV_HORNET(ah) &&
1705250003Sadrian        (ar9300_num_tx_pending(
1706250008Sadrian            ah, AH_PRIVATE(ah)->ah_caps.halTotalQueues - 1) != 0 ||
1707250003Sadrian         type == HAL_RESET_COLD))
1708250003Sadrian    {
1709250003Sadrian        u_int32_t time_out;
1710250003Sadrian#define AR_SOC_RST_RESET         0xB806001C
1711250003Sadrian#define AR_SOC_BOOT_STRAP        0xB80600AC
1712250003Sadrian#define AR_SOC_WLAN_RST          0x00000800 /* WLAN reset */
1713250003Sadrian#define REG_WRITE(_reg, _val)    *((volatile u_int32_t *)(_reg)) = (_val);
1714250003Sadrian#define REG_READ(_reg)           *((volatile u_int32_t *)(_reg))
1715250003Sadrian        HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Hornet SoC reset WMAC.\n", __func__);
1716250003Sadrian
1717250003Sadrian        REG_WRITE(AR_SOC_RST_RESET,
1718250003Sadrian            REG_READ(AR_SOC_RST_RESET) | AR_SOC_WLAN_RST);
1719250003Sadrian        REG_WRITE(AR_SOC_RST_RESET,
1720250003Sadrian            REG_READ(AR_SOC_RST_RESET) & (~AR_SOC_WLAN_RST));
1721250003Sadrian
1722250003Sadrian        time_out = 0;
1723250003Sadrian
1724250003Sadrian        while (1) {
1725250003Sadrian            tmp_reg = REG_READ(AR_SOC_BOOT_STRAP);
1726250003Sadrian            if ((tmp_reg & 0x10) == 0) {
1727250003Sadrian                break;
1728250003Sadrian            }
1729250003Sadrian            if (time_out > 20) {
1730250003Sadrian                break;
1731250003Sadrian            }
1732250003Sadrian            OS_DELAY(10000);
1733250003Sadrian            time_out++;
1734250003Sadrian        }
1735250003Sadrian
1736250003Sadrian        OS_REG_WRITE(ah, AR_RTC_RESET, 1);
1737250003Sadrian#undef REG_READ
1738250003Sadrian#undef REG_WRITE
1739250003Sadrian#undef AR_SOC_WLAN_RST
1740250003Sadrian#undef AR_SOC_RST_RESET
1741250003Sadrian#undef AR_SOC_BOOT_STRAP
1742250003Sadrian    }
1743250003Sadrian#endif /* AH_SUPPORT_HORNET */
1744250003Sadrian
1745250003Sadrian#ifdef AH_SUPPORT_SCORPION
1746250003Sadrian    if (AR_SREV_SCORPION(ah)) {
1747250003Sadrian#define DDR_CTL_CONFIG_ADDRESS                                       0xb8000000
1748250003Sadrian#define DDR_CTL_CONFIG_OFFSET                                        0x0108
1749250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MSB                           29
1750250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB                           21
1751250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK                          0x3fe00000
1752250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(x)                        (((x) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) >> DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB)
1753250003Sadrian#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_SET(x)                        (((x) << DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK)
1754250003Sadrian#define MAC_DMA_CFG_ADDRESS                                          0xb8100000
1755250003Sadrian#define MAC_DMA_CFG_OFFSET                                           0x0014
1756250003Sadrian
1757250003Sadrian#define MAC_DMA_CFG_HALT_REQ_MSB                                     11
1758250003Sadrian#define MAC_DMA_CFG_HALT_REQ_LSB                                     11
1759250003Sadrian#define MAC_DMA_CFG_HALT_REQ_MASK                                    0x00000800
1760250003Sadrian#define MAC_DMA_CFG_HALT_REQ_GET(x)                                  (((x) & MAC_DMA_CFG_HALT_REQ_MASK) >> MAC_DMA_CFG_HALT_REQ_LSB)
1761250003Sadrian#define MAC_DMA_CFG_HALT_REQ_SET(x)                                  (((x) << MAC_DMA_CFG_HALT_REQ_LSB) & MAC_DMA_CFG_HALT_REQ_MASK)
1762250003Sadrian#define MAC_DMA_CFG_HALT_ACK_MSB                                     12
1763250003Sadrian#define MAC_DMA_CFG_HALT_ACK_LSB                                     12
1764250003Sadrian#define MAC_DMA_CFG_HALT_ACK_MASK                                    0x00001000
1765250003Sadrian#define MAC_DMA_CFG_HALT_ACK_GET(x)                                  (((x) & MAC_DMA_CFG_HALT_ACK_MASK) >> MAC_DMA_CFG_HALT_ACK_LSB)
1766250003Sadrian#define MAC_DMA_CFG_HALT_ACK_SET(x)                                  (((x) << MAC_DMA_CFG_HALT_ACK_LSB) & MAC_DMA_CFG_HALT_ACK_MASK)
1767250003Sadrian
1768250003Sadrian#define RST_RESET                                                    0xB806001c
1769250003Sadrian#define RTC_RESET                                                    (1<<27)
1770250003Sadrian
1771250003Sadrian#define REG_READ(_reg)          *((volatile u_int32_t *)(_reg))
1772250003Sadrian#define REG_WRITE(_reg, _val)   *((volatile u_int32_t *)(_reg)) = (_val);
1773250003Sadrian
1774250003Sadrian#define DDR_REG_READ(_ah, _reg) \
1775250003Sadrian	    *((volatile u_int32_t *)( DDR_CTL_CONFIG_ADDRESS + (_reg)))
1776250003Sadrian#define DDR_REG_WRITE(_ah, _reg, _val) \
1777250003Sadrian	    *((volatile u_int32_t *)(DDR_CTL_CONFIG_ADDRESS + (_reg))) = (_val)
1778250003Sadrian
1779250003Sadrian	    OS_REG_WRITE(ah,MAC_DMA_CFG_OFFSET, (OS_REG_READ(ah,MAC_DMA_CFG_OFFSET) & ~MAC_DMA_CFG_HALT_REQ_MASK) |
1780250003Sadrian			    MAC_DMA_CFG_HALT_REQ_SET(1));
1781250003Sadrian
1782250003Sadrian	    {
1783250003Sadrian		    int count;
1784250003Sadrian            u_int32_t data;
1785250003Sadrian
1786250003Sadrian		    count = 0;
1787250003Sadrian		    while (!MAC_DMA_CFG_HALT_ACK_GET(OS_REG_READ(ah, MAC_DMA_CFG_OFFSET) ))
1788250003Sadrian		    {
1789250003Sadrian			    count++;
1790250003Sadrian			    if (count > 10) {
1791250003Sadrian				    ath_hal_printf(ah, "Halt ACK timeout\n");
1792250003Sadrian				    break;
1793250003Sadrian			    }
1794250003Sadrian			    OS_DELAY(10);
1795250003Sadrian		    }
1796250003Sadrian
1797250003Sadrian		    data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET);
1798285123Sadrian		    HALDEBUG(ah, HAL_DEBUG_RESET, "check DDR Activity - HIGH\n");
1799250003Sadrian
1800250003Sadrian		    count = 0;
1801250003Sadrian		    while (DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(data)) {
1802250003Sadrian			    //      AVE_DEBUG(0,"DDR Activity - HIGH\n");
1803285123Sadrian			    HALDEBUG(ah, HAL_DEBUG_RESET, "DDR Activity - HIGH\n");
1804250003Sadrian			    count++;
1805250003Sadrian			    OS_DELAY(10);
1806250003Sadrian			    data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET);
1807250003Sadrian			    if (count > 10) {
1808250003Sadrian				    ath_hal_printf(ah, "DDR Activity timeout\n");
1809250003Sadrian				    break;
1810250003Sadrian			    }
1811250003Sadrian		    }
1812250003Sadrian	    }
1813250003Sadrian
1814250003Sadrian
1815250003Sadrian	    {
1816250003Sadrian		    //Force RTC reset
1817250003Sadrian		    REG_WRITE(RST_RESET, (REG_READ(RST_RESET) | RTC_RESET));
1818250003Sadrian		    OS_DELAY(10);
1819250003Sadrian		    REG_WRITE(RST_RESET, (REG_READ(RST_RESET) & ~RTC_RESET));
1820250003Sadrian		    OS_DELAY(10);
1821250003Sadrian		    OS_REG_WRITE(ah, AR_RTC_RESET, 0);
1822250003Sadrian		    OS_DELAY(10);
1823250003Sadrian		    OS_REG_WRITE(ah, AR_RTC_RESET, 1);
1824250003Sadrian		    OS_DELAY(10);
1825285123Sadrian		    HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Scorpion SoC RTC reset done.\n", __func__);
1826250003Sadrian	    }
1827250003Sadrian#undef REG_READ
1828250003Sadrian#undef REG_WRITE
1829250003Sadrian    }
1830250003Sadrian#endif  /* AH_SUPPORT_SCORPION */
1831250003Sadrian
1832250003Sadrian    /*
1833250003Sadrian     * Set Mac(BB,Phy) Warm Reset
1834250003Sadrian     */
1835250003Sadrian    OS_REG_WRITE(ah, AR_RTC_RC, rst_flags);
1836250003Sadrian
1837250003Sadrian    OS_DELAY(50); /* XXX 50 usec */
1838250003Sadrian
1839250003Sadrian    /*
1840250003Sadrian     * Clear resets and force wakeup
1841250003Sadrian     */
1842250003Sadrian    OS_REG_WRITE(ah, AR_RTC_RC, 0);
1843250008Sadrian    if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) {
1844250003Sadrian        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
1845250003Sadrian            "%s: RTC stuck in MAC reset\n", __FUNCTION__);
1846250003Sadrian        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
1847250003Sadrian            "%s: AR_RTC_RC = 0x%x\n", __func__, OS_REG_READ(ah, AR_RTC_RC));
1848250003Sadrian        return AH_FALSE;
1849250003Sadrian    }
1850250003Sadrian
1851250003Sadrian    /* Clear AHB reset */
1852250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0);
1853250003Sadrian
1854250003Sadrian    ar9300_attach_hw_platform(ah);
1855250003Sadrian
1856278741Sadrian    ahp->ah_chip_reset_done = 1;
1857250003Sadrian    return AH_TRUE;
1858250003Sadrian}
1859250003Sadrian
1860250003Sadrianstatic inline HAL_BOOL
1861250003Sadrianar9300_set_reset_power_on(struct ath_hal *ah)
1862250003Sadrian{
1863250003Sadrian    /* Force wake */
1864250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);
1865250003Sadrian    OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */
1866250003Sadrian    OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,
1867250003Sadrian        AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
1868250003Sadrian    /*
1869250003Sadrian     * RTC reset and clear. Some delay in between is needed
1870250003Sadrian     * to give the chip time to settle.
1871250003Sadrian     */
1872250003Sadrian    OS_REG_WRITE(ah, AR_RTC_RESET, 0);
1873250003Sadrian    OS_DELAY(2);
1874250003Sadrian    OS_REG_WRITE(ah, AR_RTC_RESET, 1);
1875250003Sadrian
1876250003Sadrian    /*
1877250003Sadrian     * Poll till RTC is ON
1878250003Sadrian     */
1879250003Sadrian    if (!ath_hal_wait(ah,
1880250003Sadrian             AR_RTC_STATUS, AR_RTC_STATUS_M,
1881250008Sadrian             AR_RTC_STATUS_ON))
1882250003Sadrian    {
1883250003Sadrian        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
1884250008Sadrian            "%s: RTC not waking up for %d\n", __FUNCTION__, 1000);
1885250003Sadrian        return AH_FALSE;
1886250003Sadrian    }
1887250003Sadrian
1888250003Sadrian    /*
1889250003Sadrian     * Read Revisions from Chip right after RTC is on for the first time.
1890250003Sadrian     * This helps us detect the chip type early and initialize it accordingly.
1891250003Sadrian     */
1892250003Sadrian    ar9300_read_revisions(ah);
1893250003Sadrian
1894250003Sadrian    /*
1895250003Sadrian     * Warm reset if we aren't really powering on,
1896250003Sadrian     * just restarting the driver.
1897250003Sadrian     */
1898250003Sadrian    return ar9300_set_reset(ah, HAL_RESET_WARM);
1899250003Sadrian}
1900250003Sadrian
1901250003Sadrian/*
1902250003Sadrian * Write the given reset bit mask into the reset register
1903250003Sadrian */
1904250003SadrianHAL_BOOL
1905250003Sadrianar9300_set_reset_reg(struct ath_hal *ah, u_int32_t type)
1906250003Sadrian{
1907250003Sadrian    HAL_BOOL ret = AH_FALSE;
1908250003Sadrian
1909250003Sadrian    /*
1910250003Sadrian     * Set force wake
1911250003Sadrian     */
1912250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);
1913250003Sadrian    OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */
1914250003Sadrian    OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,
1915250003Sadrian        AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
1916250003Sadrian
1917250003Sadrian    switch (type) {
1918250003Sadrian    case HAL_RESET_POWER_ON:
1919250003Sadrian        ret = ar9300_set_reset_power_on(ah);
1920250003Sadrian        break;
1921250003Sadrian    case HAL_RESET_WARM:
1922250003Sadrian    case HAL_RESET_COLD:
1923250003Sadrian        ret = ar9300_set_reset(ah, type);
1924250003Sadrian        break;
1925250003Sadrian    default:
1926250003Sadrian        break;
1927250003Sadrian    }
1928250003Sadrian
1929250003Sadrian#if ATH_SUPPORT_MCI
1930250008Sadrian    if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {
1931250003Sadrian        OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
1932250003Sadrian    }
1933250003Sadrian#endif
1934250003Sadrian
1935250003Sadrian    return ret;
1936250003Sadrian}
1937250003Sadrian
1938250003Sadrian/*
1939250003Sadrian * Places the PHY and Radio chips into reset.  A full reset
1940250003Sadrian * must be called to leave this state.  The PCI/MAC/PCU are
1941250003Sadrian * not placed into reset as we must receive interrupt to
1942250003Sadrian * re-enable the hardware.
1943250003Sadrian */
1944250003SadrianHAL_BOOL
1945250003Sadrianar9300_phy_disable(struct ath_hal *ah)
1946250003Sadrian{
1947250003Sadrian    if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) {
1948250003Sadrian        return AH_FALSE;
1949250003Sadrian    }
1950250003Sadrian
1951250003Sadrian#ifdef ATH_SUPPORT_LED
1952250003Sadrian#define REG_READ(_reg)          *((volatile u_int32_t *)(_reg))
1953250003Sadrian#define REG_WRITE(_reg, _val)   *((volatile u_int32_t *)(_reg)) = (_val);
1954250003Sadrian#define ATH_GPIO_OE             0xB8040000
1955250003Sadrian#define ATH_GPIO_OUT            0xB8040008 /* GPIO Ouput Value reg.*/
1956250003Sadrian    if (AR_SREV_WASP(ah)) {
1957250003Sadrian        if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {
1958250003Sadrian            REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13)));
1959250003Sadrian        }
1960250003Sadrian        else {
1961250003Sadrian            REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));
1962250003Sadrian        }
1963250003Sadrian    }
1964250003Sadrian    else if (AR_SREV_SCORPION(ah)) {
1965250003Sadrian        if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {
1966250003Sadrian            REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13)));
1967250003Sadrian        }
1968250003Sadrian        else {
1969250003Sadrian            REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));
1970250003Sadrian        }
1971250003Sadrian        /* Turn off JMPST led */
1972250003Sadrian        REG_WRITE(ATH_GPIO_OUT, (REG_READ(ATH_GPIO_OUT) | (0x1 << 15)));
1973250003Sadrian    }
1974291437Sadrian    else if (AR_SREV_HONEYBEE(ah)) {
1975291437Sadrian        REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));
1976291437Sadrian    }
1977250003Sadrian#undef REG_READ
1978250003Sadrian#undef REG_WRITE
1979250003Sadrian#endif
1980250003Sadrian
1981250003Sadrian    if ( AR_SREV_OSPREY(ah) ) {
1982250003Sadrian        OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1), 0x0, 0x1f);
1983250003Sadrian    }
1984250003Sadrian
1985250003Sadrian
1986250003Sadrian    ar9300_init_pll(ah, AH_NULL);
1987250003Sadrian
1988250003Sadrian    return AH_TRUE;
1989250003Sadrian}
1990250003Sadrian
1991250003Sadrian/*
1992250003Sadrian * Places all of hardware into reset
1993250003Sadrian */
1994250003SadrianHAL_BOOL
1995250003Sadrianar9300_disable(struct ath_hal *ah)
1996250003Sadrian{
1997250003Sadrian    if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {
1998250003Sadrian        return AH_FALSE;
1999250003Sadrian    }
2000250003Sadrian    if (!ar9300_set_reset_reg(ah, HAL_RESET_COLD)) {
2001250003Sadrian        return AH_FALSE;
2002250003Sadrian    }
2003250003Sadrian
2004250003Sadrian    ar9300_init_pll(ah, AH_NULL);
2005250003Sadrian
2006250003Sadrian    return AH_TRUE;
2007250003Sadrian}
2008250003Sadrian
2009250003Sadrian/*
2010250003Sadrian * TODO: Only write the PLL if we're changing to or from CCK mode
2011250003Sadrian *
2012250003Sadrian * WARNING: The order of the PLL and mode registers must be correct.
2013250003Sadrian */
2014250003Sadrianstatic inline void
2015250008Sadrianar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan)
2016250003Sadrian{
2017250003Sadrian    u_int32_t rf_mode = 0;
2018250003Sadrian
2019250003Sadrian    if (chan == AH_NULL) {
2020250003Sadrian        return;
2021250003Sadrian    }
2022250003Sadrian    switch (AH9300(ah)->ah_hwp) {
2023250003Sadrian    case HAL_TRUE_CHIP:
2024250008Sadrian        rf_mode |= (IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_G(chan)) ?
2025250003Sadrian            AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
2026250003Sadrian        break;
2027250003Sadrian    default:
2028250003Sadrian        HALASSERT(0);
2029250003Sadrian        break;
2030250003Sadrian    }
2031250003Sadrian    /*  Phy mode bits for 5GHz channels requiring Fast Clock */
2032250003Sadrian    if ( IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {
2033250003Sadrian        rf_mode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
2034250003Sadrian    }
2035250003Sadrian    OS_REG_WRITE(ah, AR_PHY_MODE, rf_mode);
2036250003Sadrian}
2037250003Sadrian
2038250003Sadrian/*
2039250003Sadrian * Places the hardware into reset and then pulls it out of reset
2040250003Sadrian */
2041250003SadrianHAL_BOOL
2042250008Sadrianar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan)
2043250003Sadrian{
2044250003Sadrian    struct ath_hal_9300     *ahp = AH9300(ah);
2045269748Sadrian    int type = HAL_RESET_WARM;
2046250003Sadrian
2047250008Sadrian    OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);
2048250008Sadrian
2049250003Sadrian    /*
2050250003Sadrian     * Warm reset is optimistic.
2051269748Sadrian     *
2052269748Sadrian     * If the TX/RX DMA engines aren't shut down (eg, they're
2053269748Sadrian     * wedged) then we're better off doing a full cold reset
2054269748Sadrian     * to try and shake that condition.
2055250003Sadrian     */
2056269748Sadrian    if (ahp->ah_chip_full_sleep ||
2057269748Sadrian        (ah->ah_config.ah_force_full_reset == 1) ||
2058269748Sadrian        OS_REG_READ(ah, AR_Q_TXE) ||
2059269748Sadrian        (OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) {
2060269748Sadrian            type = HAL_RESET_COLD;
2061269748Sadrian    }
2062269748Sadrian
2063269748Sadrian    if (!ar9300_set_reset_reg(ah, type)) {
2064250003Sadrian        return AH_FALSE;
2065250003Sadrian    }
2066250003Sadrian
2067250003Sadrian    /* Bring out of sleep mode (AGAIN) */
2068250003Sadrian    if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {
2069250003Sadrian        return AH_FALSE;
2070250003Sadrian    }
2071250003Sadrian
2072250003Sadrian    ahp->ah_chip_full_sleep = AH_FALSE;
2073250003Sadrian
2074250003Sadrian    if (AR_SREV_HORNET(ah)) {
2075250003Sadrian        ar9300_internal_regulator_apply(ah);
2076250003Sadrian    }
2077250003Sadrian
2078250003Sadrian    ar9300_init_pll(ah, chan);
2079250003Sadrian
2080250003Sadrian    /*
2081250003Sadrian     * Perform warm reset before the mode/PLL/turbo registers
2082250003Sadrian     * are changed in order to deactivate the radio.  Mode changes
2083250003Sadrian     * with an active radio can result in corrupted shifts to the
2084250003Sadrian     * radio device.
2085250003Sadrian     */
2086250003Sadrian    ar9300_set_rf_mode(ah, chan);
2087250003Sadrian
2088250003Sadrian    return AH_TRUE;
2089250003Sadrian}
2090250003Sadrian
2091250003Sadrian/* ar9300_setup_calibration
2092250003Sadrian * Setup HW to collect samples used for current cal
2093250003Sadrian */
2094250003Sadrianinline static void
2095250003Sadrianar9300_setup_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal)
2096250003Sadrian{
2097250003Sadrian    /* Select calibration to run */
2098250003Sadrian    switch (curr_cal->cal_data->cal_type) {
2099250003Sadrian    case IQ_MISMATCH_CAL:
2100250003Sadrian        /* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */
2101250003Sadrian        OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4,
2102250003Sadrian            AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
2103250003Sadrian            curr_cal->cal_data->cal_count_max);
2104250003Sadrian        OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
2105250003Sadrian
2106250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2107250003Sadrian            "%s: starting IQ Mismatch Calibration\n", __func__);
2108250003Sadrian
2109250003Sadrian        /* Kick-off cal */
2110250003Sadrian        OS_REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
2111250003Sadrian
2112250003Sadrian        break;
2113250003Sadrian    case TEMP_COMP_CAL:
2114250003Sadrian        if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) ||
2115250003Sadrian            AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {
2116250003Sadrian            OS_REG_RMW_FIELD(ah,
2117250003Sadrian                AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1);
2118250003Sadrian            OS_REG_RMW_FIELD(ah,
2119250003Sadrian                AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1);
2120250003Sadrian        } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
2121250003Sadrian            OS_REG_RMW_FIELD(ah,
2122250003Sadrian                AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_LOCAL, 1);
2123250003Sadrian            OS_REG_RMW_FIELD(ah,
2124250003Sadrian                AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_START, 1);
2125250003Sadrian        } else {
2126250003Sadrian            OS_REG_RMW_FIELD(ah,
2127250003Sadrian                AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1);
2128250003Sadrian            OS_REG_RMW_FIELD(ah,
2129250003Sadrian                AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1);
2130250003Sadrian        }
2131250003Sadrian
2132250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2133250003Sadrian            "%s: starting Temperature Compensation Calibration\n", __func__);
2134250003Sadrian        break;
2135250003Sadrian    default:
2136250003Sadrian        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
2137250003Sadrian            "%s called with incorrect calibration type.\n", __func__);
2138250003Sadrian    }
2139250003Sadrian}
2140250003Sadrian
2141250003Sadrian/* ar9300_reset_calibration
2142250003Sadrian * Initialize shared data structures and prepare a cal to be run.
2143250003Sadrian */
2144250003Sadrianinline static void
2145250003Sadrianar9300_reset_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal)
2146250003Sadrian{
2147250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2148250003Sadrian    int i;
2149250003Sadrian
2150250003Sadrian    /* Setup HW for new calibration */
2151250003Sadrian    ar9300_setup_calibration(ah, curr_cal);
2152250003Sadrian
2153250003Sadrian    /* Change SW state to RUNNING for this calibration */
2154250003Sadrian    curr_cal->cal_state = CAL_RUNNING;
2155250003Sadrian
2156250003Sadrian    /* Reset data structures shared between different calibrations */
2157250003Sadrian    for (i = 0; i < AR9300_MAX_CHAINS; i++) {
2158250003Sadrian        ahp->ah_meas0.sign[i] = 0;
2159250003Sadrian        ahp->ah_meas1.sign[i] = 0;
2160250003Sadrian        ahp->ah_meas2.sign[i] = 0;
2161250003Sadrian        ahp->ah_meas3.sign[i] = 0;
2162250003Sadrian    }
2163250003Sadrian
2164250003Sadrian    ahp->ah_cal_samples = 0;
2165250003Sadrian}
2166250003Sadrian
2167250003Sadrian#ifdef XXX_UNUSED_FUNCTION
2168250003Sadrian/*
2169250003Sadrian * Find out which of the RX chains are enabled
2170250003Sadrian */
2171250003Sadrianstatic u_int32_t
2172250003Sadrianar9300_get_rx_chain_mask(struct ath_hal *ah)
2173250003Sadrian{
2174250003Sadrian    u_int32_t ret_val = OS_REG_READ(ah, AR_PHY_RX_CHAINMASK);
2175250003Sadrian    /* The bits [2:0] indicate the rx chain mask and are to be
2176250003Sadrian     * interpreted as follows:
2177250003Sadrian     * 00x => Only chain 0 is enabled
2178250003Sadrian     * 01x => Chain 1 and 0 enabled
2179250003Sadrian     * 1xx => Chain 2,1 and 0 enabled
2180250003Sadrian     */
2181250003Sadrian    return (ret_val & 0x7);
2182250003Sadrian}
2183250003Sadrian#endif
2184250003Sadrian
2185250003Sadrianstatic void
2186250003Sadrianar9300_get_nf_hist_base(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan,
2187250003Sadrian    int is_scan, int16_t nf[])
2188250003Sadrian{
2189250003Sadrian    HAL_NFCAL_BASE *h_base;
2190250003Sadrian
2191250003Sadrian#ifdef ATH_NF_PER_CHAN
2192250003Sadrian    h_base = &chan->nf_cal_hist.base;
2193250003Sadrian#else
2194250003Sadrian    if (is_scan) {
2195250003Sadrian        /*
2196250003Sadrian         * The channel we are currently on is not the home channel,
2197250003Sadrian         * so we shouldn't use the home channel NF buffer's values on
2198250003Sadrian         * this channel.  Instead, use the NF single value already
2199250003Sadrian         * read for this channel.  (Or, if we haven't read the NF for
2200250003Sadrian         * this channel yet, the SW default for this chip/band will
2201250003Sadrian         * be used.)
2202250003Sadrian         */
2203250003Sadrian        h_base = &chan->nf_cal_hist.base;
2204250003Sadrian    } else {
2205250003Sadrian        /* use the home channel NF info */
2206250003Sadrian        h_base = &AH_PRIVATE(ah)->nf_cal_hist.base;
2207250003Sadrian    }
2208250003Sadrian#endif
2209250003Sadrian    OS_MEMCPY(nf, h_base->priv_nf, sizeof(h_base->priv_nf));
2210250003Sadrian}
2211250003Sadrian
2212250003SadrianHAL_BOOL
2213250003Sadrianar9300_load_nf(struct ath_hal *ah, int16_t nf[])
2214250003Sadrian{
2215250003Sadrian    int i, j;
2216250003Sadrian    int32_t val;
2217250003Sadrian    /* XXX where are EXT regs defined */
2218250003Sadrian    const u_int32_t ar9300_cca_regs[] = {
2219250003Sadrian        AR_PHY_CCA_0,
2220250003Sadrian        AR_PHY_CCA_1,
2221250003Sadrian        AR_PHY_CCA_2,
2222250003Sadrian        AR_PHY_EXT_CCA,
2223250003Sadrian        AR_PHY_EXT_CCA_1,
2224250003Sadrian        AR_PHY_EXT_CCA_2,
2225250003Sadrian    };
2226250003Sadrian    u_int8_t chainmask;
2227250003Sadrian
2228250003Sadrian    /*
2229250003Sadrian     * Force NF calibration for all chains, otherwise Vista station
2230250003Sadrian     * would conduct a bad performance
2231250003Sadrian     */
2232250003Sadrian    if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
2233250003Sadrian        chainmask = 0x9;
2234291437Sadrian    } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(ah)) {
2235250003Sadrian        chainmask = 0x1b;
2236250003Sadrian    } else {
2237250003Sadrian        chainmask = 0x3F;
2238250003Sadrian    }
2239250003Sadrian
2240250003Sadrian    /*
2241250003Sadrian     * Write filtered NF values into max_cca_pwr register parameter
2242250003Sadrian     * so we can load below.
2243250003Sadrian     */
2244250008Sadrian    for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
2245250003Sadrian        if (chainmask & (1 << i)) {
2246250003Sadrian            val = OS_REG_READ(ah, ar9300_cca_regs[i]);
2247250003Sadrian            val &= 0xFFFFFE00;
2248250003Sadrian            val |= (((u_int32_t)(nf[i]) << 1) & 0x1ff);
2249250003Sadrian            OS_REG_WRITE(ah, ar9300_cca_regs[i], val);
2250250003Sadrian        }
2251250003Sadrian    }
2252250003Sadrian
2253250008Sadrian    HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s: load %d %d %d %d %d %d\n",
2254250008Sadrian      __func__,
2255250008Sadrian      nf[0], nf[1], nf[2],
2256250008Sadrian      nf[3], nf[4], nf[5]);
2257250008Sadrian
2258250003Sadrian    /*
2259250003Sadrian     * Load software filtered NF value into baseband internal min_cca_pwr
2260250003Sadrian     * variable.
2261250003Sadrian     */
2262250003Sadrian    OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
2263250003Sadrian    OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
2264250003Sadrian    OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
2265250003Sadrian
2266250003Sadrian    /* Wait for load to complete, should be fast, a few 10s of us. */
2267250003Sadrian    /* Changed the max delay 250us back to 10000us, since 250us often
2268250003Sadrian     * results in NF load timeout and causes deaf condition
2269250003Sadrian     * during stress testing 12/12/2009
2270250003Sadrian     */
2271250003Sadrian    for (j = 0; j < 10000; j++) {
2272250003Sadrian        if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){
2273250003Sadrian            break;
2274250003Sadrian        }
2275250003Sadrian        OS_DELAY(10);
2276250003Sadrian    }
2277250003Sadrian    if (j == 10000) {
2278250003Sadrian        /*
2279250003Sadrian         * We timed out waiting for the noisefloor to load, probably
2280250003Sadrian         * due to an in-progress rx.  Simply return here and allow
2281250003Sadrian         * the load plenty of time to complete before the next
2282250003Sadrian         * calibration interval.  We need to avoid trying to load -50
2283250003Sadrian         * (which happens below) while the previous load is still in
2284250003Sadrian         * progress as this can cause rx deafness (see EV 66368,62830).
2285250003Sadrian         * Instead by returning here, the baseband nf cal will
2286250003Sadrian         * just be capped by our present noisefloor until the next
2287250003Sadrian         * calibration timer.
2288250003Sadrian         */
2289250003Sadrian        HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,
2290250003Sadrian            "%s: *** TIMEOUT while waiting for nf to load: "
2291250003Sadrian            "AR_PHY_AGC_CONTROL=0x%x ***\n",
2292250003Sadrian            __func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL));
2293250003Sadrian        return AH_FALSE;
2294250003Sadrian    }
2295250003Sadrian
2296250003Sadrian    /*
2297250003Sadrian     * Restore max_cca_power register parameter again so that we're not capped
2298250003Sadrian     * by the median we just loaded.  This will be initial (and max) value
2299250003Sadrian     * of next noise floor calibration the baseband does.
2300250003Sadrian     */
2301250008Sadrian    for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
2302250003Sadrian        if (chainmask & (1 << i)) {
2303250003Sadrian            val = OS_REG_READ(ah, ar9300_cca_regs[i]);
2304250003Sadrian            val &= 0xFFFFFE00;
2305250003Sadrian            val |= (((u_int32_t)(-50) << 1) & 0x1ff);
2306250003Sadrian            OS_REG_WRITE(ah, ar9300_cca_regs[i], val);
2307250003Sadrian        }
2308250003Sadrian    }
2309250003Sadrian    return AH_TRUE;
2310250003Sadrian}
2311250003Sadrian
2312250003Sadrian/* ar9300_per_calibration
2313250003Sadrian * Generic calibration routine.
2314250003Sadrian * Recalibrate the lower PHY chips to account for temperature/environment
2315250003Sadrian * changes.
2316250003Sadrian */
2317250003Sadrianinline static void
2318250003Sadrianar9300_per_calibration(struct ath_hal *ah,  HAL_CHANNEL_INTERNAL *ichan,
2319250003Sadrian    u_int8_t rxchainmask, HAL_CAL_LIST *curr_cal, HAL_BOOL *is_cal_done)
2320250003Sadrian{
2321250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2322250003Sadrian
2323250003Sadrian    /* Cal is assumed not done until explicitly set below */
2324250003Sadrian    *is_cal_done = AH_FALSE;
2325250003Sadrian
2326250003Sadrian    /* Calibration in progress. */
2327250003Sadrian    if (curr_cal->cal_state == CAL_RUNNING) {
2328250003Sadrian        /* Check to see if it has finished. */
2329250003Sadrian        if (!(OS_REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) {
2330250003Sadrian            int i, num_chains = 0;
2331250003Sadrian            for (i = 0; i < AR9300_MAX_CHAINS; i++) {
2332250003Sadrian                if (rxchainmask & (1 << i)) {
2333250003Sadrian                    num_chains++;
2334250003Sadrian                }
2335250003Sadrian            }
2336250003Sadrian
2337250003Sadrian            /*
2338250003Sadrian             * Accumulate cal measures for active chains
2339250003Sadrian             */
2340250003Sadrian            curr_cal->cal_data->cal_collect(ah, num_chains);
2341250003Sadrian
2342250003Sadrian            ahp->ah_cal_samples++;
2343250003Sadrian
2344250003Sadrian            if (ahp->ah_cal_samples >= curr_cal->cal_data->cal_num_samples) {
2345250003Sadrian                /*
2346250003Sadrian                 * Process accumulated data
2347250003Sadrian                 */
2348250003Sadrian                curr_cal->cal_data->cal_post_proc(ah, num_chains);
2349250003Sadrian
2350250003Sadrian                /* Calibration has finished. */
2351250008Sadrian                ichan->calValid |= curr_cal->cal_data->cal_type;
2352250003Sadrian                curr_cal->cal_state = CAL_DONE;
2353250003Sadrian                *is_cal_done = AH_TRUE;
2354250003Sadrian            } else {
2355250003Sadrian                /* Set-up collection of another sub-sample until we
2356250003Sadrian                 * get desired number
2357250003Sadrian                 */
2358250003Sadrian                ar9300_setup_calibration(ah, curr_cal);
2359250003Sadrian            }
2360250003Sadrian        }
2361250008Sadrian    } else if (!(ichan->calValid & curr_cal->cal_data->cal_type)) {
2362250003Sadrian        /* If current cal is marked invalid in channel, kick it off */
2363250003Sadrian        ar9300_reset_calibration(ah, curr_cal);
2364250003Sadrian    }
2365250003Sadrian}
2366250003Sadrian
2367250003Sadrianstatic void
2368250003Sadrianar9300_start_nf_cal(struct ath_hal *ah)
2369250003Sadrian{
2370278741Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2371250003Sadrian    OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
2372250003Sadrian    OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
2373250003Sadrian    OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
2374250003Sadrian    AH9300(ah)->nf_tsf32 = ar9300_get_tsf32(ah);
2375278741Sadrian
2376278741Sadrian/*
2377278741Sadrian *  We are reading the NF values before we start the NF operation, because
2378278741Sadrian *  of that we are getting very high values like -45.
2379278741Sadrian *  This triggers the CW_INT detected and EACS module triggers the channel change
2380278741Sadrian *  chip_reset_done value is used to fix this issue.
2381278741Sadrian *  chip_reset_flag is set during the RTC reset.
2382278741Sadrian *  chip_reset_flag is cleared during the starting NF operation.
2383278741Sadrian *  if flag is set we will clear the flag and will not read the NF values.
2384278741Sadrian */
2385278741Sadrian    ahp->ah_chip_reset_done = 0;
2386250003Sadrian}
2387250003Sadrian
2388250003Sadrian/* ar9300_calibration
2389250003Sadrian * Wrapper for a more generic Calibration routine. Primarily to abstract to
2390250003Sadrian * upper layers whether there is 1 or more calibrations to be run.
2391250003Sadrian */
2392250003SadrianHAL_BOOL
2393250008Sadrianar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask,
2394250003Sadrian    HAL_BOOL do_nf_cal, HAL_BOOL *is_cal_done, int is_scan,
2395250003Sadrian    u_int32_t *sched_cals)
2396250003Sadrian{
2397250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2398250003Sadrian    HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr;
2399250003Sadrian    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
2400250008Sadrian    int16_t nf_buf[HAL_NUM_NF_READINGS];
2401250003Sadrian
2402250003Sadrian    *is_cal_done = AH_TRUE;
2403250003Sadrian
2404250003Sadrian
2405250003Sadrian    /* XXX: For initial wasp bringup - disable periodic calibration */
2406250003Sadrian    /* Invalid channel check */
2407250003Sadrian    if (ichan == AH_NULL) {
2408250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CHANNEL,
2409250003Sadrian            "%s: invalid channel %u/0x%x; no mapping\n",
2410250008Sadrian            __func__, chan->ic_freq, chan->ic_flags);
2411250003Sadrian        return AH_FALSE;
2412250003Sadrian    }
2413250003Sadrian
2414250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2415250003Sadrian        "%s: Entering, Doing NF Cal = %d\n", __func__, do_nf_cal);
2416250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 0 Rx IQ Cal Correction 0x%08x\n",
2417250003Sadrian        __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
2418250003Sadrian    if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) {
2419250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2420250003Sadrian            "%s: Chain 1 Rx IQ Cal Correction 0x%08x\n",
2421250003Sadrian            __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B1));
2422291437Sadrian        if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)) {
2423250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2424250003Sadrian                "%s: Chain 2 Rx IQ Cal Correction 0x%08x\n",
2425250003Sadrian                __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B2));
2426250003Sadrian        }
2427250003Sadrian    }
2428250003Sadrian
2429250008Sadrian    OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq);
2430250003Sadrian
2431250003Sadrian    /* For given calibration:
2432250003Sadrian     * 1. Call generic cal routine
2433250003Sadrian     * 2. When this cal is done (is_cal_done) if we have more cals waiting
2434250003Sadrian     *    (eg after reset), mask this to upper layers by not propagating
2435250003Sadrian     *    is_cal_done if it is set to TRUE.
2436250003Sadrian     *    Instead, change is_cal_done to FALSE and setup the waiting cal(s)
2437250003Sadrian     *    to be run.
2438250003Sadrian     */
2439250003Sadrian    if (curr_cal && (curr_cal->cal_data->cal_type & *sched_cals) &&
2440250003Sadrian        (curr_cal->cal_state == CAL_RUNNING ||
2441250003Sadrian         curr_cal->cal_state == CAL_WAITING))
2442250003Sadrian    {
2443250003Sadrian        ar9300_per_calibration(ah, ichan, rxchainmask, curr_cal, is_cal_done);
2444250003Sadrian
2445250003Sadrian        if (*is_cal_done == AH_TRUE) {
2446250003Sadrian            ahp->ah_cal_list_curr = curr_cal = curr_cal->cal_next;
2447250003Sadrian
2448250003Sadrian            if (curr_cal && curr_cal->cal_state == CAL_WAITING) {
2449250003Sadrian                *is_cal_done = AH_FALSE;
2450250003Sadrian                ar9300_reset_calibration(ah, curr_cal);
2451250003Sadrian            } else {
2452250003Sadrian                *sched_cals &= ~IQ_MISMATCH_CAL;
2453250003Sadrian            }
2454250003Sadrian        }
2455250003Sadrian    }
2456250003Sadrian
2457250003Sadrian    /* Do NF cal only at longer intervals */
2458250003Sadrian    if (do_nf_cal) {
2459250003Sadrian        int nf_done;
2460250003Sadrian
2461250003Sadrian        /* Get the value from the previous NF cal and update history buffer */
2462250008Sadrian        nf_done = ar9300_store_new_nf(ah, chan, is_scan);
2463250008Sadrian#if 0
2464250003Sadrian        if (ichan->channel_flags & CHANNEL_CW_INT) {
2465250003Sadrian            chan->channel_flags |= CHANNEL_CW_INT;
2466250003Sadrian        }
2467250008Sadrian#endif
2468250008Sadrian        chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;
2469250003Sadrian
2470250003Sadrian        if (nf_done) {
2471250003Sadrian            /*
2472250003Sadrian             * Load the NF from history buffer of the current channel.
2473250003Sadrian             * NF is slow time-variant, so it is OK to use a historical value.
2474250003Sadrian             */
2475250008Sadrian            ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);
2476250003Sadrian            ar9300_load_nf(ah, nf_buf);
2477250003Sadrian
2478250003Sadrian            /* start NF calibration, without updating BB NF register*/
2479278741Sadrian            ar9300_start_nf_cal(ah);
2480250003Sadrian        }
2481250003Sadrian    }
2482250003Sadrian    return AH_TRUE;
2483250003Sadrian}
2484250003Sadrian
2485250003Sadrian/* ar9300_iq_cal_collect
2486250003Sadrian * Collect data from HW to later perform IQ Mismatch Calibration
2487250003Sadrian */
2488250003Sadrianvoid
2489250003Sadrianar9300_iq_cal_collect(struct ath_hal *ah, u_int8_t num_chains)
2490250003Sadrian{
2491250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2492250003Sadrian    int i;
2493250003Sadrian
2494250003Sadrian    /*
2495250003Sadrian     * Accumulate IQ cal measures for active chains
2496250003Sadrian     */
2497250003Sadrian    for (i = 0; i < num_chains; i++) {
2498250003Sadrian        ahp->ah_total_power_meas_i[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
2499250003Sadrian        ahp->ah_total_power_meas_q[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
2500250003Sadrian        ahp->ah_total_iq_corr_meas[i] =
2501250003Sadrian            (int32_t) OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
2502250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2503250003Sadrian            "%d: Chn %d "
2504250003Sadrian            "Reg Offset(0x%04x)pmi=0x%08x; "
2505250003Sadrian            "Reg Offset(0x%04x)pmq=0x%08x; "
2506250003Sadrian            "Reg Offset (0x%04x)iqcm=0x%08x;\n",
2507250003Sadrian            ahp->ah_cal_samples,
2508250003Sadrian            i,
2509250003Sadrian            (unsigned) AR_PHY_CAL_MEAS_0(i),
2510250003Sadrian            ahp->ah_total_power_meas_i[i],
2511250003Sadrian            (unsigned) AR_PHY_CAL_MEAS_1(i),
2512250003Sadrian            ahp->ah_total_power_meas_q[i],
2513250003Sadrian            (unsigned) AR_PHY_CAL_MEAS_2(i),
2514250003Sadrian            ahp->ah_total_iq_corr_meas[i]);
2515250003Sadrian    }
2516250003Sadrian}
2517250003Sadrian
2518250003Sadrian/* ar9300_iq_calibration
2519250003Sadrian * Use HW data to perform IQ Mismatch Calibration
2520250003Sadrian */
2521250003Sadrianvoid
2522250003Sadrianar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains)
2523250003Sadrian{
2524250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2525250003Sadrian    u_int32_t power_meas_q, power_meas_i, iq_corr_meas;
2526250003Sadrian    u_int32_t q_coff_denom, i_coff_denom;
2527250003Sadrian    int32_t q_coff, i_coff;
2528250003Sadrian    int iq_corr_neg, i;
2529278741Sadrian    HAL_CHANNEL_INTERNAL *ichan;
2530250003Sadrian    static const u_int32_t offset_array[3] = {
2531250003Sadrian        AR_PHY_RX_IQCAL_CORR_B0,
2532250003Sadrian        AR_PHY_RX_IQCAL_CORR_B1,
2533250003Sadrian        AR_PHY_RX_IQCAL_CORR_B2,
2534250003Sadrian    };
2535250003Sadrian
2536278741Sadrian    ichan = ath_hal_checkchannel(ah, AH_PRIVATE(ah)->ah_curchan);
2537278741Sadrian
2538250003Sadrian    for (i = 0; i < num_chains; i++) {
2539250003Sadrian        power_meas_i = ahp->ah_total_power_meas_i[i];
2540250003Sadrian        power_meas_q = ahp->ah_total_power_meas_q[i];
2541250003Sadrian        iq_corr_meas = ahp->ah_total_iq_corr_meas[i];
2542250003Sadrian
2543250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2544250003Sadrian            "Starting IQ Cal and Correction for Chain %d\n", i);
2545250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2546250003Sadrian            "Orignal: Chn %diq_corr_meas = 0x%08x\n",
2547250003Sadrian            i, ahp->ah_total_iq_corr_meas[i]);
2548250003Sadrian
2549250003Sadrian        iq_corr_neg = 0;
2550250003Sadrian
2551250003Sadrian        /* iq_corr_meas is always negative. */
2552250003Sadrian        if (iq_corr_meas > 0x80000000)  {
2553250003Sadrian            iq_corr_meas = (0xffffffff - iq_corr_meas) + 1;
2554250003Sadrian            iq_corr_neg = 1;
2555250003Sadrian        }
2556250003Sadrian
2557250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2558250003Sadrian            "Chn %d pwr_meas_i = 0x%08x\n", i, power_meas_i);
2559250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2560250003Sadrian            "Chn %d pwr_meas_q = 0x%08x\n", i, power_meas_q);
2561250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2562250003Sadrian            "iq_corr_neg is 0x%08x\n", iq_corr_neg);
2563250003Sadrian
2564250003Sadrian        i_coff_denom = (power_meas_i / 2 + power_meas_q / 2) / 256;
2565250003Sadrian        q_coff_denom = power_meas_q / 64;
2566250003Sadrian
2567250003Sadrian        /* Protect against divide-by-0 */
2568250003Sadrian        if ((i_coff_denom != 0) && (q_coff_denom != 0)) {
2569250003Sadrian            /* IQ corr_meas is already negated if iqcorr_neg == 1 */
2570250003Sadrian            i_coff = iq_corr_meas / i_coff_denom;
2571250003Sadrian            q_coff = power_meas_i / q_coff_denom - 64;
2572250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2573250003Sadrian                "Chn %d i_coff = 0x%08x\n", i, i_coff);
2574250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2575250003Sadrian                "Chn %d q_coff = 0x%08x\n", i, q_coff);
2576250003Sadrian
2577250003Sadrian            /* Force bounds on i_coff */
2578250003Sadrian            if (i_coff >= 63) {
2579250003Sadrian                i_coff = 63;
2580250003Sadrian            } else if (i_coff <= -63) {
2581250003Sadrian                i_coff = -63;
2582250003Sadrian            }
2583250003Sadrian
2584250003Sadrian            /* Negate i_coff if iq_corr_neg == 0 */
2585250003Sadrian            if (iq_corr_neg == 0x0) {
2586250003Sadrian                i_coff = -i_coff;
2587250003Sadrian            }
2588250003Sadrian
2589250003Sadrian            /* Force bounds on q_coff */
2590250003Sadrian            if (q_coff >= 63) {
2591250003Sadrian                q_coff = 63;
2592250003Sadrian            } else if (q_coff <= -63) {
2593250003Sadrian                q_coff = -63;
2594250003Sadrian            }
2595250003Sadrian
2596250003Sadrian            i_coff = i_coff & 0x7f;
2597250003Sadrian            q_coff = q_coff & 0x7f;
2598250003Sadrian
2599250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2600250003Sadrian                "Chn %d : i_coff = 0x%x  q_coff = 0x%x\n", i, i_coff, q_coff);
2601250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2602250003Sadrian                "Register offset (0x%04x) before update = 0x%x\n",
2603250003Sadrian                offset_array[i], OS_REG_READ(ah, offset_array[i]));
2604250003Sadrian
2605250003Sadrian            OS_REG_RMW_FIELD(ah, offset_array[i],
2606250003Sadrian                AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff);
2607250003Sadrian            OS_REG_RMW_FIELD(ah, offset_array[i],
2608250003Sadrian                AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff);
2609250003Sadrian
2610278741Sadrian            /* store the RX cal results */
2611278741Sadrian	    if (ichan != NULL) {
2612278741Sadrian            ahp->ah_rx_cal_corr[i] = OS_REG_READ(ah, offset_array[i]) & 0x7fff;
2613278741Sadrian            ahp->ah_rx_cal_complete = AH_TRUE;
2614278741Sadrian            ahp->ah_rx_cal_chan = ichan->channel;
2615278741Sadrian//            ahp->ah_rx_cal_chan_flag = ichan->channel_flags &~ CHANNEL_PASSIVE;
2616278741Sadrian            ahp->ah_rx_cal_chan_flag = 0; /* XXX */
2617278741Sadrian	    } else {
2618278741Sadrian	        /* XXX? Is this what I should do? */
2619278741Sadrian            	ahp->ah_rx_cal_complete = AH_FALSE;
2620278741Sadrian
2621278741Sadrian	    }
2622278741Sadrian
2623250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2624250003Sadrian                "Register offset (0x%04x) QI COFF (bitfields 0x%08x) "
2625250003Sadrian                "after update = 0x%x\n",
2626250003Sadrian                offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
2627250003Sadrian                OS_REG_READ(ah, offset_array[i]));
2628250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2629250003Sadrian                "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) "
2630250003Sadrian                "after update = 0x%x\n",
2631250003Sadrian                offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
2632250003Sadrian                OS_REG_READ(ah, offset_array[i]));
2633250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2634250003Sadrian                "IQ Cal and Correction done for Chain %d\n", i);
2635250003Sadrian        }
2636250003Sadrian    }
2637250003Sadrian
2638250003Sadrian    OS_REG_SET_BIT(ah,
2639250003Sadrian        AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
2640250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2641250003Sadrian        "IQ Cal and Correction (offset 0x%04x) enabled "
2642250003Sadrian        "(bit position 0x%08x). New Value 0x%08x\n",
2643250003Sadrian        (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
2644250003Sadrian        AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
2645250003Sadrian        OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
2646250003Sadrian}
2647250003Sadrian
2648250003Sadrian/*
2649278741Sadrian * When coming back from offchan, we do not perform RX IQ Cal.
2650278741Sadrian * But the chip reset will clear all previous results
2651278741Sadrian * We store the previous results and restore here.
2652278741Sadrian */
2653278741Sadrianstatic void
2654278741Sadrianar9300_rx_iq_cal_restore(struct ath_hal *ah)
2655278741Sadrian{
2656278741Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2657278741Sadrian    u_int32_t   i_coff, q_coff;
2658278741Sadrian    HAL_BOOL is_restore = AH_FALSE;
2659278741Sadrian    int i;
2660278741Sadrian    static const u_int32_t offset_array[3] = {
2661278741Sadrian        AR_PHY_RX_IQCAL_CORR_B0,
2662278741Sadrian        AR_PHY_RX_IQCAL_CORR_B1,
2663278741Sadrian        AR_PHY_RX_IQCAL_CORR_B2,
2664278741Sadrian    };
2665278741Sadrian
2666278741Sadrian    for (i=0; i<AR9300_MAX_CHAINS; i++) {
2667278741Sadrian        if (ahp->ah_rx_cal_corr[i]) {
2668278741Sadrian            i_coff = (ahp->ah_rx_cal_corr[i] &
2669278741Sadrian                        AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF) >>
2670278741Sadrian                        AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S;
2671278741Sadrian            q_coff = (ahp->ah_rx_cal_corr[i] &
2672278741Sadrian                        AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF) >>
2673278741Sadrian                        AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S;
2674278741Sadrian
2675278741Sadrian            OS_REG_RMW_FIELD(ah, offset_array[i],
2676278741Sadrian                AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff);
2677278741Sadrian            OS_REG_RMW_FIELD(ah, offset_array[i],
2678278741Sadrian                AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff);
2679278741Sadrian
2680278741Sadrian            is_restore = AH_TRUE;
2681278741Sadrian        }
2682278741Sadrian    }
2683278741Sadrian
2684278741Sadrian    if (is_restore)
2685278741Sadrian        OS_REG_SET_BIT(ah,
2686278741Sadrian            AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
2687278741Sadrian
2688278741Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2689278741Sadrian        "%s: IQ Cal and Correction (offset 0x%04x) enabled "
2690278741Sadrian        "(bit position 0x%08x). New Value 0x%08x\n",
2691278741Sadrian        __func__,
2692278741Sadrian        (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
2693278741Sadrian        AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
2694278741Sadrian        OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
2695278741Sadrian}
2696278741Sadrian
2697278741Sadrian/*
2698250003Sadrian * Set a limit on the overall output power.  Used for dynamic
2699250003Sadrian * transmit power control and the like.
2700250003Sadrian *
2701250003Sadrian * NB: limit is in units of 0.5 dbM.
2702250003Sadrian */
2703250003SadrianHAL_BOOL
2704250003Sadrianar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit,
2705250003Sadrian    u_int16_t extra_txpow, u_int16_t tpc_in_db)
2706250003Sadrian{
2707250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2708250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
2709250008Sadrian    const struct ieee80211_channel *chan = ahpriv->ah_curchan;
2710250008Sadrian    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
2711250003Sadrian
2712250003Sadrian    if (NULL == chan) {
2713250008Sadrian        return AH_FALSE;
2714250008Sadrian    }
2715250003Sadrian
2716250008Sadrian    ahpriv->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);
2717250008Sadrian    ahpriv->ah_extraTxPow = extra_txpow;
2718250008Sadrian
2719250003Sadrian    if(chan == NULL) {
2720250003Sadrian        return AH_FALSE;
2721250003Sadrian    }
2722250008Sadrian    if (ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan,
2723250003Sadrian        ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan),
2724250003Sadrian        ath_hal_get_twice_max_regpower(ahpriv, ichan, chan),
2725250008Sadrian        AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)) != HAL_OK)
2726250003Sadrian    {
2727250003Sadrian        return AH_FALSE;
2728250003Sadrian    }
2729250003Sadrian    return AH_TRUE;
2730250003Sadrian}
2731250003Sadrian
2732250003Sadrian/*
2733250003Sadrian * Exported call to check for a recent gain reading and return
2734250003Sadrian * the current state of the thermal calibration gain engine.
2735250003Sadrian */
2736250003SadrianHAL_RFGAIN
2737250003Sadrianar9300_get_rfgain(struct ath_hal *ah)
2738250003Sadrian{
2739250003Sadrian    return HAL_RFGAIN_INACTIVE;
2740250003Sadrian}
2741250003Sadrian
2742250003Sadrian#define HAL_GREEN_AP_RX_MASK 0x1
2743250003Sadrian
2744250003Sadrianstatic inline void
2745250003Sadrianar9300_init_chain_masks(struct ath_hal *ah, int rx_chainmask, int tx_chainmask)
2746250003Sadrian{
2747250008Sadrian    if (AH9300(ah)->green_ap_ps_on) {
2748250003Sadrian        rx_chainmask = HAL_GREEN_AP_RX_MASK;
2749250003Sadrian    }
2750250003Sadrian    if (rx_chainmask == 0x5) {
2751250003Sadrian        OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);
2752250003Sadrian    }
2753250003Sadrian    OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
2754250003Sadrian    OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
2755250003Sadrian
2756250003Sadrian    /*
2757250003Sadrian     * Adaptive Power Management:
2758250003Sadrian     * Some 3 stream chips exceed the PCIe power requirements.
2759250003Sadrian     * This workaround will reduce power consumption by using 2 tx chains
2760250003Sadrian     * for 1 and 2 stream rates (5 GHz only).
2761250003Sadrian     *
2762250003Sadrian     * Set the self gen mask to 2 tx chains when APM is enabled.
2763250003Sadrian     *
2764250003Sadrian     */
2765250008Sadrian    if (AH_PRIVATE(ah)->ah_caps.halApmEnable && (tx_chainmask == 0x7)) {
2766250003Sadrian        OS_REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
2767250003Sadrian    }
2768250003Sadrian    else {
2769250003Sadrian        OS_REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
2770250003Sadrian    }
2771250003Sadrian
2772250003Sadrian    if (tx_chainmask == 0x5) {
2773250003Sadrian        OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);
2774250003Sadrian    }
2775250003Sadrian}
2776250003Sadrian
2777250003Sadrian/*
2778250003Sadrian * Override INI values with chip specific configuration.
2779250003Sadrian */
2780250003Sadrianstatic inline void
2781250008Sadrianar9300_override_ini(struct ath_hal *ah, struct ieee80211_channel *chan)
2782250003Sadrian{
2783250003Sadrian    u_int32_t val;
2784250003Sadrian    HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
2785250003Sadrian
2786250003Sadrian    /*
2787250003Sadrian     * Set the RX_ABORT and RX_DIS and clear it only after
2788250003Sadrian     * RXE is set for MAC. This prevents frames with
2789250003Sadrian     * corrupted descriptor status.
2790250003Sadrian     */
2791250003Sadrian    OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
2792250003Sadrian    /*
2793250003Sadrian     * For Merlin and above, there is a new feature that allows Multicast
2794250003Sadrian     * search based on both MAC Address and Key ID.
2795250003Sadrian     * By default, this feature is enabled.
2796250003Sadrian     * But since the driver is not using this feature, we switch it off;
2797250003Sadrian     * otherwise multicast search based on MAC addr only will fail.
2798250003Sadrian     */
2799250003Sadrian    val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);
2800250003Sadrian    OS_REG_WRITE(ah, AR_PCU_MISC_MODE2,
2801250003Sadrian        val | AR_BUG_58603_FIX_ENABLE | AR_AGG_WEP_ENABLE);
2802250003Sadrian
2803250003Sadrian
2804250003Sadrian    /* Osprey revision specific configuration */
2805250003Sadrian
2806250003Sadrian    /* Osprey 2.0+ - if SW RAC support is disabled, must also disable
2807250003Sadrian     * the Osprey 2.0 hardware RAC fix.
2808250003Sadrian     */
2809250008Sadrian    if (p_cap->halIsrRacSupport == AH_FALSE) {
2810250003Sadrian        OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_MISSING_TX_INTR_FIX_ENABLE);
2811250003Sadrian    }
2812250003Sadrian
2813250003Sadrian    /* try to enable old pal if it is needed for h/w green tx */
2814250003Sadrian    ar9300_hwgreentx_set_pal_spare(ah, 1);
2815250003Sadrian}
2816250003Sadrian
2817250003Sadrianstatic inline void
2818250003Sadrianar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr,
2819250003Sadrian    int column)
2820250003Sadrian{
2821250003Sadrian    int i, reg_writes = 0;
2822250003Sadrian
2823250003Sadrian    /* New INI format: Array may be undefined (pre, core, post arrays) */
2824250003Sadrian    if (ini_arr->ia_array == NULL) {
2825250003Sadrian        return;
2826250003Sadrian    }
2827250003Sadrian
2828250003Sadrian    /*
2829250003Sadrian     * New INI format: Pre, core, and post arrays for a given subsystem may be
2830250003Sadrian     * modal (> 2 columns) or non-modal (2 columns).
2831250003Sadrian     * Determine if the array is non-modal and force the column to 1.
2832250003Sadrian     */
2833250003Sadrian    if (column >= ini_arr->ia_columns) {
2834250003Sadrian        column = 1;
2835250003Sadrian    }
2836250003Sadrian
2837250003Sadrian    for (i = 0; i < ini_arr->ia_rows; i++) {
2838250003Sadrian        u_int32_t reg = INI_RA(ini_arr, i, 0);
2839250003Sadrian        u_int32_t val = INI_RA(ini_arr, i, column);
2840250003Sadrian
2841250003Sadrian        /*
2842250003Sadrian        ** Determine if this is a shift register value
2843250003Sadrian        ** (reg >= 0x16000 && reg < 0x17000 for Osprey) ,
2844250003Sadrian        ** and insert the configured delay if so.
2845250003Sadrian        ** -this delay is not required for Osprey (EV#71410)
2846250003Sadrian        */
2847250003Sadrian        OS_REG_WRITE(ah, reg, val);
2848250003Sadrian        WAR_6773(reg_writes);
2849250003Sadrian
2850250003Sadrian    }
2851250003Sadrian}
2852250003Sadrian
2853250003Sadrianstatic inline HAL_STATUS
2854250008Sadrianar9300_process_ini(struct ath_hal *ah, struct ieee80211_channel *chan,
2855250003Sadrian    HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode)
2856250003Sadrian{
2857250003Sadrian    int reg_writes = 0;
2858250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
2859250003Sadrian    u_int modes_index, modes_txgaintable_index = 0;
2860250003Sadrian    int i;
2861250003Sadrian    HAL_STATUS status;
2862250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
2863250003Sadrian    /* Setup the indices for the next set of register array writes */
2864250003Sadrian    /* TODO:
2865250003Sadrian     * If the channel marker is indicative of the current mode rather
2866250003Sadrian     * than capability, we do not need to check the phy mode below.
2867250003Sadrian     */
2868250008Sadrian#if 0
2869250003Sadrian    switch (chan->channel_flags & CHANNEL_ALL) {
2870250003Sadrian    case CHANNEL_A:
2871250003Sadrian    case CHANNEL_A_HT20:
2872250003Sadrian        if (AR_SREV_SCORPION(ah)){
2873250003Sadrian            if (chan->channel <= 5350){
2874250003Sadrian                modes_txgaintable_index = 1;
2875250003Sadrian            }else if ((chan->channel > 5350) && (chan->channel <= 5600)){
2876250003Sadrian                modes_txgaintable_index = 3;
2877250003Sadrian            }else if (chan->channel > 5600){
2878250003Sadrian                modes_txgaintable_index = 5;
2879250003Sadrian            }
2880250003Sadrian        }
2881250003Sadrian        modes_index = 1;
2882291437Sadrian        freq_index  = 1;
2883250003Sadrian        break;
2884250003Sadrian
2885250003Sadrian    case CHANNEL_A_HT40PLUS:
2886250003Sadrian    case CHANNEL_A_HT40MINUS:
2887250003Sadrian        if (AR_SREV_SCORPION(ah)){
2888250003Sadrian            if (chan->channel <= 5350){
2889250003Sadrian                modes_txgaintable_index = 2;
2890250003Sadrian            }else if ((chan->channel > 5350) && (chan->channel <= 5600)){
2891250003Sadrian                modes_txgaintable_index = 4;
2892250003Sadrian            }else if (chan->channel > 5600){
2893250003Sadrian                modes_txgaintable_index = 6;
2894250003Sadrian            }
2895250003Sadrian        }
2896250003Sadrian        modes_index = 2;
2897291437Sadrian        freq_index  = 1;
2898250003Sadrian        break;
2899250003Sadrian
2900250003Sadrian    case CHANNEL_PUREG:
2901250003Sadrian    case CHANNEL_G_HT20:
2902250003Sadrian    case CHANNEL_B:
2903250003Sadrian        if (AR_SREV_SCORPION(ah)){
2904250003Sadrian            modes_txgaintable_index = 8;
2905291437Sadrian        }else if (AR_SREV_HONEYBEE(ah)){
2906291437Sadrian	    modes_txgaintable_index = 1;
2907291437Sadrian	}
2908250003Sadrian        modes_index = 4;
2909291437Sadrian        freq_index  = 2;
2910250003Sadrian        break;
2911250003Sadrian
2912250003Sadrian    case CHANNEL_G_HT40PLUS:
2913250003Sadrian    case CHANNEL_G_HT40MINUS:
2914250003Sadrian        if (AR_SREV_SCORPION(ah)){
2915250003Sadrian            modes_txgaintable_index = 7;
2916291437Sadrian        }else if (AR_SREV_HONEYBEE(ah)){
2917291437Sadrian            modes_txgaintable_index = 1;
2918250003Sadrian        }
2919250003Sadrian        modes_index = 3;
2920291437Sadrian        freq_index  = 2;
2921250003Sadrian        break;
2922250003Sadrian
2923250003Sadrian    case CHANNEL_108G:
2924250003Sadrian        modes_index = 5;
2925291437Sadrian        freq_index  = 2;
2926250003Sadrian        break;
2927250003Sadrian
2928250003Sadrian    default:
2929250003Sadrian        HALASSERT(0);
2930250003Sadrian        return HAL_EINVAL;
2931250003Sadrian    }
2932250008Sadrian#endif
2933250003Sadrian
2934250008Sadrian    /* FreeBSD */
2935250008Sadrian    if (IS_CHAN_5GHZ(ichan)) {
2936250008Sadrian        if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) {
2937250008Sadrian            if (AR_SREV_SCORPION(ah)){
2938250008Sadrian                if (ichan->channel <= 5350){
2939250008Sadrian                    modes_txgaintable_index = 2;
2940250008Sadrian                }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){
2941250008Sadrian                    modes_txgaintable_index = 4;
2942250008Sadrian                }else if (ichan->channel > 5600){
2943250008Sadrian                    modes_txgaintable_index = 6;
2944250008Sadrian                }
2945250008Sadrian            }
2946250008Sadrian            modes_index = 2;
2947250008Sadrian        } else if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_HT20(chan)) {
2948250008Sadrian            if (AR_SREV_SCORPION(ah)){
2949250008Sadrian                if (ichan->channel <= 5350){
2950250008Sadrian                    modes_txgaintable_index = 1;
2951250008Sadrian                }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){
2952250008Sadrian                    modes_txgaintable_index = 3;
2953250008Sadrian                }else if (ichan->channel > 5600){
2954250008Sadrian                    modes_txgaintable_index = 5;
2955250008Sadrian                }
2956250008Sadrian            }
2957250008Sadrian            modes_index = 1;
2958250008Sadrian        } else
2959250008Sadrian            return HAL_EINVAL;
2960250008Sadrian    } else if (IS_CHAN_2GHZ(ichan)) {
2961250008Sadrian        if (IEEE80211_IS_CHAN_108G(chan)) {
2962250008Sadrian            modes_index = 5;
2963250008Sadrian        } else if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) {
2964250008Sadrian            if (AR_SREV_SCORPION(ah)){
2965250008Sadrian                modes_txgaintable_index = 7;
2966291437Sadrian            } else if (AR_SREV_HONEYBEE(ah)){
2967291437Sadrian                modes_txgaintable_index = 1;
2968250008Sadrian            }
2969250008Sadrian            modes_index = 3;
2970250008Sadrian        } else if (IEEE80211_IS_CHAN_HT20(chan) || IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_PUREG(chan)) {
2971250008Sadrian            if (AR_SREV_SCORPION(ah)){
2972250008Sadrian                modes_txgaintable_index = 8;
2973291437Sadrian            } else if (AR_SREV_HONEYBEE(ah)){
2974291437Sadrian                modes_txgaintable_index = 1;
2975250008Sadrian            }
2976250008Sadrian            modes_index = 4;
2977250008Sadrian        } else
2978250008Sadrian            return HAL_EINVAL;
2979250008Sadrian    } else
2980250008Sadrian            return HAL_EINVAL;
2981250008Sadrian
2982250003Sadrian#if 0
2983250003Sadrian    /* Set correct Baseband to analog shift setting to access analog chips. */
2984250003Sadrian    OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
2985250003Sadrian#endif
2986250003Sadrian
2987250003Sadrian    HALDEBUG(ah, HAL_DEBUG_RESET,
2988250003Sadrian        "ar9300_process_ini: "
2989250003Sadrian        "Skipping OS-REG-WRITE(ah, AR-PHY(0), 0x00000007)\n");
2990250003Sadrian    HALDEBUG(ah, HAL_DEBUG_RESET,
2991250003Sadrian        "ar9300_process_ini: no ADDac programming\n");
2992250003Sadrian
2993250003Sadrian
2994250003Sadrian    /*
2995250003Sadrian     * Osprey 2.0+ - new INI format.
2996250003Sadrian     * Each subsystem has a pre, core, and post array.
2997250003Sadrian     */
2998250003Sadrian    for (i = 0; i < ATH_INI_NUM_SPLIT; i++) {
2999250003Sadrian        ar9300_prog_ini(ah, &ahp->ah_ini_soc[i], modes_index);
3000250003Sadrian        ar9300_prog_ini(ah, &ahp->ah_ini_mac[i], modes_index);
3001250003Sadrian        ar9300_prog_ini(ah, &ahp->ah_ini_bb[i], modes_index);
3002250003Sadrian        ar9300_prog_ini(ah, &ahp->ah_ini_radio[i], modes_index);
3003301420Sadrian        if ((i == ATH_INI_POST) && (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah))) {
3004250003Sadrian            ar9300_prog_ini(ah, &ahp->ah_ini_radio_post_sys2ant, modes_index);
3005250003Sadrian        }
3006250003Sadrian
3007250003Sadrian    }
3008250003Sadrian
3009250003Sadrian	if (!(AR_SREV_SOC(ah))) {
3010250003Sadrian			/* Doubler issue : Some board doesn't work well with MCS15. Turn off doubler after freq locking is complete*/
3011250003Sadrian			//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));
3012250003Sadrian			OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
3013250003Sadrian			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */
3014250003Sadrian			//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));
3015250003Sadrian
3016250003Sadrian			OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
3017250003Sadrian			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */
3018250003Sadrian			OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
3019250003Sadrian			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */
3020250003Sadrian			OS_DELAY(200);
3021250003Sadrian
3022250003Sadrian			//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));
3023250003Sadrian			OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */
3024250003Sadrian			OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */
3025250003Sadrian			OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */
3026250003Sadrian			//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));
3027250003Sadrian
3028250003Sadrian			OS_DELAY(1);
3029250003Sadrian
3030250003Sadrian			//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));
3031250003Sadrian			OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */
3032250003Sadrian			OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */
3033250003Sadrian			OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */
3034250003Sadrian			//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));
3035250003Sadrian
3036250003Sadrian			OS_DELAY(200);
3037250003Sadrian
3038250003Sadrian			//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));
3039250003Sadrian			OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf);
3040250003Sadrian			//OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_SYNTH12, 1<< 16); /* clr charge pump */
3041250003Sadrian			//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));
3042250003Sadrian
3043250003Sadrian			OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
3044250003Sadrian			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */
3045250003Sadrian			OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
3046250003Sadrian			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */
3047250003Sadrian			OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
3048250003Sadrian			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */
3049250003Sadrian			//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));
3050250003Sadrian		}
3051250003Sadrian
3052250003Sadrian    /* Write rxgain Array Parameters */
3053250003Sadrian    REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain, 1, reg_writes);
3054250003Sadrian    HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain programming\n");
3055250003Sadrian
3056301423Sadrian    if (AR_SREV_JUPITER_20_OR_LATER(ah)) {
3057301423Sadrian        /*
3058301423Sadrian         * CUS217 mix LNA mode.
3059301423Sadrian         */
3060301423Sadrian        if (ar9300_rx_gain_index_get(ah) == 2) {
3061301423Sadrian            REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bb_core, 1, reg_writes);
3062301423Sadrian            REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bb_postamble,
3063301423Sadrian                modes_index, reg_writes);
3064301423Sadrian        }
3065301423Sadrian
3066301423Sadrian        /*
3067301423Sadrian         * 5G-XLNA
3068301423Sadrian         */
3069301423Sadrian        if ((ar9300_rx_gain_index_get(ah) == 2) ||
3070301423Sadrian            (ar9300_rx_gain_index_get(ah) == 3)) {
3071301423Sadrian            REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_xlna, modes_index,
3072301423Sadrian              reg_writes);
3073301423Sadrian        }
3074301423Sadrian    }
3075301423Sadrian
3076250003Sadrian    if (AR_SREV_SCORPION(ah)) {
3077250003Sadrian        /* Write rxgain bounds Array */
3078250003Sadrian        REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, modes_index, reg_writes);
3079250003Sadrian        HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain table bounds programming\n");
3080250003Sadrian    }
3081250003Sadrian    /* UB124 xLNA settings */
3082250003Sadrian    if (AR_SREV_WASP(ah) && ar9300_rx_gain_index_get(ah) == 2) {
3083250003Sadrian#define REG_WRITE(_reg,_val)    *((volatile u_int32_t *)(_reg)) = (_val);
3084250003Sadrian#define REG_READ(_reg)          *((volatile u_int32_t *)(_reg))
3085250003Sadrian        u_int32_t val;
3086250003Sadrian        /* B8040000:  bit[0]=0, bit[3]=0; */
3087250003Sadrian        val = REG_READ(0xB8040000);
3088250003Sadrian        val &= 0xfffffff6;
3089250003Sadrian        REG_WRITE(0xB8040000, val);
3090250003Sadrian        /* B804002c:  bit[31:24]=0x2e; bit[7:0]=0x2f; */
3091250003Sadrian        val = REG_READ(0xB804002c);
3092250003Sadrian        val &= 0x00ffff00;
3093250003Sadrian        val |= 0x2e00002f;
3094250003Sadrian        REG_WRITE(0xB804002c, val);
3095250003Sadrian        /* B804006c:  bit[1]=1; */
3096250003Sadrian        val = REG_READ(0xB804006c);
3097250003Sadrian        val |= 0x2;
3098250003Sadrian        REG_WRITE(0xB804006c, val);
3099250003Sadrian#undef REG_READ
3100250003Sadrian#undef REG_WRITE
3101250003Sadrian    }
3102250003Sadrian
3103250003Sadrian
3104250003Sadrian    /* Write txgain Array Parameters */
3105291437Sadrian    if (AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
3106250003Sadrian        REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_txgaintable_index,
3107250003Sadrian            reg_writes);
3108250003Sadrian    }else{
3109250003Sadrian        REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_index, reg_writes);
3110250003Sadrian    }
3111250003Sadrian    HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Tx Gain programming\n");
3112250003Sadrian
3113250003Sadrian
3114250003Sadrian    /* For 5GHz channels requiring Fast Clock, apply different modal values */
3115250003Sadrian    if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {
3116250003Sadrian        HALDEBUG(ah, HAL_DEBUG_RESET,
3117250003Sadrian            "%s: Fast clock enabled, use special ini values\n", __func__);
3118250003Sadrian        REG_WRITE_ARRAY(&ahp->ah_ini_modes_additional, modes_index, reg_writes);
3119250003Sadrian    }
3120250003Sadrian
3121250003Sadrian    if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
3122250003Sadrian        HALDEBUG(ah, HAL_DEBUG_RESET,
3123250003Sadrian            "%s: use xtal ini for AH9300(ah)->clk_25mhz: %d\n",
3124250003Sadrian            __func__, AH9300(ah)->clk_25mhz);
3125250003Sadrian        REG_WRITE_ARRAY(
3126250003Sadrian            &ahp->ah_ini_modes_additional, 1/*modes_index*/, reg_writes);
3127250003Sadrian    }
3128250003Sadrian
3129250003Sadrian    if (AR_SREV_WASP(ah) && (AH9300(ah)->clk_25mhz == 0)) {
3130250003Sadrian        HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Apply 40MHz ini settings\n", __func__);
3131250003Sadrian        REG_WRITE_ARRAY(
3132250003Sadrian            &ahp->ah_ini_modes_additional_40mhz, 1/*modesIndex*/, reg_writes);
3133250003Sadrian    }
3134250003Sadrian
3135250008Sadrian    /* Handle Japan Channel 14 channel spreading */
3136250008Sadrian    if (2484 == ichan->channel) {
3137250003Sadrian        ar9300_prog_ini(ah, &ahp->ah_ini_japan2484, 1);
3138250003Sadrian    }
3139250003Sadrian
3140250003Sadrian#if 0
3141301420Sadrian    /* XXX TODO! */
3142301420Sadrian    if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) {
3143250003Sadrian        ar9300_prog_ini(ah, &ahp->ah_ini_BTCOEX_MAX_TXPWR, 1);
3144250003Sadrian    }
3145250003Sadrian#endif
3146250003Sadrian
3147250003Sadrian    /* Override INI with chip specific configuration */
3148250003Sadrian    ar9300_override_ini(ah, chan);
3149250003Sadrian
3150250003Sadrian    /* Setup 11n MAC/Phy mode registers */
3151250003Sadrian    ar9300_set_11n_regs(ah, chan, macmode);
3152250003Sadrian
3153250003Sadrian    /*
3154250003Sadrian     * Moved ar9300_init_chain_masks() here to ensure the swap bit is set before
3155250003Sadrian     * the pdadc table is written.  Swap must occur before any radio dependent
3156250003Sadrian     * replicated register access.  The pdadc curve addressing in particular
3157250003Sadrian     * depends on the consistent setting of the swap bit.
3158250003Sadrian     */
3159250003Sadrian    ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask);
3160250003Sadrian
3161250003Sadrian    /*
3162250003Sadrian     * Setup the transmit power values.
3163250003Sadrian     *
3164250003Sadrian     * After the public to private hal channel mapping, ichan contains the
3165250003Sadrian     * valid regulatory power value.
3166250003Sadrian     * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan.
3167250003Sadrian     */
3168250008Sadrian    status = ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan,
3169250003Sadrian             ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan),
3170250003Sadrian             ath_hal_get_twice_max_regpower(ahpriv, ichan, chan),
3171250008Sadrian             AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit));
3172250003Sadrian    if (status != HAL_OK) {
3173250003Sadrian        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
3174250003Sadrian            "%s: error init'ing transmit power\n", __func__);
3175250003Sadrian        return HAL_EIO;
3176250003Sadrian    }
3177250003Sadrian
3178250003Sadrian
3179250003Sadrian    return HAL_OK;
3180250003Sadrian#undef N
3181250003Sadrian}
3182250003Sadrian
3183250003Sadrian/* ar9300_is_cal_supp
3184250003Sadrian * Determine if calibration is supported by device and channel flags
3185250003Sadrian */
3186250003Sadrianinline static HAL_BOOL
3187250008Sadrianar9300_is_cal_supp(struct ath_hal *ah, const struct ieee80211_channel *chan,
3188250003Sadrian    HAL_CAL_TYPES cal_type)
3189250003Sadrian{
3190250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
3191250003Sadrian    HAL_BOOL retval = AH_FALSE;
3192250003Sadrian
3193250003Sadrian    switch (cal_type & ahp->ah_supp_cals) {
3194250003Sadrian    case IQ_MISMATCH_CAL:
3195250003Sadrian        /* Run IQ Mismatch for non-CCK only */
3196250008Sadrian        if (!IEEE80211_IS_CHAN_B(chan)) {
3197250003Sadrian            retval = AH_TRUE;
3198250003Sadrian        }
3199250003Sadrian        break;
3200250003Sadrian    case TEMP_COMP_CAL:
3201250003Sadrian        retval = AH_TRUE;
3202250003Sadrian        break;
3203250003Sadrian    }
3204250003Sadrian
3205250003Sadrian    return retval;
3206250003Sadrian}
3207250003Sadrian
3208250003Sadrian
3209250003Sadrian#if 0
3210250003Sadrian/* ar9285_pa_cal
3211250003Sadrian * PA Calibration for Kite 1.1 and later versions of Kite.
3212250003Sadrian * - from system's team.
3213250003Sadrian */
3214250003Sadrianstatic inline void
3215250003Sadrianar9285_pa_cal(struct ath_hal *ah)
3216250003Sadrian{
3217250003Sadrian    u_int32_t reg_val;
3218250003Sadrian    int i, lo_gn, offs_6_1, offs_0;
3219250003Sadrian    u_int8_t reflo;
3220250003Sadrian    u_int32_t phy_test2_reg_val, phy_adc_ctl_reg_val;
3221250003Sadrian    u_int32_t an_top2_reg_val, phy_tst_dac_reg_val;
3222250003Sadrian
3223250003Sadrian
3224250003Sadrian    /* Kite 1.1 WAR for Bug 35666
3225250003Sadrian     * Increase the LDO value to 1.28V before accessing analog Reg */
3226250003Sadrian    if (AR_SREV_KITE_11(ah)) {
3227250003Sadrian        OS_REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14) );
3228250003Sadrian    }
3229250003Sadrian    an_top2_reg_val = OS_REG_READ(ah, AR9285_AN_TOP2);
3230250003Sadrian
3231250003Sadrian    /* set pdv2i pdrxtxbb */
3232250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1);
3233250003Sadrian    reg_val |= ((0x1 << 5) | (0x1 << 7));
3234250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val);
3235250003Sadrian
3236250003Sadrian    /* clear pwddb */
3237250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G7);
3238250003Sadrian    reg_val &= 0xfffffffd;
3239250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G7, reg_val);
3240250003Sadrian
3241250003Sadrian    /* clear enpacal */
3242250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);
3243250003Sadrian    reg_val &= 0xfffff7ff;
3244250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);
3245250003Sadrian
3246250003Sadrian    /* set offcal */
3247250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2);
3248250003Sadrian    reg_val |= (0x1 << 12);
3249250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val);
3250250003Sadrian
3251250003Sadrian    /* set pdpadrv1=pdpadrv2=pdpaout=1 */
3252250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);
3253250003Sadrian    reg_val |= (0x7 << 23);
3254250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);
3255250003Sadrian
3256250003Sadrian    /* Read back reflo, increase it by 1 and write it. */
3257250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
3258250003Sadrian    reflo = ((reg_val >> 26) & 0x7);
3259250003Sadrian
3260250003Sadrian    if (reflo < 0x7) {
3261250003Sadrian        reflo++;
3262250003Sadrian    }
3263250003Sadrian    reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26));
3264250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
3265250003Sadrian
3266250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
3267250003Sadrian    reflo = ((reg_val >> 26) & 0x7);
3268250003Sadrian
3269250003Sadrian    /* use TX single carrier to transmit
3270250003Sadrian     * dac const
3271250003Sadrian     * reg. 15
3272250003Sadrian     */
3273250003Sadrian    phy_tst_dac_reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST);
3274250003Sadrian    OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, ((0x7ff << 11) | 0x7ff));
3275250003Sadrian    reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST);
3276250003Sadrian
3277250003Sadrian    /* source is dac const
3278250003Sadrian     * reg. 2
3279250003Sadrian     */
3280250003Sadrian    phy_test2_reg_val = OS_REG_READ(ah, AR_PHY_TEST2);
3281250003Sadrian    OS_REG_WRITE(ah, AR_PHY_TEST2, ((0x1 << 7) | (0x1 << 1)));
3282250003Sadrian    reg_val = OS_REG_READ(ah, AR_PHY_TEST2);
3283250003Sadrian
3284250003Sadrian    /* set dac on
3285250003Sadrian     * reg. 11
3286250003Sadrian     */
3287250003Sadrian    phy_adc_ctl_reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL);
3288250003Sadrian    OS_REG_WRITE(ah, AR_PHY_ADC_CTL, 0x80008000);
3289250003Sadrian    reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL);
3290250003Sadrian
3291250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_TOP2, (0x1 << 27) | (0x1 << 17) | (0x1 << 16) |
3292250003Sadrian              (0x1 << 14) | (0x1 << 12) | (0x1 << 11) |
3293250003Sadrian              (0x1 << 7) | (0x1 << 5));
3294250003Sadrian
3295250003Sadrian    OS_DELAY(10); /* 10 usec */
3296250003Sadrian
3297250003Sadrian    /* clear off[6:0] */
3298250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);
3299250003Sadrian    reg_val &= 0xfc0fffff;
3300250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);
3301250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
3302250003Sadrian    reg_val &= 0xfdffffff;
3303250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
3304250003Sadrian
3305250003Sadrian    offs_6_1 = 0;
3306250003Sadrian    for (i = 6; i > 0; i--) {
3307250003Sadrian        /* sef off[$k]==1 */
3308250003Sadrian        reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);
3309250003Sadrian        reg_val &= 0xfc0fffff;
3310250003Sadrian        reg_val = reg_val | (0x1 << (19 + i)) | ((offs_6_1) << 20);
3311250003Sadrian        OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);
3312250003Sadrian        lo_gn = (OS_REG_READ(ah, AR9285_AN_RF2G9)) & 0x1;
3313250003Sadrian        offs_6_1 = offs_6_1 | (lo_gn << (i - 1));
3314250003Sadrian    }
3315250003Sadrian
3316250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);
3317250003Sadrian    reg_val &= 0xfc0fffff;
3318250003Sadrian    reg_val = reg_val | ((offs_6_1 - 1) << 20);
3319250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);
3320250003Sadrian
3321250003Sadrian    /* set off_0=1; */
3322250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
3323250003Sadrian    reg_val &= 0xfdffffff;
3324250003Sadrian    reg_val = reg_val | (0x1 << 25);
3325250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
3326250003Sadrian
3327250003Sadrian    lo_gn = OS_REG_READ(ah, AR9285_AN_RF2G9) & 0x1;
3328250003Sadrian    offs_0 = lo_gn;
3329250003Sadrian
3330250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
3331250003Sadrian    reg_val &= 0xfdffffff;
3332250003Sadrian    reg_val = reg_val | (offs_0 << 25);
3333250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
3334250003Sadrian
3335250003Sadrian    /* clear pdv2i */
3336250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1);
3337250003Sadrian    reg_val &= 0xffffff5f;
3338250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val);
3339250003Sadrian
3340250003Sadrian    /* set enpacal */
3341250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);
3342250003Sadrian    reg_val |= (0x1 << 11);
3343250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);
3344250003Sadrian
3345250003Sadrian    /* clear offcal */
3346250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2);
3347250003Sadrian    reg_val &= 0xffffefff;
3348250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val);
3349250003Sadrian
3350250003Sadrian    /* set pdpadrv1=pdpadrv2=pdpaout=0 */
3351250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);
3352250003Sadrian    reg_val &= 0xfc7fffff;
3353250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);
3354250003Sadrian
3355250003Sadrian    /* Read back reflo, decrease it by 1 and write it. */
3356250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
3357250003Sadrian    reflo = (reg_val >> 26) & 0x7;
3358250003Sadrian    if (reflo) {
3359250003Sadrian        reflo--;
3360250003Sadrian    }
3361250003Sadrian    reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26));
3362250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
3363250003Sadrian    reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
3364250003Sadrian    reflo = (reg_val >> 26) & 0x7;
3365250003Sadrian
3366250003Sadrian    /* write back registers */
3367250003Sadrian    OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, phy_tst_dac_reg_val);
3368250003Sadrian    OS_REG_WRITE(ah, AR_PHY_TEST2, phy_test2_reg_val);
3369250003Sadrian    OS_REG_WRITE(ah, AR_PHY_ADC_CTL, phy_adc_ctl_reg_val);
3370250003Sadrian    OS_REG_WRITE(ah, AR9285_AN_TOP2, an_top2_reg_val);
3371250003Sadrian
3372250003Sadrian    /* Kite 1.1 WAR for Bug 35666
3373250003Sadrian     * Decrease the LDO value back to 1.20V */
3374250003Sadrian    if (AR_SREV_KITE_11(ah)) {
3375250003Sadrian        OS_REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
3376250003Sadrian    }
3377250003Sadrian}
3378250003Sadrian#endif
3379250003Sadrian
3380250003Sadrian/* ar9300_run_init_cals
3381250003Sadrian * Runs non-periodic calibrations
3382250003Sadrian */
3383250003Sadrianinline static HAL_BOOL
3384250003Sadrianar9300_run_init_cals(struct ath_hal *ah, int init_cal_count)
3385250003Sadrian{
3386250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
3387250003Sadrian    HAL_CHANNEL_INTERNAL ichan; /* bogus */
3388250003Sadrian    HAL_BOOL is_cal_done;
3389250003Sadrian    HAL_CAL_LIST *curr_cal;
3390250008Sadrian    const HAL_PERCAL_DATA *cal_data;
3391250003Sadrian    int i;
3392250003Sadrian
3393250003Sadrian    curr_cal = ahp->ah_cal_list_curr;
3394250003Sadrian    if (curr_cal == AH_NULL) {
3395250003Sadrian        return AH_FALSE;
3396250003Sadrian    }
3397250008Sadrian    cal_data = curr_cal->cal_data;
3398250008Sadrian    ichan.calValid = 0;
3399250003Sadrian
3400250003Sadrian    for (i = 0; i < init_cal_count; i++) {
3401250003Sadrian        /* Reset this Cal */
3402250003Sadrian        ar9300_reset_calibration(ah, curr_cal);
3403250003Sadrian        /* Poll for offset calibration complete */
3404250003Sadrian        if (!ath_hal_wait(
3405250008Sadrian                ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL, 0))
3406250003Sadrian        {
3407250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3408250003Sadrian                "%s: Cal %d failed to complete in 100ms.\n",
3409250003Sadrian                __func__, curr_cal->cal_data->cal_type);
3410250003Sadrian            /* Re-initialize list pointers for periodic cals */
3411250003Sadrian            ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr
3412250003Sadrian                = AH_NULL;
3413250003Sadrian            return AH_FALSE;
3414250003Sadrian        }
3415250003Sadrian        /* Run this cal */
3416250003Sadrian        ar9300_per_calibration(
3417250003Sadrian            ah, &ichan, ahp->ah_rx_chainmask, curr_cal, &is_cal_done);
3418250003Sadrian        if (is_cal_done == AH_FALSE) {
3419250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3420250003Sadrian                "%s: Not able to run Init Cal %d.\n", __func__,
3421250003Sadrian                curr_cal->cal_data->cal_type);
3422250003Sadrian        }
3423250003Sadrian        if (curr_cal->cal_next) {
3424250003Sadrian            curr_cal = curr_cal->cal_next;
3425250003Sadrian        }
3426250003Sadrian    }
3427250003Sadrian
3428250003Sadrian    /* Re-initialize list pointers for periodic cals */
3429250003Sadrian    ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL;
3430250003Sadrian    return AH_TRUE;
3431250003Sadrian}
3432250003Sadrian
3433250003Sadrian#if 0
3434250003Sadrianstatic void
3435250003Sadrianar9300_tx_carrier_leak_war(struct ath_hal *ah)
3436250003Sadrian{
3437250003Sadrian    unsigned long tx_gain_table_max;
3438250003Sadrian    unsigned long reg_bb_cl_map_0_b0 = 0xffffffff;
3439250003Sadrian    unsigned long reg_bb_cl_map_1_b0 = 0xffffffff;
3440250003Sadrian    unsigned long reg_bb_cl_map_2_b0 = 0xffffffff;
3441250003Sadrian    unsigned long reg_bb_cl_map_3_b0 = 0xffffffff;
3442250003Sadrian    unsigned long tx_gain, cal_run = 0;
3443250003Sadrian    unsigned long cal_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];
3444250003Sadrian    unsigned long cal_gain_index[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];
3445250003Sadrian    unsigned long new_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];
3446250003Sadrian    int i, j;
3447250003Sadrian
3448250003Sadrian    OS_MEMSET(new_gain, 0, sizeof(new_gain));
3449250003Sadrian    /*printf("     Running TxCarrierLeakWAR\n");*/
3450250003Sadrian
3451250003Sadrian    /* process tx gain table, we use cl_map_hw_gen=0. */
3452250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_MAP_HW_GEN, 0);
3453250003Sadrian
3454250003Sadrian	//the table we used is txbb_gc[2:0], 1dB[2:1].
3455250003Sadrian    tx_gain_table_max = OS_REG_READ_FIELD(ah,
3456250003Sadrian        AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX);
3457250003Sadrian
3458250003Sadrian    for (i = 0; i <= tx_gain_table_max; i++) {
3459250003Sadrian        tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4);
3460250003Sadrian        cal_gain[i] = (((tx_gain >> 5)& 0x7) << 2) |
3461250003Sadrian            (((tx_gain >> 1) & 0x3) << 0);
3462250003Sadrian        if (i == 0) {
3463250003Sadrian            cal_gain_index[i] = cal_run;
3464250003Sadrian            new_gain[i] = 1;
3465250003Sadrian            cal_run++;
3466250003Sadrian        } else {
3467250003Sadrian            new_gain[i] = 1;
3468250003Sadrian            for (j = 0; j < i; j++) {
3469250003Sadrian                /*
3470250003Sadrian                printf("i=%d, j=%d cal_gain[$i]=0x%04x\n", i, j, cal_gain[i]);
3471250003Sadrian                 */
3472250003Sadrian                if (new_gain[i]) {
3473250003Sadrian                    if ((cal_gain[i] != cal_gain[j])) {
3474250003Sadrian                        new_gain[i] = 1;
3475250003Sadrian                    } else {
3476250003Sadrian                        /* if old gain found, use old cal_run value. */
3477250003Sadrian                        new_gain[i] = 0;
3478250003Sadrian                        cal_gain_index[i] = cal_gain_index[j];
3479250003Sadrian                    }
3480250003Sadrian                }
3481250003Sadrian            }
3482250003Sadrian            /* if new gain found, increase cal_run */
3483250003Sadrian            if (new_gain[i] == 1) {
3484250003Sadrian                cal_gain_index[i] = cal_run;
3485250003Sadrian                cal_run++;
3486250003Sadrian            }
3487250003Sadrian        }
3488250003Sadrian
3489250003Sadrian        reg_bb_cl_map_0_b0 = (reg_bb_cl_map_0_b0 & ~(0x1 << i)) |
3490250003Sadrian            ((cal_gain_index[i] >> 0 & 0x1) << i);
3491250003Sadrian        reg_bb_cl_map_1_b0 = (reg_bb_cl_map_1_b0 & ~(0x1 << i)) |
3492250003Sadrian            ((cal_gain_index[i] >> 1 & 0x1) << i);
3493250003Sadrian        reg_bb_cl_map_2_b0 = (reg_bb_cl_map_2_b0 & ~(0x1 << i)) |
3494250003Sadrian            ((cal_gain_index[i] >> 2 & 0x1) << i);
3495250003Sadrian        reg_bb_cl_map_3_b0 = (reg_bb_cl_map_3_b0 & ~(0x1 << i)) |
3496250003Sadrian            ((cal_gain_index[i] >> 3 & 0x1) << i);
3497250003Sadrian
3498250003Sadrian        /*
3499250003Sadrian        printf("i=%2d, cal_gain[$i]= 0x%04x, cal_run= %d, "
3500250003Sadrian            "cal_gain_index[i]=%d, new_gain[i] = %d\n",
3501250003Sadrian            i, cal_gain[i], cal_run, cal_gain_index[i], new_gain[i]);
3502250003Sadrian         */
3503250003Sadrian    }
3504250003Sadrian    OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B0, reg_bb_cl_map_0_b0);
3505250003Sadrian    OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B0, reg_bb_cl_map_1_b0);
3506250003Sadrian    OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B0, reg_bb_cl_map_2_b0);
3507250003Sadrian    OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B0, reg_bb_cl_map_3_b0);
3508250003Sadrian    if (AR_SREV_WASP(ah)) {
3509250003Sadrian        OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B1, reg_bb_cl_map_0_b0);
3510250003Sadrian        OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B1, reg_bb_cl_map_1_b0);
3511250003Sadrian        OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B1, reg_bb_cl_map_2_b0);
3512250003Sadrian        OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B1, reg_bb_cl_map_3_b0);
3513250003Sadrian    }
3514250003Sadrian}
3515250003Sadrian#endif
3516250003Sadrian
3517250003Sadrian
3518250003Sadrianstatic inline void
3519250003Sadrianar9300_invalidate_saved_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
3520250003Sadrian{
3521250003Sadrian#if ATH_SUPPORT_CAL_REUSE
3522250003Sadrian    if (AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse &
3523250003Sadrian        ATH_CAL_REUSE_REDO_IN_FULL_RESET)
3524250003Sadrian    {
3525250003Sadrian        ichan->one_time_txiqcal_done = AH_FALSE;
3526250003Sadrian        ichan->one_time_txclcal_done = AH_FALSE;
3527250003Sadrian    }
3528250003Sadrian#endif
3529250003Sadrian}
3530250003Sadrian
3531250003Sadrianstatic inline HAL_BOOL
3532250003Sadrianar9300_restore_rtt_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
3533250003Sadrian{
3534250003Sadrian    HAL_BOOL restore_status = AH_FALSE;
3535250003Sadrian
3536250003Sadrian    return restore_status;
3537250003Sadrian}
3538250003Sadrian
3539250003Sadrian/* ar9300_init_cal
3540250003Sadrian * Initialize Calibration infrastructure
3541250003Sadrian */
3542250003Sadrianstatic inline HAL_BOOL
3543250008Sadrianar9300_init_cal_internal(struct ath_hal *ah, struct ieee80211_channel *chan,
3544250008Sadrian                         HAL_CHANNEL_INTERNAL *ichan,
3545250008Sadrian                         HAL_BOOL enable_rtt, HAL_BOOL do_rtt_cal, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr)
3546250003Sadrian{
3547250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
3548250003Sadrian    HAL_BOOL txiqcal_success_flag = AH_FALSE;
3549250003Sadrian    HAL_BOOL cal_done = AH_FALSE;
3550250003Sadrian    int iqcal_idx = 0;
3551250003Sadrian    HAL_BOOL do_sep_iq_cal = AH_FALSE;
3552250003Sadrian    HAL_BOOL do_agc_cal = do_rtt_cal;
3553250003Sadrian    HAL_BOOL is_cal_reusable = AH_TRUE;
3554250003Sadrian#if ATH_SUPPORT_CAL_REUSE
3555250003Sadrian    HAL_BOOL      cal_reuse_enable = AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse &
3556250003Sadrian                                 ATH_CAL_REUSE_ENABLE;
3557250003Sadrian    HAL_BOOL      clc_success = AH_FALSE;
3558250003Sadrian    int32_t   ch_idx, j, cl_tab_reg;
3559250003Sadrian    u_int32_t BB_cl_tab_entry = MAX_BB_CL_TABLE_ENTRY;
3560250003Sadrian    u_int32_t BB_cl_tab_b[AR9300_MAX_CHAINS] = {
3561250003Sadrian                    AR_PHY_CL_TAB_0,
3562250003Sadrian                    AR_PHY_CL_TAB_1,
3563250003Sadrian                    AR_PHY_CL_TAB_2
3564250003Sadrian                };
3565250003Sadrian#endif
3566250003Sadrian
3567250003Sadrian    if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
3568250003Sadrian        /* Hornet: 1 x 1 */
3569250003Sadrian        ahp->ah_rx_cal_chainmask = 0x1;
3570250003Sadrian        ahp->ah_tx_cal_chainmask = 0x1;
3571291437Sadrian    } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(ah)) {
3572250003Sadrian        /* Wasp/Jupiter: 2 x 2 */
3573250003Sadrian        ahp->ah_rx_cal_chainmask = 0x3;
3574250003Sadrian        ahp->ah_tx_cal_chainmask = 0x3;
3575250003Sadrian    } else {
3576250003Sadrian        /*
3577250003Sadrian         * Osprey needs to be configured for the correct chain mode
3578250003Sadrian         * before running AGC/TxIQ cals.
3579250003Sadrian         */
3580250003Sadrian        if (ahp->ah_enterprise_mode & AR_ENT_OTP_CHAIN2_DISABLE) {
3581250003Sadrian            /* chain 2 disabled - 2 chain mode */
3582250003Sadrian            ahp->ah_rx_cal_chainmask = 0x3;
3583250003Sadrian            ahp->ah_tx_cal_chainmask = 0x3;
3584250003Sadrian        } else {
3585250003Sadrian            ahp->ah_rx_cal_chainmask = 0x7;
3586250003Sadrian            ahp->ah_tx_cal_chainmask = 0x7;
3587250003Sadrian        }
3588250003Sadrian    }
3589250003Sadrian        ar9300_init_chain_masks(ah, ahp->ah_rx_cal_chainmask, ahp->ah_tx_cal_chainmask);
3590250003Sadrian
3591250003Sadrian
3592250003Sadrian    if (ahp->tx_cl_cal_enable) {
3593250003Sadrian#if ATH_SUPPORT_CAL_REUSE
3594250003Sadrian        /* disable Carrie Leak or set do_agc_cal accordingly */
3595250003Sadrian        if (cal_reuse_enable && ichan->one_time_txclcal_done)
3596250003Sadrian        {
3597250003Sadrian            OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
3598250003Sadrian        } else
3599250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */
3600250003Sadrian        {
3601250003Sadrian            OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
3602250003Sadrian            do_agc_cal = AH_TRUE;
3603250003Sadrian        }
3604250003Sadrian    }
3605250003Sadrian
3606250003Sadrian    /* Do Tx IQ Calibration here for osprey hornet and wasp */
3607250003Sadrian    /* XXX: For initial wasp bringup - check and enable this */
3608250003Sadrian    /* EV 74233: Tx IQ fails to complete for half/quarter rates */
3609250008Sadrian    if (!(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) {
3610250003Sadrian        if (ahp->tx_iq_cal_enable) {
3611250003Sadrian            /* this should be eventually moved to INI file */
3612250003Sadrian            OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah),
3613250003Sadrian                AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT);
3614250003Sadrian
3615250003Sadrian            /*
3616250003Sadrian             * For poseidon and later chips,
3617250003Sadrian             * Tx IQ cal HW run will be a part of AGC calibration
3618250003Sadrian             */
3619250003Sadrian            if (ahp->tx_iq_cal_during_agc_cal) {
3620250003Sadrian                /*
3621250003Sadrian                 * txiqcal_success_flag always set to 1 to run
3622250003Sadrian                 *     ar9300_tx_iq_cal_post_proc
3623250003Sadrian                 * if following AGC cal passes
3624250003Sadrian                */
3625250003Sadrian#if ATH_SUPPORT_CAL_REUSE
3626250003Sadrian                if (!cal_reuse_enable || !ichan->one_time_txiqcal_done)
3627250003Sadrian                {
3628250003Sadrian                    txiqcal_success_flag = AH_TRUE;
3629250003Sadrian                    OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),
3630250003Sadrian                        OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) |
3631250003Sadrian                        AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
3632250003Sadrian                } else {
3633250003Sadrian                    OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),
3634250003Sadrian                        OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) &
3635250003Sadrian                        (~AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL));
3636250003Sadrian                }
3637250003Sadrian#else
3638250003Sadrian		if (OS_REG_READ_FIELD(ah,
3639250003Sadrian					AR_PHY_TX_IQCAL_CONTROL_0(ah),
3640250003Sadrian					AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)){
3641250003Sadrian			if (apply_last_iqcorr == AH_TRUE) {
3642250003Sadrian				OS_REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),
3643250003Sadrian						AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
3644250003Sadrian				txiqcal_success_flag = AH_FALSE;
3645250003Sadrian			} else {
3646250003Sadrian				txiqcal_success_flag = AH_TRUE;
3647250003Sadrian			}
3648250003Sadrian		}else{
3649250003Sadrian			txiqcal_success_flag = AH_FALSE;
3650250003Sadrian		}
3651250003Sadrian#endif
3652250003Sadrian                if (txiqcal_success_flag) {
3653250003Sadrian                    do_agc_cal = AH_TRUE;
3654250003Sadrian                }
3655250003Sadrian            } else
3656250003Sadrian#if ATH_SUPPORT_CAL_REUSE
3657250003Sadrian            if (!cal_reuse_enable || !ichan->one_time_txiqcal_done)
3658250003Sadrian#endif
3659250003Sadrian            {
3660250003Sadrian                do_sep_iq_cal = AH_TRUE;
3661250003Sadrian                do_agc_cal = AH_TRUE;
3662250003Sadrian            }
3663250003Sadrian        }
3664250003Sadrian    }
3665250003Sadrian
3666250003Sadrian#if ATH_SUPPORT_MCI
3667250008Sadrian    if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&
3668250003Sadrian        IS_CHAN_2GHZ(ichan) &&
3669250003Sadrian        (ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&
3670250003Sadrian        do_agc_cal &&
3671250008Sadrian        !(ah->ah_config.ath_hal_mci_config &
3672250003Sadrian        ATH_MCI_CONFIG_DISABLE_MCI_CAL))
3673250003Sadrian    {
3674250003Sadrian        u_int32_t payload[4] = {0, 0, 0, 0};
3675250003Sadrian
3676250003Sadrian        /* Send CAL_REQ only when BT is AWAKE. */
3677250003Sadrian        HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_REQ 0x%X\n",
3678250003Sadrian            __func__, ahp->ah_mci_wlan_cal_seq);
3679250003Sadrian        MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_REQ);
3680250003Sadrian        payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_seq++;
3681250003Sadrian        ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);
3682250003Sadrian
3683250003Sadrian        /* Wait BT_CAL_GRANT for 50ms */
3684250003Sadrian        HALDEBUG(ah, HAL_DEBUG_BT_COEX,
3685250003Sadrian            "(MCI) %s: Wait for BT_CAL_GRANT\n", __func__);
3686250003Sadrian        if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000))
3687250003Sadrian        {
3688250003Sadrian            HALDEBUG(ah, HAL_DEBUG_BT_COEX,
3689250003Sadrian                "(MCI) %s: Got BT_CAL_GRANT.\n", __func__);
3690250003Sadrian        }
3691250003Sadrian        else {
3692250003Sadrian            is_cal_reusable = AH_FALSE;
3693250003Sadrian            HALDEBUG(ah, HAL_DEBUG_BT_COEX,
3694250003Sadrian                "(MCI) %s: BT is not responding.\n", __func__);
3695250003Sadrian        }
3696250003Sadrian    }
3697250003Sadrian#endif /* ATH_SUPPORT_MCI */
3698250003Sadrian
3699250003Sadrian    if (do_sep_iq_cal)
3700250003Sadrian    {
3701250003Sadrian        /* enable Tx IQ Calibration HW for osprey/hornet/wasp */
3702250003Sadrian        txiqcal_success_flag = ar9300_tx_iq_cal_hw_run(ah);
3703250003Sadrian        OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
3704250003Sadrian        OS_DELAY(5);
3705250003Sadrian        OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
3706250003Sadrian    }
3707250003Sadrian#if 0
3708250003Sadrian    if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
3709250003Sadrian        ar9300_tx_carrier_leak_war(ah);
3710250003Sadrian    }
3711250003Sadrian#endif
3712250003Sadrian    /*
3713250003Sadrian     * Calibrate the AGC
3714250003Sadrian     *
3715250003Sadrian     * Tx IQ cal is a part of AGC cal for Jupiter/Poseidon, etc.
3716250003Sadrian     * please enable the bit of txiqcal_control_0[31] in INI file
3717250003Sadrian     * for Jupiter/Poseidon/etc.
3718250003Sadrian     */
3719250003Sadrian    if(!AR_SREV_SCORPION(ah)) {
3720250003Sadrian        if (do_agc_cal || !skip_if_none) {
3721250003Sadrian            OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
3722250003Sadrian                OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
3723250003Sadrian
3724250003Sadrian            /* Poll for offset calibration complete */
3725250003Sadrian            cal_done = ath_hal_wait(ah,
3726250008Sadrian                    AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0);
3727250003Sadrian            if (!cal_done) {
3728250003Sadrian                HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
3729250003Sadrian                    "(FCS) CAL NOT DONE!!! - %d\n", ichan->channel);
3730250003Sadrian            }
3731250003Sadrian        } else {
3732250003Sadrian            cal_done = AH_TRUE;
3733250003Sadrian        }
3734250003Sadrian            /*
3735250003Sadrian             * Tx IQ cal post-processing in SW
3736250003Sadrian             * This part of code should be common to all chips,
3737250003Sadrian             * no chip specific code for Jupiter/Posdeion except for register names.
3738250003Sadrian             */
3739250003Sadrian            if (txiqcal_success_flag) {
3740251098Sadrian                ar9300_tx_iq_cal_post_proc(ah,ichan, 1, 1,is_cal_reusable, AH_FALSE);
3741250003Sadrian            }
3742250003Sadrian    } else {
3743250003Sadrian        if (!txiqcal_success_flag) {
3744250003Sadrian            OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
3745250003Sadrian                OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
3746250008Sadrian            if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
3747250008Sadrian                    0)) {
3748250003Sadrian                HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3749250003Sadrian                    "%s: offset calibration failed to complete in 1ms; "
3750250003Sadrian                    "noisy environment?\n", __func__);
3751250003Sadrian                return AH_FALSE;
3752250003Sadrian            }
3753250003Sadrian            if (apply_last_iqcorr == AH_TRUE) {
3754250003Sadrian                ar9300_tx_iq_cal_post_proc(ah, ichan, 0, 0, is_cal_reusable, AH_TRUE);
3755250003Sadrian            }
3756250003Sadrian        } else {
3757250003Sadrian            for (iqcal_idx=0;iqcal_idx<MAXIQCAL;iqcal_idx++) {
3758250003Sadrian                OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
3759250003Sadrian                    OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
3760250003Sadrian
3761250003Sadrian                /* Poll for offset calibration complete */
3762250003Sadrian                if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL,
3763250008Sadrian                        AR_PHY_AGC_CONTROL_CAL, 0)) {
3764250003Sadrian                    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3765250003Sadrian                        "%s: offset calibration failed to complete in 1ms; "
3766250003Sadrian                        "noisy environment?\n", __func__);
3767250003Sadrian                    return AH_FALSE;
3768250003Sadrian                }
3769250003Sadrian                /*
3770250003Sadrian                 * Tx IQ cal post-processing in SW
3771250003Sadrian                 * This part of code should be common to all chips,
3772250003Sadrian                 * no chip specific code for Jupiter/Posdeion except for register names.
3773250003Sadrian                 */
3774250003Sadrian                ar9300_tx_iq_cal_post_proc(ah, ichan, iqcal_idx+1, MAXIQCAL, is_cal_reusable, AH_FALSE);
3775250003Sadrian            }
3776250003Sadrian       }
3777250003Sadrian    }
3778250003Sadrian
3779250003Sadrian
3780250003Sadrian#if ATH_SUPPORT_MCI
3781250008Sadrian    if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&
3782250003Sadrian        IS_CHAN_2GHZ(ichan) &&
3783250003Sadrian        (ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&
3784250003Sadrian        do_agc_cal &&
3785250008Sadrian        !(ah->ah_config.ath_hal_mci_config &
3786250003Sadrian        ATH_MCI_CONFIG_DISABLE_MCI_CAL))
3787250003Sadrian    {
3788250003Sadrian        u_int32_t payload[4] = {0, 0, 0, 0};
3789250003Sadrian
3790250003Sadrian        HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_DONE 0x%X\n",
3791250003Sadrian            __func__, ahp->ah_mci_wlan_cal_done);
3792250003Sadrian        MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
3793250003Sadrian        payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_done++;
3794250003Sadrian        ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);
3795250003Sadrian    }
3796250003Sadrian#endif /* ATH_SUPPORT_MCI */
3797250003Sadrian
3798250003Sadrian
3799250003Sadrian    if (!cal_done && !AR_SREV_SCORPION(ah) )
3800250003Sadrian    {
3801250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3802250003Sadrian            "%s: offset calibration failed to complete in 1ms; "
3803250003Sadrian            "noisy environment?\n", __func__);
3804250003Sadrian        return AH_FALSE;
3805250003Sadrian    }
3806250003Sadrian
3807250003Sadrian#if 0
3808250003Sadrian     /* Beacon stuck fix, refer to EV 120056 */
3809250003Sadrian    if(IS_CHAN_2GHZ(chan) && AR_SREV_SCORPION(ah))
3810250003Sadrian        OS_REG_WRITE(ah, AR_PHY_TIMING5, OS_REG_READ(ah,AR_PHY_TIMING5) & ~AR_PHY_TIMING5_CYCPWR_THR1_ENABLE);
3811250003Sadrian#endif
3812250003Sadrian
3813250003Sadrian#if 0
3814250003Sadrian    /* Do PA Calibration */
3815250003Sadrian    if (AR_SREV_KITE(ah) && AR_SREV_KITE_11_OR_LATER(ah)) {
3816250003Sadrian        ar9285_pa_cal(ah);
3817250003Sadrian    }
3818250003Sadrian#endif
3819250003Sadrian
3820250003Sadrian#if ATH_SUPPORT_CAL_REUSE
3821250003Sadrian     if (ichan->one_time_txiqcal_done) {
3822250003Sadrian        ar9300_tx_iq_cal_apply(ah, ichan);
3823250003Sadrian        HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
3824250003Sadrian            "(FCS) TXIQCAL applied - %d\n", ichan->channel);
3825250003Sadrian    }
3826250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */
3827250003Sadrian
3828250003Sadrian#if ATH_SUPPORT_CAL_REUSE
3829250003Sadrian    if (cal_reuse_enable && ahp->tx_cl_cal_enable)
3830250003Sadrian    {
3831250003Sadrian        clc_success = (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) &
3832250003Sadrian                  AR_PHY_AGC_CONTROL_CLC_SUCCESS) ? 1 : 0;
3833250003Sadrian
3834250003Sadrian        if (ichan->one_time_txclcal_done)
3835250003Sadrian        {
3836250003Sadrian            /* reapply CL cal results */
3837250003Sadrian            for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {
3838250003Sadrian                if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {
3839250003Sadrian                    continue;
3840250003Sadrian                }
3841250003Sadrian                cl_tab_reg = BB_cl_tab_b[ch_idx];
3842250003Sadrian                for (j = 0; j < BB_cl_tab_entry; j++) {
3843250003Sadrian                    OS_REG_WRITE(ah, cl_tab_reg, ichan->tx_clcal[ch_idx][j]);
3844250003Sadrian                    cl_tab_reg += 4;;
3845250003Sadrian                }
3846250003Sadrian            }
3847250003Sadrian            HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
3848250003Sadrian                "(FCS) TX CL CAL applied - %d\n", ichan->channel);
3849250003Sadrian        }
3850250003Sadrian        else if (is_cal_reusable && clc_success) {
3851250003Sadrian            /* save CL cal results */
3852250003Sadrian            for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {
3853250003Sadrian                if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {
3854250003Sadrian                    continue;
3855250003Sadrian                }
3856250003Sadrian                cl_tab_reg = BB_cl_tab_b[ch_idx];
3857250003Sadrian                for (j = 0; j < BB_cl_tab_entry; j++) {
3858250003Sadrian                    ichan->tx_clcal[ch_idx][j] = OS_REG_READ(ah, cl_tab_reg);
3859250003Sadrian                    cl_tab_reg += 4;
3860250003Sadrian                }
3861250003Sadrian            }
3862250003Sadrian            ichan->one_time_txclcal_done = AH_TRUE;
3863250003Sadrian            HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
3864250003Sadrian                "(FCS) TX CL CAL saved - %d\n", ichan->channel);
3865250003Sadrian        }
3866250003Sadrian    }
3867250003Sadrian#endif /* ATH_SUPPORT_CAL_REUSE */
3868250003Sadrian
3869250003Sadrian    /* Revert chainmasks to their original values before NF cal */
3870250003Sadrian    ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask);
3871250003Sadrian
3872250003Sadrian#if !FIX_NOISE_FLOOR
3873250003Sadrian    /*
3874250003Sadrian     * Do NF calibration after DC offset and other CALs.
3875250003Sadrian     * Per system engineers, noise floor value can sometimes be 20 dB
3876250003Sadrian     * higher than normal value if DC offset and noise floor cal are
3877250003Sadrian     * triggered at the same time.
3878250003Sadrian     */
3879250003Sadrian    OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
3880250003Sadrian        OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
3881250003Sadrian#endif
3882250003Sadrian
3883250003Sadrian    /* Initialize list pointers */
3884250003Sadrian    ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL;
3885250003Sadrian
3886250003Sadrian    /*
3887250003Sadrian     * Enable IQ, ADC Gain, ADC DC Offset Cals
3888250003Sadrian     */
3889250003Sadrian    /* Setup all non-periodic, init time only calibrations */
3890250003Sadrian    /* XXX: Init DC Offset not working yet */
3891250003Sadrian#ifdef not_yet
3892250003Sadrian    if (AH_TRUE == ar9300_is_cal_supp(ah, chan, ADC_DC_INIT_CAL)) {
3893250003Sadrian        INIT_CAL(&ahp->ah_adc_dc_cal_init_data);
3894250003Sadrian        INSERT_CAL(ahp, &ahp->ah_adc_dc_cal_init_data);
3895250003Sadrian    }
3896250003Sadrian
3897250003Sadrian    /* Initialize current pointer to first element in list */
3898250003Sadrian    ahp->ah_cal_list_curr = ahp->ah_cal_list;
3899250003Sadrian
3900250003Sadrian    if (ahp->ah_cal_list_curr) {
3901250003Sadrian        if (ar9300_run_init_cals(ah, 0) == AH_FALSE) {
3902250003Sadrian            return AH_FALSE;
3903250003Sadrian        }
3904250003Sadrian    }
3905250003Sadrian#endif
3906250003Sadrian    /* end - Init time calibrations */
3907250003Sadrian
3908278741Sadrian    /* Do not do RX cal in case of offchan, or cal data already exists on same channel*/
3909278741Sadrian    if (ahp->ah_skip_rx_iq_cal) {
3910278741Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3911278741Sadrian                "Skip RX IQ Cal\n");
3912278741Sadrian        return AH_TRUE;
3913278741Sadrian    }
3914278741Sadrian
3915250003Sadrian    /* If Cals are supported, add them to list via INIT/INSERT_CAL */
3916250003Sadrian    if (AH_TRUE == ar9300_is_cal_supp(ah, chan, IQ_MISMATCH_CAL)) {
3917250003Sadrian        INIT_CAL(&ahp->ah_iq_cal_data);
3918250003Sadrian        INSERT_CAL(ahp, &ahp->ah_iq_cal_data);
3919250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3920250003Sadrian            "%s: enabling IQ Calibration.\n", __func__);
3921250003Sadrian    }
3922250003Sadrian    if (AH_TRUE == ar9300_is_cal_supp(ah, chan, TEMP_COMP_CAL)) {
3923250003Sadrian        INIT_CAL(&ahp->ah_temp_comp_cal_data);
3924250003Sadrian        INSERT_CAL(ahp, &ahp->ah_temp_comp_cal_data);
3925250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3926250003Sadrian            "%s: enabling Temperature Compensation Calibration.\n", __func__);
3927250003Sadrian    }
3928250003Sadrian
3929250003Sadrian    /* Initialize current pointer to first element in list */
3930250003Sadrian    ahp->ah_cal_list_curr = ahp->ah_cal_list;
3931250003Sadrian
3932250003Sadrian    /* Reset state within current cal */
3933250003Sadrian    if (ahp->ah_cal_list_curr) {
3934250003Sadrian        ar9300_reset_calibration(ah, ahp->ah_cal_list_curr);
3935250003Sadrian    }
3936250003Sadrian
3937250003Sadrian    /* Mark all calibrations on this channel as being invalid */
3938250008Sadrian    ichan->calValid = 0;
3939250003Sadrian
3940250003Sadrian    return AH_TRUE;
3941250003Sadrian}
3942250003Sadrian
3943250003Sadrianstatic inline HAL_BOOL
3944250008Sadrianar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr)
3945250003Sadrian{
3946250003Sadrian    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
3947250003Sadrian    HAL_BOOL do_rtt_cal = AH_TRUE;
3948250003Sadrian    HAL_BOOL enable_rtt = AH_FALSE;
3949250003Sadrian
3950250003Sadrian    HALASSERT(ichan);
3951250003Sadrian
3952250003Sadrian    return ar9300_init_cal_internal(ah, chan, ichan, enable_rtt, do_rtt_cal, skip_if_none, apply_last_iqcorr);
3953250003Sadrian}
3954250003Sadrian
3955250003Sadrian/* ar9300_reset_cal_valid
3956250003Sadrian * Entry point for upper layers to restart current cal.
3957250003Sadrian * Reset the calibration valid bit in channel.
3958250003Sadrian */
3959250003Sadrianvoid
3960250008Sadrianar9300_reset_cal_valid(struct ath_hal *ah, const struct ieee80211_channel *chan,
3961250003Sadrian    HAL_BOOL *is_cal_done, u_int32_t cal_type)
3962250003Sadrian{
3963250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
3964250003Sadrian    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
3965250003Sadrian    HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr;
3966250003Sadrian
3967250003Sadrian    *is_cal_done = AH_TRUE;
3968250003Sadrian
3969250003Sadrian    if (curr_cal == AH_NULL) {
3970250003Sadrian        return;
3971250003Sadrian    }
3972250003Sadrian    if (ichan == AH_NULL) {
3973250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3974250003Sadrian            "%s: invalid channel %u/0x%x; no mapping\n",
3975250008Sadrian            __func__, chan->ic_freq, chan->ic_flags);
3976250003Sadrian        return;
3977250003Sadrian    }
3978250003Sadrian
3979250003Sadrian    if (!(cal_type & IQ_MISMATCH_CAL)) {
3980250003Sadrian        *is_cal_done = AH_FALSE;
3981250003Sadrian        return;
3982250003Sadrian    }
3983250003Sadrian
3984250003Sadrian    /* Expected that this calibration has run before, post-reset.
3985250003Sadrian     * Current state should be done
3986250003Sadrian     */
3987250003Sadrian    if (curr_cal->cal_state != CAL_DONE) {
3988250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3989250003Sadrian            "%s: Calibration state incorrect, %d\n",
3990250003Sadrian            __func__, curr_cal->cal_state);
3991250003Sadrian        return;
3992250003Sadrian    }
3993250003Sadrian
3994250003Sadrian    /* Verify Cal is supported on this channel */
3995250003Sadrian    if (ar9300_is_cal_supp(ah, chan, curr_cal->cal_data->cal_type) == AH_FALSE) {
3996250003Sadrian        return;
3997250003Sadrian    }
3998250003Sadrian
3999250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
4000250003Sadrian        "%s: Resetting Cal %d state for channel %u/0x%x\n", __func__,
4001250008Sadrian        curr_cal->cal_data->cal_type, chan->ic_freq, chan->ic_flags);
4002250003Sadrian
4003250003Sadrian    /* Disable cal validity in channel */
4004250008Sadrian    ichan->calValid &= ~curr_cal->cal_data->cal_type;
4005250003Sadrian    curr_cal->cal_state = CAL_WAITING;
4006250003Sadrian    /* Indicate to upper layers that we need polling */
4007250003Sadrian    *is_cal_done = AH_FALSE;
4008250003Sadrian}
4009250003Sadrian
4010250003Sadrianstatic inline void
4011250003Sadrianar9300_set_dma(struct ath_hal *ah)
4012250003Sadrian{
4013250003Sadrian    u_int32_t   regval;
4014250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
4015278741Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
4016278741Sadrian    HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
4017250003Sadrian
4018250003Sadrian#if 0
4019250003Sadrian    /*
4020250003Sadrian     * set AHB_MODE not to do cacheline prefetches
4021250003Sadrian     */
4022250003Sadrian    regval = OS_REG_READ(ah, AR_AHB_MODE);
4023250003Sadrian    OS_REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
4024250003Sadrian#endif
4025250003Sadrian
4026250003Sadrian    /*
4027250003Sadrian     * let mac dma reads be in 128 byte chunks
4028250003Sadrian     */
4029250003Sadrian    regval = OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
4030250003Sadrian    OS_REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
4031250003Sadrian
4032250003Sadrian    /*
4033250003Sadrian     * Restore TX Trigger Level to its pre-reset value.
4034250003Sadrian     * The initial value depends on whether aggregation is enabled, and is
4035250003Sadrian     * adjusted whenever underruns are detected.
4036250003Sadrian     */
4037250003Sadrian    /*
4038250003Sadrian    OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, AH_PRIVATE(ah)->ah_tx_trig_level);
4039250003Sadrian     */
4040250003Sadrian    /*
4041250003Sadrian     * Osprey 1.0 bug (EV 61936). Don't change trigger level from .ini default.
4042250003Sadrian     * Osprey 2.0 - hardware recommends using the default INI settings.
4043250003Sadrian     */
4044250003Sadrian#if 0
4045250003Sadrian    OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, 0x3f);
4046250003Sadrian#endif
4047250003Sadrian    /*
4048250003Sadrian     * let mac dma writes be in 128 byte chunks
4049250003Sadrian     */
4050250003Sadrian    regval = OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
4051250003Sadrian    OS_REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
4052250003Sadrian
4053250003Sadrian    /*
4054250003Sadrian     * Setup receive FIFO threshold to hold off TX activities
4055250003Sadrian     */
4056250003Sadrian    OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
4057250003Sadrian
4058250003Sadrian    /*
4059250003Sadrian     * reduce the number of usable entries in PCU TXBUF to avoid
4060250003Sadrian     * wrap around bugs. (bug 20428)
4061250003Sadrian     */
4062250003Sadrian
4063250003Sadrian    if (AR_SREV_WASP(ah) &&
4064250003Sadrian        (AH_PRIVATE((ah))->ah_macRev > AR_SREV_REVISION_WASP_12)) {
4065250003Sadrian        /* Wasp 1.3 fix for EV#85395 requires usable entries
4066250003Sadrian         * to be set to 0x500
4067250003Sadrian         */
4068250003Sadrian        OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, 0x500);
4069250003Sadrian    } else {
4070250003Sadrian        OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE);
4071250003Sadrian    }
4072250003Sadrian
4073250003Sadrian    /*
4074250003Sadrian     * Enable HPQ for UAPSD
4075250003Sadrian     */
4076278741Sadrian    if (pCap->halHwUapsdTrig == AH_TRUE) {
4077278741Sadrian    /* Only enable this if HAL capabilities says it is OK */
4078278741Sadrian        if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
4079278741Sadrian            OS_REG_WRITE(ah, AR_HP_Q_CONTROL,
4080278741Sadrian                    AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN);
4081278741Sadrian        }
4082278741Sadrian    } else {
4083278741Sadrian        /* use default value from ini file - which disable HPQ queue usage */
4084250003Sadrian    }
4085250003Sadrian
4086250003Sadrian    /*
4087250003Sadrian     * set the transmit status ring
4088250003Sadrian     */
4089250003Sadrian    ar9300_reset_tx_status_ring(ah);
4090250003Sadrian
4091250003Sadrian    /*
4092250003Sadrian     * set rxbp threshold.  Must be non-zero for RX_EOL to occur.
4093250003Sadrian     * For Osprey 2.0+, keep the original thresholds
4094250003Sadrian     * otherwise performance is lost due to excessive RX EOL interrupts.
4095250003Sadrian     */
4096250003Sadrian    OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1);
4097250003Sadrian    OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1);
4098250003Sadrian
4099250003Sadrian    /*
4100250003Sadrian     * set receive buffer size.
4101250003Sadrian     */
4102250003Sadrian    if (ahp->rx_buf_size) {
4103250003Sadrian        OS_REG_WRITE(ah, AR_DATABUF, ahp->rx_buf_size);
4104250003Sadrian    }
4105250003Sadrian}
4106250003Sadrian
4107250003Sadrianstatic inline void
4108250008Sadrianar9300_init_bb(struct ath_hal *ah, struct ieee80211_channel *chan)
4109250003Sadrian{
4110250003Sadrian    u_int32_t synth_delay;
4111250003Sadrian
4112250003Sadrian    /*
4113250003Sadrian     * Wait for the frequency synth to settle (synth goes on
4114250003Sadrian     * via AR_PHY_ACTIVE_EN).  Read the phy active delay register.
4115250003Sadrian     * Value is in 100ns increments.
4116250003Sadrian     */
4117250003Sadrian    synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
4118250008Sadrian    if (IEEE80211_IS_CHAN_CCK(chan)) {
4119250003Sadrian        synth_delay = (4 * synth_delay) / 22;
4120250003Sadrian    } else {
4121250003Sadrian        synth_delay /= 10;
4122250003Sadrian    }
4123250003Sadrian
4124250003Sadrian    /* Activate the PHY (includes baseband activate + synthesizer on) */
4125250003Sadrian    OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
4126250003Sadrian
4127250003Sadrian    /*
4128250003Sadrian     * There is an issue if the AP starts the calibration before
4129250003Sadrian     * the base band timeout completes.  This could result in the
4130291437Sadrian     * rx_clear false triggering.  As a workaround we add delay an
4131250003Sadrian     * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
4132250003Sadrian     * does not happen.
4133250003Sadrian     */
4134250003Sadrian    OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY);
4135250003Sadrian}
4136250003Sadrian
4137250003Sadrianstatic inline void
4138250003Sadrianar9300_init_interrupt_masks(struct ath_hal *ah, HAL_OPMODE opmode)
4139250003Sadrian{
4140250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
4141250003Sadrian    u_int32_t msi_cfg = 0;
4142250003Sadrian    u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT;
4143250003Sadrian
4144250003Sadrian    /*
4145250003Sadrian     * Setup interrupt handling.  Note that ar9300_reset_tx_queue
4146250003Sadrian     * manipulates the secondary IMR's as queues are enabled
4147250003Sadrian     * and disabled.  This is done with RMW ops to insure the
4148250003Sadrian     * settings we make here are preserved.
4149250003Sadrian     */
4150250003Sadrian    ahp->ah_mask_reg =
4151250003Sadrian        AR_IMR_TXERR | AR_IMR_TXURN |
4152250003Sadrian        AR_IMR_RXERR | AR_IMR_RXORN |
4153250003Sadrian        AR_IMR_BCNMISC;
4154250003Sadrian
4155250003Sadrian    if (ahp->ah_intr_mitigation_rx) {
4156250003Sadrian        /* enable interrupt mitigation for rx */
4157250003Sadrian        ahp->ah_mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR | AR_IMR_RXOK_HP;
4158250003Sadrian        msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR;
4159250003Sadrian    } else {
4160250003Sadrian        ahp->ah_mask_reg |= AR_IMR_RXOK_LP | AR_IMR_RXOK_HP;
4161250003Sadrian        msi_cfg |= AR_INTCFG_MSI_RXOK;
4162250003Sadrian    }
4163250003Sadrian    if (ahp->ah_intr_mitigation_tx) {
4164250003Sadrian        /* enable interrupt mitigation for tx */
4165250003Sadrian        ahp->ah_mask_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR;
4166250003Sadrian        msi_cfg |= AR_INTCFG_MSI_TXINTM | AR_INTCFG_MSI_TXMINTR;
4167250003Sadrian    } else {
4168250003Sadrian        ahp->ah_mask_reg |= AR_IMR_TXOK;
4169250003Sadrian        msi_cfg |= AR_INTCFG_MSI_TXOK;
4170250003Sadrian    }
4171250003Sadrian    if (opmode == HAL_M_HOSTAP) {
4172250003Sadrian        ahp->ah_mask_reg |= AR_IMR_MIB;
4173250003Sadrian    }
4174250003Sadrian
4175250003Sadrian    OS_REG_WRITE(ah, AR_IMR, ahp->ah_mask_reg);
4176250003Sadrian    OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
4177250003Sadrian    ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2);
4178250003Sadrian
4179250008Sadrian    if (ah->ah_config.ath_hal_enable_msi) {
4180250003Sadrian        /* Cache MSI register value */
4181250003Sadrian        ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI));
4182250003Sadrian        ahp->ah_msi_reg |= AR_PCIE_MSI_HW_DBI_WR_EN;
4183250003Sadrian        if (AR_SREV_POSEIDON(ah)) {
4184250003Sadrian            ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64;
4185250003Sadrian        } else {
4186250003Sadrian            ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR;
4187250003Sadrian        }
4188250003Sadrian        /* Program MSI configuration */
4189250003Sadrian        OS_REG_WRITE(ah, AR_INTCFG, msi_cfg);
4190250003Sadrian    }
4191250003Sadrian
4192250003Sadrian    /*
4193250003Sadrian     * debug - enable to see all synchronous interrupts status
4194250003Sadrian     */
4195250003Sadrian    /* Clear any pending sync cause interrupts */
4196250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE), 0xFFFFFFFF);
4197250003Sadrian
4198250003Sadrian    /* Allow host interface sync interrupt sources to set cause bit */
4199250003Sadrian    if (AR_SREV_POSEIDON(ah)) {
4200250003Sadrian        sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR;
4201250003Sadrian    }
4202250003Sadrian    else if (AR_SREV_WASP(ah)) {
4203250003Sadrian        sync_en_def = AR9340_INTR_SYNC_DEFAULT;
4204250003Sadrian    }
4205250003Sadrian    OS_REG_WRITE(ah,
4206250003Sadrian        AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), sync_en_def);
4207250003Sadrian
4208250003Sadrian    /* _Disable_ host interface sync interrupt when cause bits set */
4209250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 0);
4210250003Sadrian
4211250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0);
4212250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 0);
4213250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE), 0);
4214250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK), 0);
4215250003Sadrian}
4216250003Sadrian
4217250003Sadrianstatic inline void
4218250003Sadrianar9300_init_qos(struct ath_hal *ah)
4219250003Sadrian{
4220250003Sadrian    OS_REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);  /* XXX magic */
4221250003Sadrian    OS_REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);    /* XXX magic */
4222250003Sadrian
4223250003Sadrian    /* Turn on NOACK Support for QoS packets */
4224250003Sadrian    OS_REG_WRITE(ah, AR_QOS_NO_ACK,
4225250003Sadrian        SM(2, AR_QOS_NO_ACK_TWO_BIT) |
4226250003Sadrian        SM(5, AR_QOS_NO_ACK_BIT_OFF) |
4227250003Sadrian        SM(0, AR_QOS_NO_ACK_BYTE_OFF));
4228250003Sadrian
4229250003Sadrian    /*
4230250003Sadrian     * initialize TXOP for all TIDs
4231250003Sadrian     */
4232250003Sadrian    OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
4233250003Sadrian    OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
4234250003Sadrian    OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
4235250003Sadrian    OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
4236250003Sadrian    OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
4237250003Sadrian}
4238250003Sadrian
4239250003Sadrianstatic inline void
4240250003Sadrianar9300_init_user_settings(struct ath_hal *ah)
4241250003Sadrian{
4242250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
4243250003Sadrian
4244250003Sadrian    /* Restore user-specified settings */
4245250003Sadrian    HALDEBUG(ah, HAL_DEBUG_RESET,
4246250003Sadrian        "--AP %s ahp->ah_misc_mode 0x%x\n", __func__, ahp->ah_misc_mode);
4247250003Sadrian    if (ahp->ah_misc_mode != 0) {
4248250003Sadrian        OS_REG_WRITE(ah,
4249250003Sadrian            AR_PCU_MISC, OS_REG_READ(ah, AR_PCU_MISC) | ahp->ah_misc_mode);
4250250003Sadrian    }
4251250003Sadrian    if (ahp->ah_get_plcp_hdr) {
4252250003Sadrian        OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM);
4253250003Sadrian    }
4254250003Sadrian    if (ahp->ah_slot_time != (u_int) -1) {
4255250003Sadrian        ar9300_set_slot_time(ah, ahp->ah_slot_time);
4256250003Sadrian    }
4257250003Sadrian    if (ahp->ah_ack_timeout != (u_int) -1) {
4258250003Sadrian        ar9300_set_ack_timeout(ah, ahp->ah_ack_timeout);
4259250003Sadrian    }
4260250003Sadrian    if (AH_PRIVATE(ah)->ah_diagreg != 0) {
4261250003Sadrian        OS_REG_SET_BIT(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
4262250003Sadrian    }
4263250003Sadrian    if (ahp->ah_beacon_rssi_threshold != 0) {
4264250003Sadrian        ar9300_set_hw_beacon_rssi_threshold(ah, ahp->ah_beacon_rssi_threshold);
4265250003Sadrian    }
4266250003Sadrian#ifdef ATH_SUPPORT_DFS
4267250003Sadrian    if (ahp->ah_cac_quiet_enabled) {
4268250003Sadrian        ar9300_cac_tx_quiet(ah, 1);
4269250003Sadrian    }
4270250003Sadrian#endif /* ATH_SUPPORT_DFS */
4271250003Sadrian}
4272250003Sadrian
4273250003Sadrianint
4274250003Sadrianar9300_get_spur_info(struct ath_hal * ah, int *enable, int len, u_int16_t *freq)
4275250003Sadrian{
4276250008Sadrian//    struct ath_hal_private *ap = AH_PRIVATE(ah);
4277250003Sadrian    int i, j;
4278250003Sadrian
4279250003Sadrian    for (i = 0; i < len; i++) {
4280250003Sadrian        freq[i] =  0;
4281250003Sadrian    }
4282250003Sadrian
4283250008Sadrian    *enable = ah->ah_config.ath_hal_spur_mode;
4284250003Sadrian    for (i = 0, j = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
4285250008Sadrian        if (AH9300(ah)->ath_hal_spur_chans[i][0] != AR_NO_SPUR) {
4286250008Sadrian            freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][0];
4287250003Sadrian            HALDEBUG(ah, HAL_DEBUG_ANI,
4288250008Sadrian                "1. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][0]);
4289250003Sadrian        }
4290250008Sadrian        if (AH9300(ah)->ath_hal_spur_chans[i][1] != AR_NO_SPUR) {
4291250008Sadrian            freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][1];
4292250003Sadrian            HALDEBUG(ah, HAL_DEBUG_ANI,
4293250008Sadrian                "2. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][1]);
4294250003Sadrian        }
4295250003Sadrian    }
4296250003Sadrian
4297250003Sadrian    return 0;
4298250003Sadrian}
4299250003Sadrian
4300250003Sadrian#define ATH_HAL_2GHZ_FREQ_MIN   20000
4301250003Sadrian#define ATH_HAL_2GHZ_FREQ_MAX   29999
4302250003Sadrian#define ATH_HAL_5GHZ_FREQ_MIN   50000
4303250003Sadrian#define ATH_HAL_5GHZ_FREQ_MAX   59999
4304250003Sadrian
4305250008Sadrian#if 0
4306250003Sadrianint
4307250003Sadrianar9300_set_spur_info(struct ath_hal * ah, int enable, int len, u_int16_t *freq)
4308250003Sadrian{
4309250003Sadrian    struct ath_hal_private *ap = AH_PRIVATE(ah);
4310250003Sadrian    int i, j, k;
4311250003Sadrian
4312250003Sadrian    ap->ah_config.ath_hal_spur_mode = enable;
4313250003Sadrian
4314250003Sadrian    if (ap->ah_config.ath_hal_spur_mode == SPUR_ENABLE_IOCTL) {
4315250003Sadrian        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
4316250008Sadrian            AH9300(ah)->ath_hal_spur_chans[i][0] = AR_NO_SPUR;
4317250008Sadrian            AH9300(ah)->ath_hal_spur_chans[i][1] = AR_NO_SPUR;
4318250003Sadrian        }
4319250003Sadrian        for (i = 0, j = 0, k = 0; i < len; i++) {
4320250003Sadrian            if (freq[i] > ATH_HAL_2GHZ_FREQ_MIN &&
4321250003Sadrian                freq[i] < ATH_HAL_2GHZ_FREQ_MAX)
4322250003Sadrian            {
4323250003Sadrian                /* 2GHz Spur */
4324250003Sadrian                if (j < AR_EEPROM_MODAL_SPURS) {
4325250008Sadrian                    AH9300(ah)->ath_hal_spur_chans[j++][1] =  freq[i];
4326250003Sadrian                    HALDEBUG(ah, HAL_DEBUG_ANI, "1 set spur %d\n", freq[i]);
4327250003Sadrian                }
4328250003Sadrian            } else if (freq[i] > ATH_HAL_5GHZ_FREQ_MIN &&
4329250003Sadrian                       freq[i] < ATH_HAL_5GHZ_FREQ_MAX)
4330250003Sadrian            {
4331250003Sadrian                /* 5Ghz Spur */
4332250003Sadrian                if (k < AR_EEPROM_MODAL_SPURS) {
4333250008Sadrian                    AH9300(ah)->ath_hal_spur_chans[k++][0] =  freq[i];
4334250003Sadrian                    HALDEBUG(ah, HAL_DEBUG_ANI, "2 set spur %d\n", freq[i]);
4335250003Sadrian                }
4336250003Sadrian            }
4337250003Sadrian        }
4338250003Sadrian    }
4339250003Sadrian
4340250003Sadrian    return 0;
4341250003Sadrian}
4342250008Sadrian#endif
4343250003Sadrian
4344250003Sadrian#define ar9300_check_op_mode(_opmode) \
4345250003Sadrian    ((_opmode == HAL_M_STA) || (_opmode == HAL_M_IBSS) ||\
4346250003Sadrian     (_opmode == HAL_M_HOSTAP) || (_opmode == HAL_M_MONITOR))
4347250003Sadrian
4348250003Sadrian
4349250003Sadrian
4350250003Sadrian
4351250003Sadrian#ifndef ATH_NF_PER_CHAN
4352250003Sadrian/*
4353250003Sadrian* To fixed first reset noise floor value not correct issue
4354250003Sadrian* For ART need it to fixed low rate sens too low issue
4355250003Sadrian*/
4356250003Sadrianstatic int
4357250003SadrianFirst_NFCal(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan,
4358250008Sadrian    int is_scan, struct ieee80211_channel *chan)
4359250003Sadrian{
4360250003Sadrian    HAL_NFCAL_HIST_FULL *nfh;
4361250003Sadrian    int i, j, k;
4362250008Sadrian    int16_t nfarray[HAL_NUM_NF_READINGS] = {0};
4363250003Sadrian    int is_2g = 0;
4364250003Sadrian    int nf_hist_len;
4365250003Sadrian    int stats = 0;
4366250003Sadrian
4367250008Sadrian    int16_t nf_buf[HAL_NUM_NF_READINGS];
4368250003Sadrian#define IS(_c, _f)       (((_c)->channel_flags & _f) || 0)
4369250003Sadrian
4370250003Sadrian
4371250003Sadrian    if ((!is_scan) &&
4372250008Sadrian        chan->ic_freq == AH_PRIVATE(ah)->ah_curchan->ic_freq)
4373250003Sadrian    {
4374250003Sadrian        nfh = &AH_PRIVATE(ah)->nf_cal_hist;
4375250003Sadrian    } else {
4376250003Sadrian        nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;
4377250003Sadrian    }
4378250008Sadrian
4379250003Sadrian    ar9300_start_nf_cal(ah);
4380250003Sadrian    for (j = 0; j < 10000; j++) {
4381250003Sadrian        if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){
4382250003Sadrian            break;
4383250003Sadrian		}
4384250003Sadrian        OS_DELAY(10);
4385250003Sadrian    }
4386250003Sadrian	if (j < 10000) {
4387250008Sadrian        is_2g = IEEE80211_IS_CHAN_2GHZ(chan);
4388250003Sadrian        ar9300_upload_noise_floor(ah, is_2g, nfarray);
4389250003Sadrian
4390250003Sadrian	    if (is_scan) {
4391250003Sadrian			/*
4392250003Sadrian			 * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct
4393250003Sadrian			 * rather than a HAL_NFCAL_HIST_FULL struct.
4394250003Sadrian			 * As long as we only use the first history element of nf_cal_buffer
4395250008Sadrian			 * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use
4396250003Sadrian			 * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably.
4397250003Sadrian			 */
4398250003Sadrian            nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;
4399250003Sadrian            nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL;
4400250003Sadrian		} else {
4401250003Sadrian            nfh = &AH_PRIVATE(ah)->nf_cal_hist;
4402250003Sadrian            nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;
4403250003Sadrian		}
4404250003Sadrian
4405250008Sadrian  	    for (i = 0; i < HAL_NUM_NF_READINGS; i ++) {
4406250003Sadrian    		for (k = 0; k < HAL_NF_CAL_HIST_LEN_FULL; k++) {
4407250003Sadrian                nfh->nf_cal_buffer[k][i] = nfarray[i];
4408250003Sadrian            }
4409250003Sadrian            nfh->base.priv_nf[i] = ar9300_limit_nf_range(ah,
4410250003Sadrian							ar9300_get_nf_hist_mid(ah, nfh, i, nf_hist_len));
4411250003Sadrian  		}
4412250003Sadrian
4413250003Sadrian
4414250003Sadrian		//ar9300StoreNewNf(ah, ichan, is_scan);
4415250003Sadrian
4416250003Sadrian		/*
4417250003Sadrian		 * See if the NF value from the old channel should be
4418250003Sadrian		 * retained when switching to a new channel.
4419250003Sadrian		 * TBD: this may need to be changed, as it wipes out the
4420250003Sadrian		 * purpose of saving NF values for each channel.
4421250003Sadrian		 */
4422250008Sadrian		for (i = 0; i < HAL_NUM_NF_READINGS; i++)
4423250003Sadrian		{
4424250008Sadrian    		if (IEEE80211_IS_CHAN_2GHZ(chan))
4425250003Sadrian    		{
4426250003Sadrian    			if (nfh->nf_cal_buffer[0][i] <
4427250003Sadrian					AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ)
4428250003Sadrian                {
4429250003Sadrian                    ichan->nf_cal_hist.nf_cal_buffer[0][i] =
4430250003Sadrian							AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];
4431250003Sadrian				}
4432250003Sadrian    		} else {
4433250003Sadrian                if (AR_SREV_AR9580(ah)) {
4434250003Sadrian                    if (nfh->nf_cal_buffer[0][i] <
4435250003Sadrian                        AR_PHY_CCA_NOM_VAL_PEACOCK_5GHZ)
4436250003Sadrian                    {
4437250003Sadrian                       ichan->nf_cal_hist.nf_cal_buffer[0][i] =
4438250003Sadrian                       AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];
4439250003Sadrian                    }
4440250003Sadrian                } else {
4441250003Sadrian                   if (nfh->nf_cal_buffer[0][i] <
4442250003Sadrian                       AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ)
4443250003Sadrian                    {
4444250003Sadrian                        ichan->nf_cal_hist.nf_cal_buffer[0][i] =
4445250003Sadrian                            AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];
4446250003Sadrian                     }
4447250003Sadrian                }
4448250003Sadrian            }
4449250003Sadrian        }
4450250003Sadrian		/*
4451250003Sadrian		 * Copy the channel's NF buffer, which may have been modified
4452250003Sadrian		 * just above here, to the full NF history buffer.
4453250003Sadrian		 */
4454250003Sadrian        ar9300_reset_nf_hist_buff(ah, ichan);
4455250008Sadrian        ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);
4456250003Sadrian        ar9300_load_nf(ah, nf_buf);
4457250003Sadrian        stats = 0;
4458250003Sadrian	} else {
4459250003Sadrian        stats = 1;
4460250003Sadrian	}
4461250003Sadrian#undef IS
4462250003Sadrian    return stats;
4463250003Sadrian}
4464250003Sadrian#endif
4465250003Sadrian
4466250003Sadrian
4467250003Sadrian/*
4468250003Sadrian * Places the device in and out of reset and then places sane
4469250003Sadrian * values in the registers based on EEPROM config, initialization
4470250003Sadrian * vectors (as determined by the mode), and station configuration
4471250003Sadrian *
4472250003Sadrian * b_channel_change is used to preserve DMA/PCU registers across
4473250003Sadrian * a HW Reset during channel change.
4474250003Sadrian */
4475250003SadrianHAL_BOOL
4476250008Sadrianar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan,
4477250003Sadrian    HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask,
4478250003Sadrian    HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change,
4479250003Sadrian    HAL_STATUS *status, int is_scan)
4480250003Sadrian{
4481250003Sadrian#define FAIL(_code)     do { ecode = _code; goto bad; } while (0)
4482250003Sadrian    u_int32_t               save_led_state;
4483250003Sadrian    struct ath_hal_9300     *ahp = AH9300(ah);
4484250003Sadrian    struct ath_hal_private  *ap  = AH_PRIVATE(ah);
4485250003Sadrian    HAL_CHANNEL_INTERNAL    *ichan;
4486250008Sadrian    //const struct ieee80211_channel *curchan = ap->ah_curchan;
4487250003Sadrian#if ATH_SUPPORT_MCI
4488250003Sadrian    HAL_BOOL                    save_full_sleep = ahp->ah_chip_full_sleep;
4489250003Sadrian#endif
4490250003Sadrian    u_int32_t               save_def_antenna;
4491250003Sadrian    u_int32_t               mac_sta_id1;
4492250003Sadrian    HAL_STATUS              ecode;
4493250003Sadrian    int                     i, rx_chainmask;
4494250003Sadrian    int                     nf_hist_buff_reset = 0;
4495250008Sadrian    int16_t                 nf_buf[HAL_NUM_NF_READINGS];
4496250003Sadrian#ifdef ATH_FORCE_PPM
4497250003Sadrian    u_int32_t               save_force_val, tmp_reg;
4498250003Sadrian#endif
4499291437Sadrian    u_int8_t                clk_25mhz = AH9300(ah)->clk_25mhz;
4500250003Sadrian    HAL_BOOL                    stopped, cal_ret;
4501250003Sadrian    HAL_BOOL                    apply_last_iqcorr = AH_FALSE;
4502250003Sadrian
4503278741Sadrian
4504250003Sadrian    if (OS_REG_READ(ah, AR_IER) == AR_IER_ENABLE) {
4505250003Sadrian        HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "** Reset called with WLAN "
4506250003Sadrian                "interrupt enabled %08x **\n", ar9300_get_interrupts(ah));
4507250003Sadrian    }
4508250003Sadrian
4509250003Sadrian    /*
4510250003Sadrian     * Set the status to "ok" by default to cover the cases
4511291437Sadrian     * where we return false without going to "bad"
4512250003Sadrian     */
4513250003Sadrian    HALASSERT(status);
4514250003Sadrian    *status = HAL_OK;
4515250008Sadrian    if ((ah->ah_config.ath_hal_sta_update_tx_pwr_enable)) {
4516250008Sadrian        AH9300(ah)->green_tx_status = HAL_RSSI_TX_POWER_NONE;
4517250003Sadrian    }
4518250003Sadrian
4519250003Sadrian#if ATH_SUPPORT_MCI
4520250008Sadrian    if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&
4521301420Sadrian        (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)))
4522250003Sadrian    {
4523250008Sadrian        ar9300_mci_2g5g_changed(ah, IEEE80211_IS_CHAN_2GHZ(chan));
4524250003Sadrian    }
4525250003Sadrian#endif
4526250003Sadrian
4527250003Sadrian    ahp->ah_ext_prot_spacing = extprotspacing;
4528250008Sadrian    ahp->ah_tx_chainmask = txchainmask & ap->ah_caps.halTxChainMask;
4529250008Sadrian    ahp->ah_rx_chainmask = rxchainmask & ap->ah_caps.halRxChainMask;
4530250008Sadrian    ahp->ah_tx_cal_chainmask = ap->ah_caps.halTxChainMask;
4531250008Sadrian    ahp->ah_rx_cal_chainmask = ap->ah_caps.halRxChainMask;
4532278741Sadrian
4533278741Sadrian    /*
4534278741Sadrian     * Keep the previous optinal txchainmask value
4535278741Sadrian     */
4536278741Sadrian
4537250003Sadrian    HALASSERT(ar9300_check_op_mode(opmode));
4538250003Sadrian
4539250003Sadrian    OS_MARK(ah, AH_MARK_RESET, b_channel_change);
4540250003Sadrian
4541250003Sadrian    /*
4542250003Sadrian     * Map public channel to private.
4543250003Sadrian     */
4544250003Sadrian    ichan = ar9300_check_chan(ah, chan);
4545250003Sadrian    if (ichan == AH_NULL) {
4546250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CHANNEL,
4547250003Sadrian            "%s: invalid channel %u/0x%x; no mapping\n",
4548250008Sadrian            __func__, chan->ic_freq, chan->ic_flags);
4549250003Sadrian        FAIL(HAL_EINVAL);
4550250003Sadrian    }
4551250003Sadrian
4552250003Sadrian    ichan->paprd_table_write_done = 0;  /* Clear PAPRD table write flag */
4553250008Sadrian#if 0
4554250003Sadrian    chan->paprd_table_write_done = 0;  /* Clear PAPRD table write flag */
4555250008Sadrian#endif
4556250003Sadrian
4557250003Sadrian    if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) {
4558250003Sadrian        /* Need to stop RX DMA before reset otherwise chip might hang */
4559250003Sadrian        stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */
4560250003Sadrian        ar9300_set_rx_filter(ah, 0);
4561250003Sadrian        stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */
4562250003Sadrian        if (!stopped) {
4563250003Sadrian            /*
4564250003Sadrian             * During the transition from full sleep to reset,
4565250003Sadrian             * recv DMA regs are not available to be read
4566250003Sadrian             */
4567250003Sadrian            HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
4568250003Sadrian                "%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__);
4569250003Sadrian            b_channel_change = AH_FALSE;
4570250003Sadrian        }
4571250003Sadrian    } else {
4572250003Sadrian        HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
4573250003Sadrian            "%s[%d]: Chip is already in full sleep\n", __func__, __LINE__);
4574250003Sadrian    }
4575250003Sadrian
4576250003Sadrian#if ATH_SUPPORT_MCI
4577250008Sadrian    if ((AH_PRIVATE(ah)->ah_caps.halMciSupport) &&
4578250003Sadrian        (ahp->ah_mci_bt_state == MCI_BT_CAL_START))
4579250003Sadrian    {
4580250003Sadrian        u_int32_t payload[4] = {0, 0, 0, 0};
4581250003Sadrian
4582250003Sadrian        HALDEBUG(ah, HAL_DEBUG_BT_COEX,
4583250003Sadrian            "(MCI) %s: Stop rx for BT cal.\n", __func__);
4584250003Sadrian        ahp->ah_mci_bt_state = MCI_BT_CAL;
4585250003Sadrian
4586250003Sadrian        /*
4587250003Sadrian         * MCIFIX: disable mci interrupt here. This is to avoid SW_MSG_DONE or
4588250003Sadrian         * RX_MSG bits to trigger MCI_INT and lead to mci_intr reentry.
4589250003Sadrian         */
4590250003Sadrian        ar9300_mci_disable_interrupt(ah);
4591250003Sadrian
4592250003Sadrian        HALDEBUG(ah, HAL_DEBUG_BT_COEX,
4593250003Sadrian            "(MCI) %s: Send WLAN_CAL_GRANT\n", __func__);
4594250003Sadrian        MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
4595250003Sadrian        ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);
4596250003Sadrian
4597250003Sadrian        /* Wait BT calibration to be completed for 25ms */
4598250003Sadrian        HALDEBUG(ah, HAL_DEBUG_BT_COEX,
4599250003Sadrian            "(MCI) %s: BT is calibrating.\n", __func__);
4600250003Sadrian        if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) {
4601250003Sadrian            HALDEBUG(ah, HAL_DEBUG_BT_COEX,
4602250003Sadrian                "(MCI) %s: Got BT_CAL_DONE.\n", __func__);
4603250003Sadrian        }
4604250003Sadrian        else {
4605250003Sadrian            HALDEBUG(ah, HAL_DEBUG_BT_COEX,
4606250003Sadrian                "(MCI) %s: ### BT cal takes too long. Force bt_state to be bt_awake.\n",
4607250003Sadrian                __func__);
4608250003Sadrian        }
4609250003Sadrian        ahp->ah_mci_bt_state = MCI_BT_AWAKE;
4610250003Sadrian        /* MCIFIX: enable mci interrupt here */
4611250003Sadrian        ar9300_mci_enable_interrupt(ah);
4612250003Sadrian
4613250003Sadrian        return AH_TRUE;
4614250003Sadrian    }
4615250003Sadrian#endif
4616250003Sadrian
4617250003Sadrian    /* Bring out of sleep mode */
4618250003Sadrian    if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {
4619250003Sadrian        *status = HAL_INV_PMODE;
4620250003Sadrian        return AH_FALSE;
4621250003Sadrian    }
4622250003Sadrian
4623250003Sadrian    /* Check the Rx mitigation config again, it might have changed
4624250003Sadrian     * during attach in ath_vap_attach.
4625250003Sadrian     */
4626250008Sadrian    if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) {
4627250003Sadrian        ahp->ah_intr_mitigation_rx = AH_TRUE;
4628250003Sadrian    } else {
4629250003Sadrian        ahp->ah_intr_mitigation_rx = AH_FALSE;
4630250003Sadrian    }
4631250003Sadrian
4632250008Sadrian    /*
4633250008Sadrian     * XXX TODO FreeBSD:
4634250008Sadrian     *
4635250008Sadrian     * This is painful because we don't have a non-const channel pointer
4636250008Sadrian     * at this stage.
4637250008Sadrian     *
4638250008Sadrian     * Make sure this gets fixed!
4639250008Sadrian     */
4640250008Sadrian#if 0
4641250003Sadrian    /* Get the value from the previous NF cal and update history buffer */
4642250003Sadrian    if (curchan && (ahp->ah_chip_full_sleep != AH_TRUE)) {
4643278741Sadrian
4644278741Sadrian        if(ahp->ah_chip_reset_done){
4645278741Sadrian            ahp->ah_chip_reset_done = 0;
4646278741Sadrian        } else {
4647278741Sadrian        	/*
4648278741Sadrian         	 * is_scan controls updating NF for home channel or off channel.
4649278741Sadrian         	 * Home -> Off, update home channel
4650278741Sadrian         	 * Off -> Home, update off channel
4651278741Sadrian         	 * Home -> Home, uppdate home channel
4652278741Sadrian         	 */
4653278741Sadrian        	if (ap->ah_curchan->channel != chan->channel)
4654278741Sadrian            	ar9300_store_new_nf(ah, curchan, !is_scan);
4655278741Sadrian        	else
4656278741Sadrian            	ar9300_store_new_nf(ah, curchan, is_scan);
4657278741Sadrian        }
4658250003Sadrian    }
4659250008Sadrian#endif
4660250003Sadrian
4661250003Sadrian    /*
4662250003Sadrian     * Account for the effect of being in either the 2 GHz or 5 GHz band
4663250003Sadrian     * on the nominal, max allowable, and min allowable noise floor values.
4664250003Sadrian     */
4665250008Sadrian    AH9300(ah)->nfp = IS_CHAN_2GHZ(ichan) ? &ahp->nf_2GHz : &ahp->nf_5GHz;
4666250003Sadrian
4667250008Sadrian    /*
4668278741Sadrian     * XXX FreeBSD For now, don't apply the last IQ correction.
4669250008Sadrian     *
4670250008Sadrian     * This should be done when scorpion is enabled on FreeBSD; just be
4671250008Sadrian     * sure to fix this channel match code so it uses net80211 flags
4672250008Sadrian     * instead.
4673250008Sadrian     */
4674250008Sadrian#if 0
4675250003Sadrian    if (AR_SREV_SCORPION(ah) && curchan && (chan->channel == curchan->channel) &&
4676250003Sadrian        ((chan->channel_flags & (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)) ==
4677250003Sadrian         (curchan->channel_flags &
4678250003Sadrian          (CHANNEL_ALL | CHANNEL_HALF | CHANNEL_QUARTER)))) {
4679250003Sadrian            apply_last_iqcorr = AH_TRUE;
4680250003Sadrian    }
4681250008Sadrian#endif
4682250008Sadrian    apply_last_iqcorr = AH_FALSE;
4683250008Sadrian
4684250003Sadrian
4685250003Sadrian#ifndef ATH_NF_PER_CHAN
4686250003Sadrian    /*
4687250003Sadrian     * If there's only one full-size home-channel NF history buffer
4688250003Sadrian     * rather than a full-size NF history buffer per channel, decide
4689250003Sadrian     * whether to (re)initialize the home-channel NF buffer.
4690250003Sadrian     * If this is just a channel change for a scan, or if the channel
4691250003Sadrian     * is not being changed, don't mess up the home channel NF history
4692250003Sadrian     * buffer with NF values from this scanned channel.  If we're
4693250003Sadrian     * changing the home channel to a new channel, reset the home-channel
4694250003Sadrian     * NF history buffer with the most accurate NF known for the new channel.
4695250003Sadrian     */
4696250003Sadrian    if (!is_scan && (!ap->ah_curchan ||
4697250008Sadrian        ap->ah_curchan->ic_freq != chan->ic_freq)) // ||
4698250008Sadrian//        ap->ah_curchan->channel_flags != chan->channel_flags))
4699250003Sadrian    {
4700250003Sadrian        nf_hist_buff_reset = 1;
4701250003Sadrian        ar9300_reset_nf_hist_buff(ah, ichan);
4702250003Sadrian    }
4703250003Sadrian#endif
4704250003Sadrian    /*
4705278741Sadrian     * In case of
4706278741Sadrian     * - offchan scan, or
4707278741Sadrian     * - same channel and RX IQ Cal already available
4708278741Sadrian     * disable RX IQ Cal.
4709278741Sadrian     */
4710278741Sadrian    if (is_scan) {
4711278741Sadrian        ahp->ah_skip_rx_iq_cal = AH_TRUE;
4712278741Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
4713278741Sadrian                "Skip RX IQ Cal due to scanning\n");
4714278741Sadrian    } else {
4715278741Sadrian#if 0
4716278741Sadrian        /* XXX FreeBSD: always just do the RX IQ cal */
4717278741Sadrian	/* XXX I think it's just going to speed things up; I don't think it's to avoid chan bugs */
4718278741Sadrian        if (ahp->ah_rx_cal_complete &&
4719278741Sadrian            ahp->ah_rx_cal_chan == ichan->channel &&
4720278741Sadrian            ahp->ah_rx_cal_chan_flag == chan->channel_flags) {
4721278741Sadrian            ahp->ah_skip_rx_iq_cal = AH_TRUE;
4722278741Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
4723278741Sadrian                    "Skip RX IQ Cal due to same channel with completed RX IQ Cal\n");
4724278741Sadrian        } else
4725278741Sadrian#endif
4726278741Sadrian            ahp->ah_skip_rx_iq_cal = AH_FALSE;
4727278741Sadrian    }
4728280829Sadrian
4729280829Sadrian    /* FreeBSD: clear the channel survey data */
4730280829Sadrian    ath_hal_survey_clear(ah);
4731280829Sadrian
4732278741Sadrian    /*
4733250003Sadrian     * Fast channel change (Change synthesizer based on channel freq
4734250003Sadrian     * without resetting chip)
4735250003Sadrian     * Don't do it when
4736250003Sadrian     *   - Flag is not set
4737250003Sadrian     *   - Chip is just coming out of full sleep
4738250003Sadrian     *   - Channel to be set is same as current channel
4739250003Sadrian     *   - Channel flags are different, like when moving from 2GHz to 5GHz
4740250003Sadrian     *     channels
4741250003Sadrian     *   - Merlin: Switching in/out of fast clock enabled channels
4742250003Sadrian     *             (not currently coded, since fast clock is enabled
4743250003Sadrian     *             across the 5GHz band
4744250003Sadrian     *             and we already do a full reset when switching in/out
4745250003Sadrian     *             of 5GHz channels)
4746250003Sadrian     */
4747250008Sadrian#if 0
4748250003Sadrian    if (b_channel_change &&
4749250003Sadrian        (ahp->ah_chip_full_sleep != AH_TRUE) &&
4750250003Sadrian        (AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&
4751250003Sadrian        ((chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) &&
4752250003Sadrian        (((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & chan->channel_flags) ==
4753250003Sadrian        ((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & AH_PRIVATE(ah)->ah_curchan->channel_flags))))
4754250003Sadrian    {
4755250003Sadrian        if (ar9300_channel_change(ah, chan, ichan, macmode)) {
4756250003Sadrian            chan->channel_flags = ichan->channel_flags;
4757250003Sadrian            chan->priv_flags = ichan->priv_flags;
4758250003Sadrian            AH_PRIVATE(ah)->ah_curchan->ah_channel_time = 0;
4759250003Sadrian            AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar9300_get_tsf64(ah);
4760250003Sadrian
4761250003Sadrian            /*
4762250003Sadrian             * Load the NF from history buffer of the current channel.
4763250003Sadrian             * NF is slow time-variant, so it is OK to use a historical value.
4764250003Sadrian             */
4765250003Sadrian            ar9300_get_nf_hist_base(ah,
4766250003Sadrian                AH_PRIVATE(ah)->ah_curchan, is_scan, nf_buf);
4767250003Sadrian            ar9300_load_nf(ah, nf_buf);
4768250003Sadrian
4769250003Sadrian            /* start NF calibration, without updating BB NF register*/
4770250003Sadrian            ar9300_start_nf_cal(ah);
4771250003Sadrian
4772250003Sadrian            /*
4773250003Sadrian             * If channel_change completed and DMA was stopped
4774250003Sadrian             * successfully - skip the rest of reset
4775250003Sadrian             */
4776250003Sadrian            if (AH9300(ah)->ah_dma_stuck != AH_TRUE) {
4777250003Sadrian                WAR_USB_DISABLE_PLL_LOCK_DETECT(ah);
4778250003Sadrian#if ATH_SUPPORT_MCI
4779250008Sadrian                if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready)
4780250003Sadrian                {
4781250003Sadrian                    ar9300_mci_2g5g_switch(ah, AH_TRUE);
4782250003Sadrian                }
4783250003Sadrian#endif
4784250008Sadrian                return HAL_OK;
4785250003Sadrian            }
4786250003Sadrian         }
4787250003Sadrian    }
4788250008Sadrian#endif /* #if 0 */
4789250003Sadrian
4790250003Sadrian#if ATH_SUPPORT_MCI
4791250008Sadrian    if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {
4792250003Sadrian        ar9300_mci_disable_interrupt(ah);
4793250003Sadrian        if (ahp->ah_mci_ready && !save_full_sleep) {
4794250003Sadrian            ar9300_mci_mute_bt(ah);
4795250003Sadrian            OS_DELAY(20);
4796250003Sadrian            OS_REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
4797250003Sadrian        }
4798250003Sadrian
4799250003Sadrian        ahp->ah_mci_bt_state = MCI_BT_SLEEP;
4800250003Sadrian        ahp->ah_mci_ready = AH_FALSE;
4801250003Sadrian    }
4802250003Sadrian#endif
4803250003Sadrian
4804250003Sadrian    AH9300(ah)->ah_dma_stuck = AH_FALSE;
4805250003Sadrian#ifdef ATH_FORCE_PPM
4806250003Sadrian    /* Preserve force ppm state */
4807250003Sadrian    save_force_val =
4808250003Sadrian        OS_REG_READ(ah, AR_PHY_TIMING2) &
4809250003Sadrian        (AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL);
4810250003Sadrian#endif
4811250003Sadrian    /*
4812250003Sadrian     * Preserve the antenna on a channel change
4813250003Sadrian     */
4814250003Sadrian    save_def_antenna = OS_REG_READ(ah, AR_DEF_ANTENNA);
4815250003Sadrian    if (0 == ahp->ah_smartantenna_enable )
4816250003Sadrian    {
4817250003Sadrian        if (save_def_antenna == 0) {
4818250003Sadrian            save_def_antenna = 1;
4819250003Sadrian        }
4820250003Sadrian    }
4821250003Sadrian
4822250003Sadrian    /* Save hardware flag before chip reset clears the register */
4823250003Sadrian    mac_sta_id1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
4824250003Sadrian
4825250003Sadrian    /* Save led state from pci config register */
4826250003Sadrian    save_led_state = OS_REG_READ(ah, AR_CFG_LED) &
4827250003Sadrian        (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
4828250003Sadrian        AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW);
4829250003Sadrian
4830250003Sadrian    /* Mark PHY inactive prior to reset, to be undone in ar9300_init_bb () */
4831250003Sadrian    ar9300_mark_phy_inactive(ah);
4832250003Sadrian
4833250003Sadrian    if (!ar9300_chip_reset(ah, chan)) {
4834250003Sadrian        HALDEBUG(ah, HAL_DEBUG_RESET, "%s: chip reset failed\n", __func__);
4835250003Sadrian        FAIL(HAL_EIO);
4836250003Sadrian    }
4837250003Sadrian
4838250003Sadrian    OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
4839250003Sadrian
4840250003Sadrian
4841250003Sadrian    /* Disable JTAG */
4842250003Sadrian    OS_REG_SET_BIT(ah,
4843250003Sadrian        AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE);
4844250003Sadrian
4845250003Sadrian    /*
4846250003Sadrian     * Note that ar9300_init_chain_masks() is called from within
4847250003Sadrian     * ar9300_process_ini() to ensure the swap bit is set before
4848250003Sadrian     * the pdadc table is written.
4849250003Sadrian     */
4850250003Sadrian    ecode = ar9300_process_ini(ah, chan, ichan, macmode);
4851250003Sadrian    if (ecode != HAL_OK) {
4852250003Sadrian        goto bad;
4853250003Sadrian    }
4854291437Sadrian
4855291437Sadrian    /*
4856291437Sadrian     * Configuring WMAC PLL values for 25/40 MHz
4857291437Sadrian     */
4858291437Sadrian    if(AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah) || AR_SREV_SCORPION(ah) ) {
4859291437Sadrian        if(clk_25mhz) {
4860291437Sadrian            OS_REG_WRITE(ah, AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); // 32KHz sleep clk
4861291437Sadrian        } else {
4862291437Sadrian            OS_REG_WRITE(ah, AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); // 32KHz sleep clk
4863291437Sadrian        }
4864291437Sadrian        OS_DELAY(100);
4865291437Sadrian    }
4866250003Sadrian
4867250003Sadrian    ahp->ah_immunity_on = AH_FALSE;
4868250003Sadrian
4869250003Sadrian    if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
4870250003Sadrian        ahp->tx_iq_cal_enable = OS_REG_READ_FIELD(ah,
4871250003Sadrian                                AR_PHY_TX_IQCAL_CONTROL_0(ah),
4872250003Sadrian                                AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL) ?
4873250003Sadrian                                1 : 0;
4874250003Sadrian    }
4875250003Sadrian    ahp->tx_cl_cal_enable = (OS_REG_READ(ah, AR_PHY_CL_CAL_CTL) &
4876250003Sadrian                                AR_PHY_CL_CAL_ENABLE) ? 1 : 0;
4877250003Sadrian
4878250003Sadrian    /* For devices with full HW RIFS Rx support (Sowl/Howl/Merlin, etc),
4879250003Sadrian     * restore register settings from prior to reset.
4880250003Sadrian     */
4881250003Sadrian    if ((AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&
4882250003Sadrian        (ar9300_get_capability(ah, HAL_CAP_LDPCWAR, 0, AH_NULL) == HAL_OK))
4883250003Sadrian    {
4884250003Sadrian        /* Re-program RIFS Rx policy after reset */
4885250003Sadrian        ar9300_set_rifs_delay(ah, ahp->ah_rifs_enabled);
4886250003Sadrian    }
4887250003Sadrian
4888250003Sadrian#if ATH_SUPPORT_MCI
4889250008Sadrian    if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {
4890250008Sadrian        ar9300_mci_reset(ah, AH_FALSE, IS_CHAN_2GHZ(ichan), save_full_sleep);
4891250003Sadrian    }
4892250003Sadrian#endif
4893250003Sadrian
4894250003Sadrian    /* Initialize Management Frame Protection */
4895250003Sadrian    ar9300_init_mfp(ah);
4896250003Sadrian
4897250003Sadrian    ahp->ah_immunity_vals[0] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,
4898250003Sadrian        AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
4899250003Sadrian    ahp->ah_immunity_vals[1] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,
4900250003Sadrian        AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
4901250003Sadrian    ahp->ah_immunity_vals[2] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,
4902250003Sadrian        AR_PHY_SFCORR_M1_THRESH);
4903250003Sadrian    ahp->ah_immunity_vals[3] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,
4904250003Sadrian        AR_PHY_SFCORR_M2_THRESH);
4905250003Sadrian    ahp->ah_immunity_vals[4] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,
4906250003Sadrian        AR_PHY_SFCORR_M2COUNT_THR);
4907250003Sadrian    ahp->ah_immunity_vals[5] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,
4908250003Sadrian        AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
4909250003Sadrian
4910250003Sadrian    /* Write delta slope for OFDM enabled modes (A, G, Turbo) */
4911250008Sadrian    if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) {
4912250008Sadrian        ar9300_set_delta_slope(ah, chan);
4913250003Sadrian    }
4914250003Sadrian
4915250003Sadrian    ar9300_spur_mitigate(ah, chan);
4916250008Sadrian    if (!ar9300_eeprom_set_board_values(ah, chan)) {
4917250003Sadrian        HALDEBUG(ah, HAL_DEBUG_EEPROM,
4918250003Sadrian            "%s: error setting board options\n", __func__);
4919250003Sadrian        FAIL(HAL_EIO);
4920250003Sadrian    }
4921250003Sadrian
4922250003Sadrian#ifdef ATH_HAL_WAR_REG16284_APH128
4923250003Sadrian    /* temp work around, will be removed. */
4924250003Sadrian    if (AR_SREV_WASP(ah)) {
4925250003Sadrian        OS_REG_WRITE(ah, 0x16284, 0x1553e000);
4926250003Sadrian    }
4927250003Sadrian#endif
4928250003Sadrian
4929250003Sadrian    OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
4930250003Sadrian
4931250003Sadrian    OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));
4932250003Sadrian    OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)
4933250003Sadrian            | mac_sta_id1
4934250003Sadrian            | AR_STA_ID1_RTS_USE_DEF
4935250008Sadrian            | (ah->ah_config.ath_hal_6mb_ack ? AR_STA_ID1_ACKCTS_6MB : 0)
4936250003Sadrian            | ahp->ah_sta_id1_defaults
4937250003Sadrian    );
4938250003Sadrian    ar9300_set_operating_mode(ah, opmode);
4939250003Sadrian
4940250003Sadrian    /* Set Venice BSSID mask according to current state */
4941250003Sadrian    OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssid_mask));
4942250003Sadrian    OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssid_mask + 4));
4943250003Sadrian
4944250003Sadrian    /* Restore previous antenna */
4945250003Sadrian    OS_REG_WRITE(ah, AR_DEF_ANTENNA, save_def_antenna);
4946250003Sadrian#ifdef ATH_FORCE_PPM
4947250003Sadrian    /* Restore force ppm state */
4948250003Sadrian    tmp_reg = OS_REG_READ(ah, AR_PHY_TIMING2) &
4949250003Sadrian        ~(AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL);
4950250003Sadrian    OS_REG_WRITE(ah, AR_PHY_TIMING2, tmp_reg | save_force_val);
4951250003Sadrian#endif
4952250003Sadrian
4953250003Sadrian    /* then our BSSID and assocID */
4954250003Sadrian    OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
4955250003Sadrian    OS_REG_WRITE(ah, AR_BSS_ID1,
4956250003Sadrian        LE_READ_2(ahp->ah_bssid + 4) |
4957250003Sadrian        ((ahp->ah_assoc_id & 0x3fff) << AR_BSS_ID1_AID_S));
4958250003Sadrian
4959250003Sadrian    OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */
4960250003Sadrian
4961250003Sadrian    OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR);
4962250003Sadrian
4963250003Sadrian    /* HW beacon processing */
4964250008Sadrian    /*
4965250008Sadrian     * XXX what happens if I just leave filter_interval=0?
4966250008Sadrian     * it stays disabled?
4967250008Sadrian     */
4968250003Sadrian    OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_BCN_WEIGHT,
4969250003Sadrian            INIT_RSSI_BEACON_WEIGHT);
4970250003Sadrian    OS_REG_SET_BIT(ah, AR_HWBCNPROC1, AR_HWBCNPROC1_CRC_ENABLE |
4971250003Sadrian            AR_HWBCNPROC1_EXCLUDE_TIM_ELM);
4972250008Sadrian    if (ah->ah_config.ath_hal_beacon_filter_interval) {
4973250003Sadrian        OS_REG_RMW_FIELD(ah, AR_HWBCNPROC2, AR_HWBCNPROC2_FILTER_INTERVAL,
4974250008Sadrian                ah->ah_config.ath_hal_beacon_filter_interval);
4975250003Sadrian        OS_REG_SET_BIT(ah, AR_HWBCNPROC2,
4976250003Sadrian                AR_HWBCNPROC2_FILTER_INTERVAL_ENABLE);
4977250003Sadrian    }
4978250003Sadrian
4979250003Sadrian
4980250003Sadrian    /*
4981250003Sadrian     * Set Channel now modifies bank 6 parameters for FOWL workaround
4982250003Sadrian     * to force rf_pwd_icsyndiv bias current as function of synth
4983250003Sadrian     * frequency.Thus must be called after ar9300_process_ini() to ensure
4984250003Sadrian     * analog register cache is valid.
4985250003Sadrian     */
4986250008Sadrian    if (!ahp->ah_rf_hal.set_channel(ah, chan)) {
4987250003Sadrian        FAIL(HAL_EIO);
4988250003Sadrian    }
4989250003Sadrian
4990250003Sadrian
4991250003Sadrian    OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
4992250003Sadrian
4993250003Sadrian    /* Set 1:1 QCU to DCU mapping for all queues */
4994250003Sadrian    for (i = 0; i < AR_NUM_DCU; i++) {
4995250003Sadrian        OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
4996250003Sadrian    }
4997250003Sadrian
4998250003Sadrian    ahp->ah_intr_txqs = 0;
4999250008Sadrian    for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) {
5000250003Sadrian        ar9300_reset_tx_queue(ah, i);
5001250003Sadrian    }
5002250003Sadrian
5003250003Sadrian    ar9300_init_interrupt_masks(ah, opmode);
5004250003Sadrian
5005250003Sadrian    /* Reset ier reference count to disabled */
5006250008Sadrian//    OS_ATOMIC_SET(&ahp->ah_ier_ref_count, 1);
5007250003Sadrian    if (ath_hal_isrfkillenabled(ah)) {
5008250003Sadrian        ar9300_enable_rf_kill(ah);
5009250003Sadrian    }
5010250003Sadrian
5011250003Sadrian    /* must be called AFTER ini is processed */
5012250003Sadrian    ar9300_ani_init_defaults(ah, macmode);
5013250003Sadrian
5014250003Sadrian    ar9300_init_qos(ah);
5015250003Sadrian
5016250003Sadrian    ar9300_init_user_settings(ah);
5017250003Sadrian
5018250003Sadrian
5019250003Sadrian    AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */
5020250003Sadrian
5021250003Sadrian    OS_MARK(ah, AH_MARK_RESET_DONE, 0);
5022250003Sadrian
5023250003Sadrian    /*
5024250003Sadrian     * disable seq number generation in hw
5025250003Sadrian     */
5026250003Sadrian    OS_REG_WRITE(ah, AR_STA_ID1,
5027250003Sadrian        OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
5028250003Sadrian
5029250003Sadrian    ar9300_set_dma(ah);
5030250003Sadrian
5031250003Sadrian    /*
5032250003Sadrian     * program OBS bus to see MAC interrupts
5033250003Sadrian     */
5034250003Sadrian#if ATH_SUPPORT_MCI
5035250008Sadrian    if (!AH_PRIVATE(ah)->ah_caps.halMciSupport) {
5036250003Sadrian        OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8);
5037250003Sadrian    }
5038250003Sadrian#else
5039250003Sadrian    OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8);
5040250003Sadrian#endif
5041250003Sadrian
5042250003Sadrian
5043250003Sadrian    /* enabling AR_GTTM_IGNORE_IDLE in GTTM register so that
5044250003Sadrian       GTT timer will not increment if the channel idle indicates
5045250003Sadrian       the air is busy or NAV is still counting down */
5046250003Sadrian    OS_REG_WRITE(ah, AR_GTTM, AR_GTTM_IGNORE_IDLE);
5047250003Sadrian
5048250003Sadrian    /*
5049250003Sadrian     * GTT debug mode setting
5050250003Sadrian     */
5051250003Sadrian    /*
5052250003Sadrian    OS_REG_WRITE(ah, 0x64, 0x00320000);
5053250003Sadrian    OS_REG_WRITE(ah, 0x68, 7);
5054250003Sadrian    OS_REG_WRITE(ah, 0x4080, 0xC);
5055250003Sadrian     */
5056250003Sadrian    /*
5057250003Sadrian     * Disable general interrupt mitigation by setting MIRT = 0x0
5058250003Sadrian     * Rx and tx interrupt mitigation are conditionally enabled below.
5059250003Sadrian     */
5060250003Sadrian    OS_REG_WRITE(ah, AR_MIRT, 0);
5061250003Sadrian    if (ahp->ah_intr_mitigation_rx) {
5062250003Sadrian        /*
5063250003Sadrian         * Enable Interrupt Mitigation for Rx.
5064250003Sadrian         * If no build-specific limits for the rx interrupt mitigation
5065250003Sadrian         * timer have been specified, use conservative defaults.
5066250003Sadrian         */
5067250003Sadrian        #ifndef AH_RIMT_VAL_LAST
5068250003Sadrian            #define AH_RIMT_LAST_MICROSEC 500
5069250003Sadrian        #endif
5070250003Sadrian        #ifndef AH_RIMT_VAL_FIRST
5071250003Sadrian            #define AH_RIMT_FIRST_MICROSEC 2000
5072250003Sadrian        #endif
5073250003Sadrian#ifndef HOST_OFFLOAD
5074250003Sadrian        OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, AH_RIMT_LAST_MICROSEC);
5075250003Sadrian        OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, AH_RIMT_FIRST_MICROSEC);
5076250003Sadrian#else
5077250003Sadrian        /* lower mitigation level to reduce latency for offload arch. */
5078250003Sadrian        OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST,
5079250003Sadrian            (AH_RIMT_LAST_MICROSEC >> 2));
5080250003Sadrian        OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST,
5081250003Sadrian            (AH_RIMT_FIRST_MICROSEC >> 2));
5082250003Sadrian#endif
5083250003Sadrian    }
5084250003Sadrian
5085250003Sadrian    if (ahp->ah_intr_mitigation_tx) {
5086250003Sadrian        /*
5087250003Sadrian         * Enable Interrupt Mitigation for Tx.
5088250003Sadrian         * If no build-specific limits for the tx interrupt mitigation
5089250003Sadrian         * timer have been specified, use the values preferred for
5090250003Sadrian         * the carrier group's products.
5091250003Sadrian         */
5092250003Sadrian        #ifndef AH_TIMT_LAST
5093250003Sadrian            #define AH_TIMT_LAST_MICROSEC 300
5094250003Sadrian        #endif
5095250003Sadrian        #ifndef AH_TIMT_FIRST
5096250003Sadrian            #define AH_TIMT_FIRST_MICROSEC 750
5097250003Sadrian        #endif
5098250003Sadrian        OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, AH_TIMT_LAST_MICROSEC);
5099250003Sadrian        OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, AH_TIMT_FIRST_MICROSEC);
5100250003Sadrian    }
5101250003Sadrian
5102250003Sadrian    rx_chainmask = ahp->ah_rx_chainmask;
5103250003Sadrian
5104250003Sadrian    OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
5105250003Sadrian    OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
5106250003Sadrian
5107250003Sadrian    ar9300_init_bb(ah, chan);
5108250003Sadrian
5109250003Sadrian    /* BB Step 7: Calibration */
5110278741Sadrian    /*
5111278741Sadrian     * Only kick off calibration not on offchan.
5112278741Sadrian     * If coming back from offchan, restore prevous Cal results
5113278741Sadrian     * since chip reset will clear existings.
5114278741Sadrian     */
5115278741Sadrian    if (!ahp->ah_skip_rx_iq_cal) {
5116278741Sadrian        int i;
5117278741Sadrian        /* clear existing RX cal data */
5118278741Sadrian        for (i=0; i<AR9300_MAX_CHAINS; i++)
5119278741Sadrian            ahp->ah_rx_cal_corr[i] = 0;
5120278741Sadrian
5121278741Sadrian        ahp->ah_rx_cal_complete = AH_FALSE;
5122278741Sadrian//        ahp->ah_rx_cal_chan = chan->channel;
5123278741Sadrian//        ahp->ah_rx_cal_chan_flag = ichan->channel_flags;
5124278741Sadrian        ahp->ah_rx_cal_chan = 0;
5125278741Sadrian        ahp->ah_rx_cal_chan_flag = 0; /* XXX FreeBSD */
5126278741Sadrian    }
5127250003Sadrian    ar9300_invalidate_saved_cals(ah, ichan);
5128250003Sadrian    cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr);
5129250003Sadrian
5130250003Sadrian#if ATH_SUPPORT_MCI
5131250008Sadrian    if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) {
5132250008Sadrian        if (IS_CHAN_2GHZ(ichan) &&
5133250003Sadrian            (ahp->ah_mci_bt_state == MCI_BT_SLEEP))
5134250003Sadrian        {
5135250003Sadrian            if (ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
5136250003Sadrian                ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))
5137250003Sadrian            {
5138250003Sadrian                /*
5139250003Sadrian                 * BT is sleeping. Check if BT wakes up duing WLAN
5140250003Sadrian                 * calibration. If BT wakes up during WLAN calibration, need
5141250003Sadrian                 * to go through all message exchanges again and recal.
5142250003Sadrian                 */
5143250003Sadrian                HALDEBUG(ah, HAL_DEBUG_BT_COEX,
5144250003Sadrian                    "(MCI) ### %s: BT wakes up during WLAN calibration.\n",
5145250003Sadrian                    __func__);
5146250003Sadrian                OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
5147250003Sadrian                        AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
5148250003Sadrian                        AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
5149250003Sadrian                HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) send REMOTE_RESET\n");
5150250003Sadrian                ar9300_mci_remote_reset(ah, AH_TRUE);
5151250003Sadrian                ar9300_mci_send_sys_waking(ah, AH_TRUE);
5152250003Sadrian                OS_DELAY(1);
5153250008Sadrian                if (IS_CHAN_2GHZ(ichan)) {
5154250003Sadrian                    ar9300_mci_send_lna_transfer(ah, AH_TRUE);
5155250003Sadrian                }
5156250003Sadrian                ahp->ah_mci_bt_state = MCI_BT_AWAKE;
5157250003Sadrian
5158250003Sadrian                /* Redo calibration */
5159250003Sadrian                HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Re-calibrate.\n",
5160250003Sadrian                    __func__);
5161250003Sadrian                ar9300_invalidate_saved_cals(ah, ichan);
5162250008Sadrian                cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr);
5163250003Sadrian            }
5164250003Sadrian        }
5165250003Sadrian        ar9300_mci_enable_interrupt(ah);
5166250003Sadrian    }
5167250003Sadrian#endif
5168250003Sadrian
5169250003Sadrian    if (!cal_ret) {
5170250003Sadrian        HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Init Cal Failed\n", __func__);
5171250003Sadrian        FAIL(HAL_ESELFTEST);
5172250003Sadrian    }
5173250003Sadrian
5174250003Sadrian    ar9300_init_txbf(ah);
5175250003Sadrian#if 0
5176250003Sadrian    /*
5177250003Sadrian     * WAR for owl 1.0 - restore chain mask for 2-chain cfgs after cal
5178250003Sadrian     */
5179250003Sadrian    rx_chainmask = ahp->ah_rx_chainmask;
5180250003Sadrian    if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
5181250003Sadrian        OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
5182250003Sadrian        OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
5183250003Sadrian    }
5184250003Sadrian#endif
5185250003Sadrian
5186250003Sadrian    /* Restore previous led state */
5187250003Sadrian    OS_REG_WRITE(ah, AR_CFG_LED, save_led_state | AR_CFG_SCLK_32KHZ);
5188250003Sadrian
5189250008Sadrian#if ATH_BT_COEX
5190250003Sadrian    if (ahp->ah_bt_coex_config_type != HAL_BT_COEX_CFG_NONE) {
5191250003Sadrian        ar9300_init_bt_coex(ah);
5192250003Sadrian
5193250003Sadrian#if ATH_SUPPORT_MCI
5194250008Sadrian        if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) {
5195250003Sadrian            /* Check BT state again to make sure it's not changed. */
5196250003Sadrian            ar9300_mci_sync_bt_state(ah);
5197250003Sadrian            ar9300_mci_2g5g_switch(ah, AH_TRUE);
5198250003Sadrian
5199250003Sadrian            if ((ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&
5200250003Sadrian                (ahp->ah_mci_query_bt == AH_TRUE))
5201250003Sadrian            {
5202250003Sadrian                ahp->ah_mci_need_flush_btinfo = AH_TRUE;
5203250003Sadrian            }
5204250003Sadrian        }
5205250003Sadrian#endif
5206250003Sadrian    }
5207250003Sadrian#endif
5208250003Sadrian
5209250003Sadrian    /* Start TSF2 for generic timer 8-15. */
5210250003Sadrian    ar9300_start_tsf2(ah);
5211250003Sadrian
5212250003Sadrian    /* MIMO Power save setting */
5213250003Sadrian    if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) == HAL_OK) {
5214250003Sadrian        ar9300_set_sm_power_mode(ah, ahp->ah_sm_power_mode);
5215250003Sadrian    }
5216250003Sadrian
5217250003Sadrian    /*
5218250003Sadrian     * For big endian systems turn on swapping for descriptors
5219250003Sadrian     */
5220250003Sadrian#if AH_BYTE_ORDER == AH_BIG_ENDIAN
5221291437Sadrian    if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
5222250003Sadrian        OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB, 0);
5223250003Sadrian    } else {
5224250003Sadrian        ar9300_init_cfg_reg(ah);
5225250003Sadrian    }
5226250003Sadrian#endif
5227250003Sadrian
5228291437Sadrian    if ( AR_SREV_OSPREY(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah) ) {
5229250003Sadrian        OS_REG_RMW(ah, AR_CFG_LED, AR_CFG_LED_ASSOC_CTL, AR_CFG_LED_ASSOC_CTL);
5230250003Sadrian    }
5231250003Sadrian
5232250003Sadrian#if !(defined(ART_BUILD)) && defined(ATH_SUPPORT_LED)
5233250003Sadrian#define REG_WRITE(_reg, _val)   *((volatile u_int32_t *)(_reg)) = (_val);
5234250003Sadrian#define REG_READ(_reg)          *((volatile u_int32_t *)(_reg))
5235250003Sadrian#define ATH_GPIO_OUT_FUNCTION3  0xB8040038
5236250003Sadrian#define ATH_GPIO_OE             0xB8040000
5237250003Sadrian    if ( AR_SREV_WASP(ah)) {
5238250003Sadrian        if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {
5239250003Sadrian            REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x33 << 8) );
5240250003Sadrian            REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )));
5241250003Sadrian        }
5242250003Sadrian        else {
5243250003Sadrian
5244250003Sadrian            /* Disable 2G WLAN LED. During ath_open, reset function is called even before channel is set.
5245250003Sadrian            So 2GHz is taken as default and it also blinks. Hence
5246250003Sadrian            to avoid both from blinking, disable 2G led while in 5G mode */
5247250003Sadrian
5248250003Sadrian            REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) | (1 << 13) ));
5249250003Sadrian            REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x33) );
5250250003Sadrian            REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )));
5251250003Sadrian        }
5252250003Sadrian
5253250003Sadrian    }
5254250003Sadrian    else if (AR_SREV_SCORPION(ah)) {
5255250003Sadrian        if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {
5256250003Sadrian            REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x2F << 8) );
5257250003Sadrian    	    REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )) | (0x1 << 12)));
5258250003Sadrian        } else if (IS_CHAN_5GHZ((AH_PRIVATE(ah)->ah_curchan))) {
5259250003Sadrian            REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x2F) );
5260250003Sadrian    	    REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )) | (0x1 << 13)));
5261250003Sadrian        }
5262250003Sadrian    }
5263291437Sadrian    else if (AR_SREV_HONEYBEE(ah)) {
5264291437Sadrian            REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x32) );
5265291437Sadrian            REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) ))));
5266291437Sadrian    }
5267250003Sadrian#undef REG_READ
5268250003Sadrian#undef REG_WRITE
5269250003Sadrian#endif
5270250003Sadrian
5271250008Sadrian    /* XXX FreeBSD What's this? -adrian */
5272250008Sadrian#if 0
5273250003Sadrian    chan->channel_flags = ichan->channel_flags;
5274250003Sadrian    chan->priv_flags = ichan->priv_flags;
5275250008Sadrian#endif
5276250003Sadrian
5277250003Sadrian#if FIX_NOISE_FLOOR
5278250008Sadrian    /* XXX FreeBSD is ichan appropariate? It was curchan.. */
5279250008Sadrian    ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);
5280250003Sadrian    ar9300_load_nf(ah, nf_buf);
5281250003Sadrian    if (nf_hist_buff_reset == 1)
5282250003Sadrian    {
5283250003Sadrian        nf_hist_buff_reset = 0;
5284250003Sadrian    #ifndef ATH_NF_PER_CHAN
5285250003Sadrian	    if (First_NFCal(ah, ichan, is_scan, chan)){
5286278741Sadrian            if (ahp->ah_skip_rx_iq_cal && !is_scan) {
5287278741Sadrian                /* restore RX Cal result if existing */
5288278741Sadrian                ar9300_rx_iq_cal_restore(ah);
5289278741Sadrian                ahp->ah_skip_rx_iq_cal = AH_FALSE;
5290278741Sadrian            }
5291250003Sadrian        }
5292250003Sadrian    #endif /* ATH_NF_PER_CHAN */
5293250003Sadrian    }
5294250003Sadrian    else{
5295250003Sadrian        ar9300_start_nf_cal(ah);
5296250003Sadrian    }
5297250003Sadrian#endif
5298250003Sadrian
5299250003Sadrian#ifdef AH_SUPPORT_AR9300
5300250003Sadrian    /* BB Panic Watchdog */
5301250003Sadrian    if (ar9300_get_capability(ah, HAL_CAP_BB_PANIC_WATCHDOG, 0, AH_NULL) ==
5302250003Sadrian        HAL_OK)
5303250003Sadrian    {
5304250003Sadrian        ar9300_config_bb_panic_watchdog(ah);
5305250003Sadrian    }
5306250003Sadrian#endif
5307250003Sadrian
5308250003Sadrian    /* While receiving unsupported rate frame receive state machine
5309250003Sadrian     * gets into a state 0xb and if phy_restart happens when rx
5310250003Sadrian     * state machine is in 0xb state, BB would go hang, if we
5311250003Sadrian     * see 0xb state after first bb panic, make sure that we
5312250003Sadrian     * disable the phy_restart.
5313250003Sadrian     *
5314250003Sadrian     * There may be multiple panics, make sure that we always do
5315250003Sadrian     * this if we see this panic at least once. This is required
5316250003Sadrian     * because reset seems to be writing from INI file.
5317250003Sadrian     */
5318250003Sadrian    if ((ar9300_get_capability(ah, HAL_CAP_PHYRESTART_CLR_WAR, 0, AH_NULL)
5319250008Sadrian         == HAL_OK) && (((MS((AH9300(ah)->ah_bb_panic_last_status),
5320250003Sadrian                AR_PHY_BB_WD_RX_OFDM_SM)) == 0xb) ||
5321250008Sadrian            AH9300(ah)->ah_phyrestart_disabled) )
5322250003Sadrian    {
5323250003Sadrian        ar9300_disable_phy_restart(ah, 1);
5324250003Sadrian    }
5325250003Sadrian
5326250003Sadrian
5327250003Sadrian
5328250003Sadrian    ahp->ah_radar1 = MS(OS_REG_READ(ah, AR_PHY_RADAR_1),
5329250003Sadrian                        AR_PHY_RADAR_1_CF_BIN_THRESH);
5330250003Sadrian    ahp->ah_dc_offset = MS(OS_REG_READ(ah, AR_PHY_TIMING2),
5331250003Sadrian                        AR_PHY_TIMING2_DC_OFFSET);
5332250003Sadrian    ahp->ah_disable_cck = MS(OS_REG_READ(ah, AR_PHY_MODE),
5333250003Sadrian                        AR_PHY_MODE_DISABLE_CCK);
5334250003Sadrian
5335250008Sadrian    if (AH9300(ah)->ah_enable_keysearch_always) {
5336250003Sadrian        ar9300_enable_keysearch_always(ah, 1);
5337250003Sadrian    }
5338250003Sadrian
5339250003Sadrian#if ATH_LOW_POWER_ENABLE
5340250003Sadrian#define REG_WRITE(_reg, _val)   *((volatile u_int32_t *)(_reg)) = (_val)
5341250003Sadrian#define REG_READ(_reg)      *((volatile u_int32_t *)(_reg))
5342250003Sadrian    if (AR_SREV_OSPREY(ah)) {
5343250003Sadrian        REG_WRITE(0xb4000080, REG_READ(0xb4000080) | 3);
5344250003Sadrian        OS_REG_WRITE(ah, AR_RTC_RESET, 1);
5345250003Sadrian        OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL),
5346250003Sadrian                        AR_PCIE_PM_CTRL_ENA);
5347250003Sadrian        OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_SPARE), 0xffffffff);
5348250003Sadrian    }
5349250003Sadrian#undef REG_READ
5350250003Sadrian#undef REG_WRITE
5351250003Sadrian#endif  /* ATH_LOW_POWER_ENABLE */
5352250003Sadrian
5353250003Sadrian    WAR_USB_DISABLE_PLL_LOCK_DETECT(ah);
5354250003Sadrian
5355250003Sadrian    /* H/W Green TX */
5356250003Sadrian    ar9300_control_signals_for_green_tx_mode(ah);
5357250003Sadrian    /* Smart Antenna, only for 5GHz on Scropion */
5358250008Sadrian    if (IEEE80211_IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan)) && AR_SREV_SCORPION(ah)) {
5359250003Sadrian        ahp->ah_smartantenna_enable = 0;
5360250003Sadrian    }
5361250003Sadrian
5362250003Sadrian    ar9300_set_smart_antenna(ah, ahp->ah_smartantenna_enable);
5363250003Sadrian
5364301094Sadrian    if (AR_SREV_APHRODITE(ah) && ahp->ah_lna_div_use_bt_ant_enable)
5365301094Sadrian        OS_REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
5366301094Sadrian
5367278741Sadrian    if (ahp->ah_skip_rx_iq_cal && !is_scan) {
5368278741Sadrian        /* restore RX Cal result if existing */
5369278741Sadrian        ar9300_rx_iq_cal_restore(ah);
5370278741Sadrian        ahp->ah_skip_rx_iq_cal = AH_FALSE;
5371278741Sadrian    }
5372250003Sadrian
5373278741Sadrian
5374250003Sadrian    return AH_TRUE;
5375250003Sadrianbad:
5376250003Sadrian    OS_MARK(ah, AH_MARK_RESET_DONE, ecode);
5377250003Sadrian    *status = ecode;
5378250003Sadrian
5379278741Sadrian    if (ahp->ah_skip_rx_iq_cal && !is_scan) {
5380278741Sadrian        /* restore RX Cal result if existing */
5381278741Sadrian        ar9300_rx_iq_cal_restore(ah);
5382278741Sadrian        ahp->ah_skip_rx_iq_cal = AH_FALSE;
5383278741Sadrian    }
5384278741Sadrian
5385250003Sadrian    return AH_FALSE;
5386250003Sadrian#undef FAIL
5387250003Sadrian}
5388250003Sadrian
5389250003Sadrianvoid
5390250003Sadrianar9300_green_ap_ps_on_off( struct ath_hal *ah, u_int16_t on_off)
5391250003Sadrian{
5392250003Sadrian    /* Set/reset the ps flag */
5393250008Sadrian    AH9300(ah)->green_ap_ps_on = !!on_off;
5394250003Sadrian}
5395250003Sadrian
5396250003Sadrian/*
5397250003Sadrian * This function returns 1, where it is possible to do
5398250003Sadrian * single-chain power save.
5399250003Sadrian */
5400250003Sadrianu_int16_t
5401250003Sadrianar9300_is_single_ant_power_save_possible(struct ath_hal *ah)
5402250003Sadrian{
5403250003Sadrian    return AH_TRUE;
5404250003Sadrian}
5405250003Sadrian
5406250003Sadrian/* To avoid compilation warnings. Functions not used when EMULATION. */
5407250003Sadrian/*
5408250003Sadrian * ar9300_find_mag_approx()
5409250003Sadrian */
5410250003Sadrianstatic int32_t
5411250003Sadrianar9300_find_mag_approx(struct ath_hal *ah, int32_t in_re, int32_t in_im)
5412250003Sadrian{
5413250003Sadrian    int32_t abs_i = abs(in_re);
5414250003Sadrian    int32_t abs_q = abs(in_im);
5415250003Sadrian    int32_t max_abs, min_abs;
5416250003Sadrian
5417250003Sadrian    if (abs_i > abs_q) {
5418250003Sadrian        max_abs = abs_i;
5419250003Sadrian        min_abs = abs_q;
5420250003Sadrian    } else {
5421250003Sadrian        max_abs = abs_q;
5422250003Sadrian        min_abs = abs_i;
5423250003Sadrian    }
5424250003Sadrian
5425250003Sadrian    return (max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4));
5426250003Sadrian}
5427250003Sadrian
5428250003Sadrian/*
5429250003Sadrian * ar9300_solve_iq_cal()
5430250003Sadrian * solve 4x4 linear equation used in loopback iq cal.
5431250003Sadrian */
5432250003Sadrianstatic HAL_BOOL
5433250003Sadrianar9300_solve_iq_cal(
5434250003Sadrian    struct ath_hal *ah,
5435250003Sadrian    int32_t sin_2phi_1,
5436250003Sadrian    int32_t cos_2phi_1,
5437250003Sadrian    int32_t sin_2phi_2,
5438250003Sadrian    int32_t cos_2phi_2,
5439250003Sadrian    int32_t mag_a0_d0,
5440250003Sadrian    int32_t phs_a0_d0,
5441250003Sadrian    int32_t mag_a1_d0,
5442250003Sadrian    int32_t phs_a1_d0,
5443250003Sadrian    int32_t solved_eq[])
5444250003Sadrian{
5445250003Sadrian    int32_t f1 = cos_2phi_1 - cos_2phi_2;
5446250003Sadrian    int32_t f3 = sin_2phi_1 - sin_2phi_2;
5447250003Sadrian    int32_t f2;
5448250003Sadrian    int32_t mag_tx, phs_tx, mag_rx, phs_rx;
5449250003Sadrian    const int32_t result_shift = 1 << 15;
5450250003Sadrian
5451250003Sadrian    f2 = (((int64_t)f1 * (int64_t)f1) / result_shift) + (((int64_t)f3 * (int64_t)f3) / result_shift);
5452250003Sadrian
5453250003Sadrian    if (0 == f2) {
5454250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d).\n",
5455250003Sadrian            __func__, __LINE__);
5456250003Sadrian        return AH_FALSE;
5457250003Sadrian    }
5458250003Sadrian
5459250003Sadrian    /* magnitude mismatch, tx */
5460250003Sadrian    mag_tx = f1 * (mag_a0_d0  - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
5461250003Sadrian    /* phase mismatch, tx */
5462250003Sadrian    phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
5463250003Sadrian
5464250003Sadrian    mag_tx = (mag_tx / f2);
5465250003Sadrian    phs_tx = (phs_tx / f2);
5466250003Sadrian
5467250003Sadrian    /* magnitude mismatch, rx */
5468250003Sadrian    mag_rx =
5469250003Sadrian        mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / result_shift;
5470250003Sadrian    /* phase mismatch, rx */
5471250003Sadrian    phs_rx =
5472250003Sadrian        phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / result_shift;
5473250003Sadrian
5474250003Sadrian    solved_eq[0] = mag_tx;
5475250003Sadrian    solved_eq[1] = phs_tx;
5476250003Sadrian    solved_eq[2] = mag_rx;
5477250003Sadrian    solved_eq[3] = phs_rx;
5478250003Sadrian
5479250003Sadrian    return AH_TRUE;
5480250003Sadrian}
5481250003Sadrian
5482250003Sadrian/*
5483250003Sadrian * ar9300_calc_iq_corr()
5484250003Sadrian */
5485250003Sadrianstatic HAL_BOOL
5486250003Sadrianar9300_calc_iq_corr(struct ath_hal *ah, int32_t chain_idx,
5487250003Sadrian    const int32_t iq_res[], int32_t iqc_coeff[])
5488250003Sadrian{
5489250003Sadrian    int32_t i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0;
5490250003Sadrian    int32_t i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1;
5491250003Sadrian    int32_t i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0;
5492250003Sadrian    int32_t i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
5493250003Sadrian    int32_t mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1;
5494250003Sadrian    int32_t phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1;
5495250003Sadrian    int32_t sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2;
5496250003Sadrian    int32_t mag_tx, phs_tx, mag_rx, phs_rx;
5497250003Sadrian    int32_t solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx;
5498250003Sadrian    int32_t q_q_coff, q_i_coff;
5499250003Sadrian    const int32_t res_scale = 1 << 15;
5500250003Sadrian    const int32_t delpt_shift = 1 << 8;
5501250003Sadrian    int32_t mag1, mag2;
5502250003Sadrian
5503250003Sadrian    i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
5504250003Sadrian    i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
5505250003Sadrian    iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
5506250003Sadrian
5507250003Sadrian    if (i2_m_q2_a0_d0 > 0x800)  {
5508250003Sadrian        i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
5509250003Sadrian    }
5510250003Sadrian    if (iq_corr_a0_d0 > 0x800)  {
5511250003Sadrian        iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
5512250003Sadrian    }
5513250003Sadrian
5514250003Sadrian    i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
5515250003Sadrian    i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
5516250003Sadrian    iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
5517250003Sadrian
5518250003Sadrian    if (i2_m_q2_a0_d1 > 0x800)  {
5519250003Sadrian        i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
5520250003Sadrian    }
5521250003Sadrian    if (iq_corr_a0_d1 > 0x800)  {
5522250003Sadrian        iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
5523250003Sadrian    }
5524250003Sadrian
5525250003Sadrian    i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
5526250003Sadrian    i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
5527250003Sadrian    iq_corr_a1_d0 = iq_res[4] & 0xfff;
5528250003Sadrian
5529250003Sadrian    if (i2_m_q2_a1_d0 > 0x800)  {
5530250003Sadrian        i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
5531250003Sadrian    }
5532250003Sadrian    if (iq_corr_a1_d0 > 0x800)  {
5533250003Sadrian        iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
5534250003Sadrian    }
5535250003Sadrian
5536250003Sadrian    i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
5537250003Sadrian    i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
5538250003Sadrian    iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
5539250003Sadrian
5540250003Sadrian    if (i2_m_q2_a1_d1 > 0x800)  {
5541250003Sadrian        i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
5542250003Sadrian    }
5543250003Sadrian    if (iq_corr_a1_d1 > 0x800)  {
5544250003Sadrian        iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
5545250003Sadrian    }
5546250003Sadrian
5547250003Sadrian    if ((i2_p_q2_a0_d0 == 0) ||
5548250003Sadrian        (i2_p_q2_a0_d1 == 0) ||
5549250003Sadrian        (i2_p_q2_a1_d0 == 0) ||
5550250003Sadrian        (i2_p_q2_a1_d1 == 0)) {
5551250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5552250003Sadrian            "%s: Divide by 0(%d):\na0_d0=%d\na0_d1=%d\na2_d0=%d\na1_d1=%d\n",
5553250003Sadrian            __func__, __LINE__,
5554250003Sadrian            i2_p_q2_a0_d0, i2_p_q2_a0_d1, i2_p_q2_a1_d0, i2_p_q2_a1_d1);
5555250003Sadrian        return AH_FALSE;
5556250003Sadrian    }
5557250003Sadrian
5558250003Sadrian    if ((i2_p_q2_a0_d0 <= 1024) || (i2_p_q2_a0_d0 > 2047) ||
5559250003Sadrian            (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||
5560250003Sadrian            (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||
5561250003Sadrian            (i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||
5562250003Sadrian            (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||
5563250003Sadrian            (i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||
5564250003Sadrian            (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||
5565250003Sadrian            (i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||
5566250003Sadrian            (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||
5567250003Sadrian            (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {
5568250003Sadrian        return AH_FALSE;
5569250003Sadrian    }
5570250003Sadrian
5571250003Sadrian    mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
5572250003Sadrian    phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
5573250003Sadrian
5574250003Sadrian    mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
5575250003Sadrian    phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
5576250003Sadrian
5577250003Sadrian    mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
5578250003Sadrian    phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
5579250003Sadrian
5580250003Sadrian    mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
5581250003Sadrian    phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
5582250003Sadrian
5583250003Sadrian    /* without analog phase shift */
5584250003Sadrian    sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);
5585250003Sadrian    /* without analog phase shift */
5586250003Sadrian    cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);
5587250003Sadrian    /* with  analog phase shift */
5588250003Sadrian    sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);
5589250003Sadrian    /* with analog phase shift */
5590250003Sadrian    cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);
5591250003Sadrian
5592250003Sadrian    /* force sin^2 + cos^2 = 1; */
5593250003Sadrian    /* find magnitude by approximation */
5594250003Sadrian    mag1 = ar9300_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
5595250003Sadrian    mag2 = ar9300_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
5596250003Sadrian
5597250003Sadrian    if ((mag1 == 0) || (mag2 == 0)) {
5598250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5599250003Sadrian            "%s: Divide by 0(%d): mag1=%d, mag2=%d\n",
5600250003Sadrian            __func__, __LINE__, mag1, mag2);
5601250003Sadrian        return AH_FALSE;
5602250003Sadrian    }
5603250003Sadrian
5604250003Sadrian    /* normalization sin and cos by mag */
5605250003Sadrian    sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
5606250003Sadrian    cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
5607250003Sadrian    sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
5608250003Sadrian    cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
5609250003Sadrian
5610250003Sadrian    /* calculate IQ mismatch */
5611250008Sadrian    if (AH_FALSE == ar9300_solve_iq_cal(ah,
5612250003Sadrian            sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2, mag_a0_d0,
5613250003Sadrian            phs_a0_d0, mag_a1_d0, phs_a1_d0, solved_eq))
5614250003Sadrian    {
5615250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5616250003Sadrian            "%s: Call to ar9300_solve_iq_cal failed.\n", __func__);
5617250003Sadrian        return AH_FALSE;
5618250003Sadrian    }
5619250003Sadrian
5620250003Sadrian    mag_tx = solved_eq[0];
5621250003Sadrian    phs_tx = solved_eq[1];
5622250003Sadrian    mag_rx = solved_eq[2];
5623250003Sadrian    phs_rx = solved_eq[3];
5624250003Sadrian
5625250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5626250003Sadrian        "%s: chain %d: mag mismatch=%d phase mismatch=%d\n",
5627250003Sadrian        __func__, chain_idx, mag_tx / res_scale, phs_tx / res_scale);
5628250003Sadrian
5629250003Sadrian    if (res_scale == mag_tx) {
5630250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5631250003Sadrian            "%s: Divide by 0(%d): mag_tx=%d, res_scale=%d\n",
5632250003Sadrian            __func__, __LINE__, mag_tx, res_scale);
5633250003Sadrian        return AH_FALSE;
5634250003Sadrian    }
5635250003Sadrian
5636250003Sadrian    /* calculate and quantize Tx IQ correction factor */
5637250003Sadrian    mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
5638250003Sadrian    phs_corr_tx = -phs_tx;
5639250003Sadrian
5640250003Sadrian    q_q_coff = (mag_corr_tx * 128 / res_scale);
5641250003Sadrian    q_i_coff = (phs_corr_tx * 256 / res_scale);
5642250003Sadrian
5643250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5644250003Sadrian        "%s: tx chain %d: mag corr=%d  phase corr=%d\n",
5645250003Sadrian        __func__, chain_idx, q_q_coff, q_i_coff);
5646250003Sadrian
5647250003Sadrian    if (q_i_coff < -63) {
5648250003Sadrian        q_i_coff = -63;
5649250003Sadrian    }
5650250003Sadrian    if (q_i_coff > 63) {
5651250003Sadrian        q_i_coff = 63;
5652250003Sadrian    }
5653250003Sadrian    if (q_q_coff < -63) {
5654250003Sadrian        q_q_coff = -63;
5655250003Sadrian    }
5656250003Sadrian    if (q_q_coff > 63) {
5657250003Sadrian        q_q_coff = 63;
5658250003Sadrian    }
5659250003Sadrian
5660250003Sadrian    iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
5661250003Sadrian
5662250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: tx chain %d: iq corr coeff=%x\n",
5663250003Sadrian        __func__, chain_idx, iqc_coeff[0]);
5664250003Sadrian
5665250003Sadrian    if (-mag_rx == res_scale) {
5666250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5667250003Sadrian            "%s: Divide by 0(%d): mag_rx=%d, res_scale=%d\n",
5668250003Sadrian            __func__, __LINE__, mag_rx, res_scale);
5669250003Sadrian        return AH_FALSE;
5670250003Sadrian    }
5671250003Sadrian
5672250003Sadrian    /* calculate and quantize Rx IQ correction factors */
5673250003Sadrian    mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
5674250003Sadrian    phs_corr_rx = -phs_rx;
5675250003Sadrian
5676250003Sadrian    q_q_coff = (mag_corr_rx * 128 / res_scale);
5677250003Sadrian    q_i_coff = (phs_corr_rx * 256 / res_scale);
5678250003Sadrian
5679250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5680250003Sadrian        "%s: rx chain %d: mag corr=%d  phase corr=%d\n",
5681250003Sadrian        __func__, chain_idx, q_q_coff, q_i_coff);
5682250003Sadrian
5683250003Sadrian    if (q_i_coff < -63) {
5684250003Sadrian        q_i_coff = -63;
5685250003Sadrian    }
5686250003Sadrian    if (q_i_coff > 63) {
5687250003Sadrian        q_i_coff = 63;
5688250003Sadrian    }
5689250003Sadrian    if (q_q_coff < -63) {
5690250003Sadrian        q_q_coff = -63;
5691250003Sadrian    }
5692250003Sadrian    if (q_q_coff > 63) {
5693250003Sadrian        q_q_coff = 63;
5694250003Sadrian    }
5695250003Sadrian
5696250003Sadrian    iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
5697250003Sadrian
5698250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: rx chain %d: iq corr coeff=%x\n",
5699250003Sadrian        __func__, chain_idx, iqc_coeff[1]);
5700250003Sadrian
5701250003Sadrian    return AH_TRUE;
5702250003Sadrian}
5703250003Sadrian
5704250003Sadrian#define MAX_MAG_DELTA 11 //maximum magnitude mismatch delta across gains
5705250003Sadrian#define MAX_PHS_DELTA 10 //maximum phase mismatch delta across gains
5706250003Sadrian#define ABS(x) ((x) >= 0 ? (x) : (-(x)))
5707250003Sadrian
5708250003Sadrian    u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {
5709250003Sadrian    {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
5710250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
5711250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
5712250003Sadrian    {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
5713250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
5714250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
5715250003Sadrian    {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
5716250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
5717250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
5718250003Sadrian    {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
5719250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
5720250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
5721250003Sadrian    {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
5722250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
5723250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
5724250003Sadrian    {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
5725250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
5726250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
5727250003Sadrian    {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
5728250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
5729250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
5730250003Sadrian    {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
5731250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
5732250003Sadrian        AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
5733250003Sadrian    };
5734250003Sadrian
5735250003Sadrianstatic void
5736250003Sadrianar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, u_int32_t num_chains,
5737250008Sadrian    struct coeff_t *coeff, HAL_BOOL is_cal_reusable)
5738250003Sadrian{
5739250003Sadrian    int nmeasurement, ch_idx, im;
5740250003Sadrian    int32_t magnitude, phase;
5741250003Sadrian    int32_t magnitude_max, phase_max;
5742250003Sadrian    int32_t magnitude_min, phase_min;
5743250003Sadrian
5744250003Sadrian    int32_t magnitude_max_idx, phase_max_idx;
5745250003Sadrian    int32_t magnitude_min_idx, phase_min_idx;
5746250003Sadrian
5747250003Sadrian    int32_t magnitude_avg, phase_avg;
5748250003Sadrian    int32_t outlier_mag_idx = 0;
5749250003Sadrian    int32_t outlier_phs_idx = 0;
5750250003Sadrian
5751250003Sadrian
5752250003Sadrian    if (AR_SREV_POSEIDON(ah)) {
5753250003Sadrian        HALASSERT(num_chains == 0x1);
5754250003Sadrian
5755250003Sadrian        tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;
5756250003Sadrian        tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;
5757250003Sadrian        tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;
5758250003Sadrian        tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;
5759250003Sadrian        tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;
5760250003Sadrian        tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;
5761250003Sadrian        tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;
5762250003Sadrian        tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;
5763250003Sadrian    }
5764250003Sadrian
5765250003Sadrian    for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {
5766250003Sadrian        nmeasurement = OS_REG_READ_FIELD(ah,
5767250003Sadrian            AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0);
5768250003Sadrian        if (nmeasurement > MAX_MEASUREMENT) {
5769250003Sadrian            nmeasurement = MAX_MEASUREMENT;
5770250003Sadrian        }
5771250003Sadrian
5772250003Sadrian        if (!AR_SREV_SCORPION(ah)) {
5773250003Sadrian            /*
5774250003Sadrian             * reset max/min variable to min/max values so that
5775250003Sadrian             * we always start with 1st calibrated gain value
5776250003Sadrian             */
5777250003Sadrian            magnitude_max = -64;
5778250003Sadrian            phase_max     = -64;
5779250003Sadrian            magnitude_min = 63;
5780250003Sadrian            phase_min     = 63;
5781250003Sadrian            magnitude_avg = 0;
5782250003Sadrian            phase_avg     = 0;
5783250003Sadrian            magnitude_max_idx = 0;
5784250003Sadrian            magnitude_min_idx = 0;
5785250003Sadrian            phase_max_idx = 0;
5786250003Sadrian            phase_min_idx = 0;
5787250003Sadrian
5788250003Sadrian            /* detect outlier only if nmeasurement > 1 */
5789250003Sadrian            if (nmeasurement > 1) {
5790250003Sadrian                /* printf("----------- start outlier detection -----------\n"); */
5791250003Sadrian                /*
5792250003Sadrian                 * find max/min and phase/mag mismatch across all calibrated gains
5793250003Sadrian                 */
5794250003Sadrian                for (im = 0; im < nmeasurement; im++) {
5795250003Sadrian                    magnitude = coeff->mag_coeff[ch_idx][im][0];
5796250003Sadrian                    phase = coeff->phs_coeff[ch_idx][im][0];
5797250003Sadrian
5798250003Sadrian                    magnitude_avg = magnitude_avg + magnitude;
5799250003Sadrian                    phase_avg = phase_avg + phase;
5800250003Sadrian                    if (magnitude > magnitude_max) {
5801250003Sadrian                        magnitude_max = magnitude;
5802250003Sadrian                        magnitude_max_idx = im;
5803250003Sadrian                    }
5804250003Sadrian                    if (magnitude < magnitude_min) {
5805250003Sadrian                        magnitude_min = magnitude;
5806250003Sadrian                        magnitude_min_idx = im;
5807250003Sadrian                    }
5808250003Sadrian                    if (phase > phase_max) {
5809250003Sadrian                        phase_max = phase;
5810250003Sadrian                        phase_max_idx = im;
5811250003Sadrian                    }
5812250003Sadrian                    if (phase < phase_min) {
5813250003Sadrian                        phase_min = phase;
5814250003Sadrian                        phase_min_idx = im;
5815250003Sadrian                    }
5816250003Sadrian                }
5817250003Sadrian                /* find average (exclude max abs value) */
5818250003Sadrian                for (im = 0; im < nmeasurement; im++) {
5819250003Sadrian                    magnitude = coeff->mag_coeff[ch_idx][im][0];
5820250003Sadrian                    phase = coeff->phs_coeff[ch_idx][im][0];
5821250003Sadrian                    if ((ABS(magnitude) < ABS(magnitude_max)) ||
5822250003Sadrian                        (ABS(magnitude) < ABS(magnitude_min)))
5823250003Sadrian                    {
5824250003Sadrian                        magnitude_avg = magnitude_avg + magnitude;
5825250003Sadrian                    }
5826250003Sadrian                    if ((ABS(phase) < ABS(phase_max)) ||
5827250003Sadrian                        (ABS(phase) < ABS(phase_min)))
5828250003Sadrian                    {
5829250003Sadrian                        phase_avg = phase_avg + phase;
5830250003Sadrian                    }
5831250003Sadrian                }
5832250003Sadrian                magnitude_avg = magnitude_avg / (nmeasurement - 1);
5833250003Sadrian                phase_avg = phase_avg / (nmeasurement - 1);
5834250003Sadrian
5835250003Sadrian                /* detect magnitude outlier */
5836250003Sadrian                if (ABS(magnitude_max - magnitude_min) > MAX_MAG_DELTA) {
5837250003Sadrian                    if (ABS(magnitude_max - magnitude_avg) >
5838250003Sadrian                        ABS(magnitude_min - magnitude_avg))
5839250003Sadrian                    {
5840250003Sadrian                        /* max is outlier, force to avg */
5841250003Sadrian                        outlier_mag_idx = magnitude_max_idx;
5842250003Sadrian                    } else {
5843250003Sadrian                        /* min is outlier, force to avg */
5844250003Sadrian                        outlier_mag_idx = magnitude_min_idx;
5845250003Sadrian                    }
5846250003Sadrian                    coeff->mag_coeff[ch_idx][outlier_mag_idx][0] = magnitude_avg;
5847250003Sadrian                    coeff->phs_coeff[ch_idx][outlier_mag_idx][0] = phase_avg;
5848250003Sadrian                    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5849250003Sadrian                        "[ch%d][outlier mag gain%d]:: "
5850250003Sadrian                        "mag_avg = %d (/128), phase_avg = %d (/256)\n",
5851250003Sadrian                        ch_idx, outlier_mag_idx, magnitude_avg, phase_avg);
5852250003Sadrian                }
5853250003Sadrian                /* detect phase outlier */
5854250003Sadrian                if (ABS(phase_max - phase_min) > MAX_PHS_DELTA) {
5855250003Sadrian                    if (ABS(phase_max-phase_avg) > ABS(phase_min - phase_avg)) {
5856250003Sadrian                        /* max is outlier, force to avg */
5857250003Sadrian                        outlier_phs_idx = phase_max_idx;
5858250003Sadrian                    } else{
5859250003Sadrian                        /* min is outlier, force to avg */
5860250003Sadrian                        outlier_phs_idx = phase_min_idx;
5861250003Sadrian                    }
5862250003Sadrian                    coeff->mag_coeff[ch_idx][outlier_phs_idx][0] = magnitude_avg;
5863250003Sadrian                    coeff->phs_coeff[ch_idx][outlier_phs_idx][0] = phase_avg;
5864250003Sadrian                    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
5865250003Sadrian                        "[ch%d][outlier phs gain%d]:: "
5866250003Sadrian                        "mag_avg = %d (/128), phase_avg = %d (/256)\n",
5867250003Sadrian                        ch_idx, outlier_phs_idx, magnitude_avg, phase_avg);
5868250003Sadrian                }
5869250003Sadrian            }
5870250003Sadrian        }
5871250003Sadrian
5872250003Sadrian        /*printf("------------ after outlier detection -------------\n");*/
5873250003Sadrian        for (im = 0; im < nmeasurement; im++) {
5874250003Sadrian            magnitude = coeff->mag_coeff[ch_idx][im][0];
5875250003Sadrian            phase = coeff->phs_coeff[ch_idx][im][0];
5876250003Sadrian
5877250003Sadrian            #if 0
5878250003Sadrian            printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n",
5879250003Sadrian                ch_idx, im, magnitude, phase);
5880250003Sadrian            #endif
5881250003Sadrian
5882250003Sadrian            coeff->iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7);
5883250003Sadrian
5884250003Sadrian            if ((im % 2) == 0) {
5885250003Sadrian                OS_REG_RMW_FIELD(ah,
5886250003Sadrian                    tx_corr_coeff[im][ch_idx],
5887250003Sadrian                    AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
5888250003Sadrian                    coeff->iqc_coeff[0]);
5889250003Sadrian            } else {
5890250003Sadrian                OS_REG_RMW_FIELD(ah,
5891250003Sadrian                    tx_corr_coeff[im][ch_idx],
5892250003Sadrian                    AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
5893250003Sadrian                    coeff->iqc_coeff[0]);
5894250003Sadrian            }
5895250003Sadrian#if ATH_SUPPORT_CAL_REUSE
5896250003Sadrian            ichan->tx_corr_coeff[im][ch_idx] = coeff->iqc_coeff[0];
5897250003Sadrian#endif
5898250003Sadrian        }
5899250003Sadrian#if ATH_SUPPORT_CAL_REUSE
5900250003Sadrian        ichan->num_measures[ch_idx] = nmeasurement;
5901250003Sadrian#endif
5902250003Sadrian    }
5903250003Sadrian
5904250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
5905250003Sadrian                     AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
5906250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
5907250003Sadrian                     AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
5908250003Sadrian
5909250003Sadrian#if ATH_SUPPORT_CAL_REUSE
5910250003Sadrian    if (is_cal_reusable) {
5911250003Sadrian        ichan->one_time_txiqcal_done = AH_TRUE;
5912250003Sadrian        HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
5913250003Sadrian            "(FCS) TXIQCAL saved - %d\n", ichan->channel);
5914250003Sadrian    }
5915250003Sadrian#endif
5916250003Sadrian}
5917250003Sadrian
5918250003Sadrian#if ATH_SUPPORT_CAL_REUSE
5919250003Sadrianstatic void
5920250003Sadrianar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
5921250003Sadrian{
5922250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
5923250003Sadrian    int nmeasurement, ch_idx, im;
5924250003Sadrian
5925250003Sadrian    u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {
5926250003Sadrian        {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
5927250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
5928250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
5929250003Sadrian        {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
5930250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
5931250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
5932250003Sadrian        {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
5933250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
5934250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
5935250003Sadrian        {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
5936250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
5937250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
5938250003Sadrian        {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
5939250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
5940250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
5941250003Sadrian        {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
5942250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
5943250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
5944250003Sadrian        {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
5945250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
5946250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
5947250003Sadrian        {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
5948250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
5949250003Sadrian            AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
5950250003Sadrian    };
5951250003Sadrian
5952250003Sadrian    if (AR_SREV_POSEIDON(ah)) {
5953250003Sadrian        HALASSERT(ahp->ah_tx_cal_chainmask == 0x1);
5954250003Sadrian
5955250003Sadrian        tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;
5956250003Sadrian        tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;
5957250003Sadrian        tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;
5958250003Sadrian        tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;
5959250003Sadrian        tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;
5960250003Sadrian        tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;
5961250003Sadrian        tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;
5962250003Sadrian        tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;
5963250003Sadrian    }
5964250003Sadrian
5965250003Sadrian    for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {
5966250003Sadrian        if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {
5967250003Sadrian            continue;
5968250003Sadrian        }
5969250003Sadrian        nmeasurement = ichan->num_measures[ch_idx];
5970250003Sadrian
5971250003Sadrian        for (im = 0; im < nmeasurement; im++) {
5972250003Sadrian            if ((im % 2) == 0) {
5973250003Sadrian                OS_REG_RMW_FIELD(ah,
5974250003Sadrian                    tx_corr_coeff[im][ch_idx],
5975250003Sadrian                    AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
5976250003Sadrian                    ichan->tx_corr_coeff[im][ch_idx]);
5977250003Sadrian            } else {
5978250003Sadrian                OS_REG_RMW_FIELD(ah,
5979250003Sadrian                    tx_corr_coeff[im][ch_idx],
5980250003Sadrian                    AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
5981250003Sadrian                    ichan->tx_corr_coeff[im][ch_idx]);
5982250003Sadrian            }
5983250003Sadrian        }
5984250003Sadrian    }
5985250003Sadrian
5986250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
5987250003Sadrian                     AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
5988250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
5989250003Sadrian                     AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
5990250003Sadrian}
5991250003Sadrian#endif
5992250003Sadrian
5993250003Sadrian/*
5994250003Sadrian * ar9300_tx_iq_cal_hw_run is only needed for osprey/wasp/hornet
5995250003Sadrian * It is not needed for jupiter/poseidon.
5996250003Sadrian */
5997250003SadrianHAL_BOOL
5998250003Sadrianar9300_tx_iq_cal_hw_run(struct ath_hal *ah)
5999250003Sadrian{
6000250003Sadrian    int is_tx_gain_forced;
6001250003Sadrian
6002250003Sadrian    is_tx_gain_forced = OS_REG_READ_FIELD(ah,
6003250003Sadrian        AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE);
6004250003Sadrian    if (is_tx_gain_forced) {
6005250003Sadrian        /*printf("Tx gain can not be forced during tx I/Q cal!\n");*/
6006250003Sadrian        OS_REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0);
6007250003Sadrian    }
6008250003Sadrian
6009250003Sadrian    /* enable tx IQ cal */
6010250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah),
6011250003Sadrian        AR_PHY_TX_IQCAL_START_DO_CAL, AR_PHY_TX_IQCAL_START_DO_CAL);
6012250003Sadrian
6013250003Sadrian    if (!ath_hal_wait(ah,
6014250008Sadrian            AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 0))
6015250003Sadrian    {
6016250003Sadrian        HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
6017250003Sadrian            "%s: Tx IQ Cal is never completed.\n", __func__);
6018250003Sadrian        return AH_FALSE;
6019250003Sadrian    }
6020250003Sadrian    return AH_TRUE;
6021250003Sadrian}
6022250003Sadrian
6023250003Sadrianstatic void
6024250003Sadrianar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan,
6025250003Sadrian                           int iqcal_idx, int max_iqcal,HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr)
6026250003Sadrian{
6027250003Sadrian    int nmeasurement=0, im, ix, iy, temp;
6028250003Sadrian    struct ath_hal_9300     *ahp = AH9300(ah);
6029250003Sadrian    u_int32_t txiqcal_status[AR9300_MAX_CHAINS] = {
6030250003Sadrian        AR_PHY_TX_IQCAL_STATUS_B0(ah),
6031250003Sadrian        AR_PHY_TX_IQCAL_STATUS_B1,
6032250003Sadrian        AR_PHY_TX_IQCAL_STATUS_B2,
6033250003Sadrian    };
6034250003Sadrian    const u_int32_t chan_info_tab[] = {
6035250003Sadrian        AR_PHY_CHAN_INFO_TAB_0,
6036250003Sadrian        AR_PHY_CHAN_INFO_TAB_1,
6037250003Sadrian        AR_PHY_CHAN_INFO_TAB_2,
6038250003Sadrian    };
6039250003Sadrian    int32_t iq_res[6];
6040250003Sadrian    int32_t ch_idx, j;
6041250003Sadrian    u_int32_t num_chains = 0;
6042250003Sadrian    static struct coeff_t coeff;
6043250003Sadrian    txiqcal_status[0] = AR_PHY_TX_IQCAL_STATUS_B0(ah);
6044250003Sadrian
6045250003Sadrian    for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {
6046250003Sadrian        if (ahp->ah_tx_chainmask & (1 << ch_idx)) {
6047250003Sadrian            num_chains++;
6048250003Sadrian        }
6049250003Sadrian    }
6050250003Sadrian
6051250003Sadrian    if (apply_last_corr) {
6052250003Sadrian	    if (coeff.last_cal == AH_TRUE) {
6053250003Sadrian		    int32_t magnitude, phase;
6054250003Sadrian		    int ch_idx, im;
6055250003Sadrian		    u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {
6056250003Sadrian			    {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
6057250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
6058250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
6059250003Sadrian			    {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
6060250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
6061250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
6062250003Sadrian			    {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
6063250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
6064250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
6065250003Sadrian			    {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
6066250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
6067250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
6068250003Sadrian			    {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
6069250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
6070250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
6071250003Sadrian			    {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
6072250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
6073250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
6074250003Sadrian			    {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
6075250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
6076250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
6077250003Sadrian			    {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
6078250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
6079250003Sadrian				    AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
6080250003Sadrian		    };
6081250003Sadrian		    for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {
6082250003Sadrian			    for (im = 0; im < coeff.last_nmeasurement; im++) {
6083250003Sadrian				    magnitude = coeff.mag_coeff[ch_idx][im][0];
6084250003Sadrian				    phase = coeff.phs_coeff[ch_idx][im][0];
6085250003Sadrian
6086250003Sadrian#if 0
6087250003Sadrian				    printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n",
6088250003Sadrian						    ch_idx, im, magnitude, phase);
6089250003Sadrian#endif
6090250003Sadrian
6091250003Sadrian				    coeff.iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7);
6092250003Sadrian				    if ((im % 2) == 0) {
6093250003Sadrian					    OS_REG_RMW_FIELD(ah,
6094250003Sadrian							    tx_corr_coeff[im][ch_idx],
6095250003Sadrian							    AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
6096250003Sadrian							    coeff.iqc_coeff[0]);
6097250003Sadrian				    } else {
6098250003Sadrian					    OS_REG_RMW_FIELD(ah,
6099250003Sadrian							    tx_corr_coeff[im][ch_idx],
6100250003Sadrian							    AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
6101250003Sadrian							    coeff.iqc_coeff[0]);
6102250003Sadrian				    }
6103250003Sadrian			    }
6104250003Sadrian		    }
6105250003Sadrian		    OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
6106250003Sadrian				    AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
6107250003Sadrian	    }
6108250003Sadrian	    return;
6109250003Sadrian    }
6110250003Sadrian
6111250003Sadrian
6112250003Sadrian    for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {
6113250003Sadrian        nmeasurement = OS_REG_READ_FIELD(ah,
6114250003Sadrian            AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0);
6115250003Sadrian        if (nmeasurement > MAX_MEASUREMENT) {
6116250003Sadrian            nmeasurement = MAX_MEASUREMENT;
6117250003Sadrian        }
6118250003Sadrian
6119250003Sadrian        for (im = 0; im < nmeasurement; im++) {
6120250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
6121250003Sadrian                "%s: Doing Tx IQ Cal for chain %d.\n", __func__, ch_idx);
6122250003Sadrian            if (OS_REG_READ(ah, txiqcal_status[ch_idx]) &
6123250003Sadrian                AR_PHY_TX_IQCAL_STATUS_FAILED)
6124250003Sadrian            {
6125250003Sadrian                HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
6126250003Sadrian                    "%s: Tx IQ Cal failed for chain %d.\n", __func__, ch_idx);
6127250003Sadrian                goto TX_IQ_CAL_FAILED_;
6128250003Sadrian            }
6129250003Sadrian
6130250003Sadrian            for (j = 0; j < 3; j++) {
6131250003Sadrian                u_int32_t idx = 2 * j;
6132250003Sadrian                /* 3 registers for each calibration result */
6133250003Sadrian                u_int32_t offset = 4 * (3 * im + j);
6134250003Sadrian
6135250003Sadrian                OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
6136250003Sadrian                    AR_PHY_CHAN_INFO_TAB_S2_READ, 0);
6137250003Sadrian                /* 32 bits */
6138250003Sadrian                iq_res[idx] = OS_REG_READ(ah, chan_info_tab[ch_idx] + offset);
6139250003Sadrian                OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
6140250003Sadrian                    AR_PHY_CHAN_INFO_TAB_S2_READ, 1);
6141250003Sadrian                /* 16 bits */
6142250003Sadrian                iq_res[idx + 1] = 0xffff &
6143250003Sadrian                    OS_REG_READ(ah, chan_info_tab[ch_idx] + offset);
6144250003Sadrian
6145250003Sadrian                HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
6146250003Sadrian                    "%s: IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
6147250003Sadrian                    __func__, idx, iq_res[idx], idx + 1, iq_res[idx + 1]);
6148250003Sadrian            }
6149250003Sadrian
6150250008Sadrian            if (AH_FALSE == ar9300_calc_iq_corr(
6151250003Sadrian                             ah, ch_idx, iq_res, coeff.iqc_coeff))
6152250003Sadrian            {
6153250003Sadrian                HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
6154250003Sadrian                    "%s: Failed in calculation of IQ correction.\n",
6155250003Sadrian                     __func__);
6156250003Sadrian                goto TX_IQ_CAL_FAILED_;
6157250003Sadrian            }
6158250003Sadrian
6159250003Sadrian            coeff.phs_coeff[ch_idx][im][iqcal_idx-1] = coeff.iqc_coeff[0] & 0x7f;
6160250003Sadrian            coeff.mag_coeff[ch_idx][im][iqcal_idx-1] = (coeff.iqc_coeff[0] >> 7) & 0x7f;
6161250003Sadrian            if (coeff.mag_coeff[ch_idx][im][iqcal_idx-1] > 63) {
6162250003Sadrian                coeff.mag_coeff[ch_idx][im][iqcal_idx-1] -= 128;
6163250003Sadrian            }
6164250003Sadrian            if (coeff.phs_coeff[ch_idx][im][iqcal_idx-1] > 63) {
6165250003Sadrian                coeff.phs_coeff[ch_idx][im][iqcal_idx-1] -= 128;
6166250003Sadrian            }
6167250003Sadrian#if 0
6168250003Sadrian            ath_hal_printf(ah, "IQCAL::[ch%d][gain%d]:: mag = %d phase = %d \n",
6169250003Sadrian                ch_idx, im, coeff.mag_coeff[ch_idx][im][iqcal_idx-1],
6170250003Sadrian                coeff.phs_coeff[ch_idx][im][iqcal_idx-1]);
6171250003Sadrian#endif
6172250003Sadrian        }
6173250003Sadrian    }
6174250003Sadrian    //last iteration; calculate mag and phs
6175250003Sadrian    if (iqcal_idx == max_iqcal) {
6176250003Sadrian        if (max_iqcal>1) {
6177250003Sadrian            for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {
6178250003Sadrian                for (im = 0; im < nmeasurement; im++) {
6179250003Sadrian                    //sort mag and phs
6180250003Sadrian                    for( ix=0;ix<max_iqcal-1;ix++){
6181250003Sadrian                        for( iy=ix+1;iy<=max_iqcal-1;iy++){
6182250003Sadrian                            if(coeff.mag_coeff[ch_idx][im][iy] <
6183250003Sadrian                                coeff.mag_coeff[ch_idx][im][ix]) {
6184250003Sadrian                                //swap
6185250003Sadrian                                temp=coeff.mag_coeff[ch_idx][im][ix];
6186250003Sadrian                                coeff.mag_coeff[ch_idx][im][ix] = coeff.mag_coeff[ch_idx][im][iy];
6187250003Sadrian                                coeff.mag_coeff[ch_idx][im][iy] = temp;
6188250003Sadrian                            }
6189250003Sadrian                            if(coeff.phs_coeff[ch_idx][im][iy] <
6190250003Sadrian                                coeff.phs_coeff[ch_idx][im][ix]){
6191250003Sadrian                                //swap
6192250003Sadrian                                temp=coeff.phs_coeff[ch_idx][im][ix];
6193250003Sadrian                                coeff.phs_coeff[ch_idx][im][ix]=coeff.phs_coeff[ch_idx][im][iy];
6194250003Sadrian                                coeff.phs_coeff[ch_idx][im][iy]=temp;
6195250003Sadrian                            }
6196250003Sadrian                        }
6197250003Sadrian                    }
6198250003Sadrian                    //select median; 3rd entry in the sorted array
6199250003Sadrian                    coeff.mag_coeff[ch_idx][im][0] =
6200250003Sadrian                        coeff.mag_coeff[ch_idx][im][max_iqcal/2];
6201250003Sadrian                    coeff.phs_coeff[ch_idx][im][0] =
6202250003Sadrian                        coeff.phs_coeff[ch_idx][im][max_iqcal/2];
6203250003Sadrian                    HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
6204250003Sadrian                        "IQCAL: Median [ch%d][gain%d]:: mag = %d phase = %d \n",
6205250003Sadrian                        ch_idx, im,coeff.mag_coeff[ch_idx][im][0],
6206250003Sadrian                        coeff.phs_coeff[ch_idx][im][0]);
6207250003Sadrian                }
6208250003Sadrian            }
6209250003Sadrian        }
6210250003Sadrian        ar9300_tx_iq_cal_outlier_detection(ah,ichan, num_chains, &coeff,is_cal_reusable);
6211250003Sadrian    }
6212250003Sadrian
6213250003Sadrian
6214250003Sadrian    coeff.last_nmeasurement = nmeasurement;
6215250003Sadrian    coeff.last_cal = AH_TRUE;
6216250003Sadrian
6217250003Sadrian    return;
6218250003Sadrian
6219250003SadrianTX_IQ_CAL_FAILED_:
6220250003Sadrian    /* no need to print this, it is AGC failure not chip stuck */
6221250003Sadrian    /*ath_hal_printf(ah, "Tx IQ Cal failed(%d)\n", line);*/
6222250003Sadrian    coeff.last_cal = AH_FALSE;
6223250003Sadrian    return;
6224250003Sadrian}
6225250003Sadrian
6226250003Sadrian
6227250003Sadrian/*
6228250003Sadrian * ar9300_disable_phy_restart
6229250003Sadrian *
6230250003Sadrian * In some BBpanics, we can disable the phyrestart
6231250003Sadrian * disable_phy_restart
6232250003Sadrian *      != 0, disable the phy restart in h/w
6233250003Sadrian *      == 0, enable the phy restart in h/w
6234250003Sadrian */
6235250003Sadrianvoid ar9300_disable_phy_restart(struct ath_hal *ah, int disable_phy_restart)
6236250003Sadrian{
6237250003Sadrian    u_int32_t val;
6238250003Sadrian
6239250003Sadrian    val = OS_REG_READ(ah, AR_PHY_RESTART);
6240250003Sadrian    if (disable_phy_restart) {
6241250003Sadrian        val &= ~AR_PHY_RESTART_ENA;
6242250008Sadrian        AH9300(ah)->ah_phyrestart_disabled = 1;
6243250003Sadrian    } else {
6244250003Sadrian        val |= AR_PHY_RESTART_ENA;
6245250008Sadrian        AH9300(ah)->ah_phyrestart_disabled = 0;
6246250003Sadrian    }
6247250003Sadrian    OS_REG_WRITE(ah, AR_PHY_RESTART, val);
6248250003Sadrian
6249250003Sadrian    val = OS_REG_READ(ah, AR_PHY_RESTART);
6250250003Sadrian}
6251250003Sadrian
6252250003SadrianHAL_BOOL
6253250003Sadrianar9300_interference_is_present(struct ath_hal *ah)
6254250003Sadrian{
6255250003Sadrian    int i;
6256250003Sadrian    struct ath_hal_private  *ahpriv = AH_PRIVATE(ah);
6257250008Sadrian    const struct ieee80211_channel *chan = ahpriv->ah_curchan;
6258250008Sadrian    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
6259250003Sadrian
6260250008Sadrian    if (ichan == NULL) {
6261250008Sadrian        ath_hal_printf(ah, "%s: called with ichan=NULL\n", __func__);
6262250008Sadrian        return AH_FALSE;
6263250008Sadrian    }
6264250008Sadrian
6265250003Sadrian    /* This function is called after a stuck beacon, if EACS is enabled.
6266250003Sadrian     * If CW interference is severe, then HW goes into a loop of continuous
6267250003Sadrian     * stuck beacons and resets. On reset the NF cal history is cleared.
6268250003Sadrian     * So the median value of the history cannot be used -
6269250003Sadrian     * hence check if any value (Chain 0/Primary Channel)
6270250003Sadrian     * is outside the bounds.
6271250003Sadrian     */
6272250008Sadrian    HAL_NFCAL_HIST_FULL *h = AH_HOME_CHAN_NFCAL_HIST(ah, ichan);
6273250003Sadrian    for (i = 0; i < HAL_NF_CAL_HIST_LEN_FULL; i++) {
6274250003Sadrian        if (h->nf_cal_buffer[i][0] >
6275250008Sadrian            AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta)
6276250003Sadrian        {
6277250003Sadrian            return AH_TRUE;
6278250003Sadrian        }
6279250003Sadrian
6280250003Sadrian    }
6281250003Sadrian    return AH_FALSE;
6282250003Sadrian}
6283250003Sadrian
6284250003Sadrian#if ATH_SUPPORT_CRDC
6285250003Sadrianvoid
6286250003Sadrianar9300_crdc_rx_notify(struct ath_hal *ah, struct ath_rx_status *rxs)
6287250003Sadrian{
6288250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
6289250003Sadrian    int rssi_index;
6290250003Sadrian
6291250003Sadrian    if ((!AR_SREV_WASP(ah)) ||
6292250003Sadrian        (!ahpriv->ah_config.ath_hal_crdc_enable)) {
6293250003Sadrian        return;
6294250003Sadrian    }
6295250003Sadrian
6296250003Sadrian    if (rxs->rs_isaggr && rxs->rs_moreaggr) {
6297250003Sadrian        return;
6298250003Sadrian    }
6299250003Sadrian
6300250003Sadrian    if ((rxs->rs_rssi_ctl0 >= HAL_RSSI_BAD) ||
6301250003Sadrian        (rxs->rs_rssi_ctl1 >= HAL_RSSI_BAD)) {
6302250003Sadrian        return;
6303250003Sadrian    }
6304250003Sadrian
6305250003Sadrian    rssi_index = ah->ah_crdc_rssi_ptr % HAL_MAX_CRDC_RSSI_SAMPLE;
6306250003Sadrian
6307250003Sadrian    ah->ah_crdc_rssi_sample[0][rssi_index] = rxs->rs_rssi_ctl0;
6308250003Sadrian    ah->ah_crdc_rssi_sample[1][rssi_index] = rxs->rs_rssi_ctl1;
6309250003Sadrian
6310250003Sadrian    ah->ah_crdc_rssi_ptr++;
6311250003Sadrian}
6312250003Sadrian
6313250003Sadrianstatic int
6314250003Sadrianar9300_crdc_avg_rssi(struct ath_hal *ah, int chain)
6315250003Sadrian{
6316250003Sadrian    int crdc_rssi_sum = 0;
6317250003Sadrian    int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr, i;
6318250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
6319250003Sadrian    int crdc_window = ahpriv->ah_config.ath_hal_crdc_window;
6320250003Sadrian
6321250003Sadrian    if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) {
6322250003Sadrian        crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE;
6323250003Sadrian    }
6324250003Sadrian
6325250003Sadrian    for (i = 1; i <= crdc_window; i++) {
6326250003Sadrian        crdc_rssi_sum +=
6327250003Sadrian            ah->ah_crdc_rssi_sample[chain]
6328250003Sadrian            [(crdc_rssi_ptr - i) % HAL_MAX_CRDC_RSSI_SAMPLE];
6329250003Sadrian    }
6330250003Sadrian
6331250003Sadrian    return crdc_rssi_sum / crdc_window;
6332250003Sadrian}
6333250003Sadrian
6334250003Sadrianstatic void
6335250003Sadrianar9300_crdc_activate(struct ath_hal *ah, int rssi_diff, int enable)
6336250003Sadrian{
6337250003Sadrian    int val, orig_val;
6338250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
6339250003Sadrian    int crdc_numerator = ahpriv->ah_config.ath_hal_crdc_numerator;
6340250003Sadrian    int crdc_denominator = ahpriv->ah_config.ath_hal_crdc_denominator;
6341250003Sadrian    int c = (rssi_diff * crdc_numerator) / crdc_denominator;
6342250003Sadrian
6343250003Sadrian    val = orig_val = OS_REG_READ(ah, AR_PHY_MULTICHAIN_CTRL);
6344250003Sadrian    val &= 0xffffff00;
6345250003Sadrian    if (enable) {
6346250003Sadrian        val |= 0x1;
6347250003Sadrian        val |= ((c << 1) & 0xff);
6348250003Sadrian    }
6349250003Sadrian    OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_CTRL, val);
6350250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "diff: %02d comp: %02d reg: %08x %08x\n",
6351250003Sadrian        rssi_diff, c, orig_val, val);
6352250003Sadrian}
6353250003Sadrian
6354250003Sadrian
6355250003Sadrianvoid ar9300_chain_rssi_diff_compensation(struct ath_hal *ah)
6356250003Sadrian{
6357250003Sadrian    struct ath_hal_private  *ahpriv = AH_PRIVATE(ah);
6358250003Sadrian    int crdc_window = ahpriv->ah_config.ath_hal_crdc_window;
6359250003Sadrian    int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr;
6360250003Sadrian    int crdc_rssi_thresh = ahpriv->ah_config.ath_hal_crdc_rssithresh;
6361250003Sadrian    int crdc_diff_thresh = ahpriv->ah_config.ath_hal_crdc_diffthresh;
6362250003Sadrian    int avg_rssi[2], avg_rssi_diff;
6363250003Sadrian
6364250003Sadrian    if ((!AR_SREV_WASP(ah)) ||
6365250003Sadrian        (!ahpriv->ah_config.ath_hal_crdc_enable)) {
6366250003Sadrian        if (ah->ah_crdc_rssi_ptr) {
6367250003Sadrian            ar9300_crdc_activate(ah, 0, 0);
6368250003Sadrian            ah->ah_crdc_rssi_ptr = 0;
6369250003Sadrian        }
6370250003Sadrian        return;
6371250003Sadrian    }
6372250003Sadrian
6373250003Sadrian    if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) {
6374250003Sadrian        crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE;
6375250003Sadrian    }
6376250003Sadrian
6377250003Sadrian    if (crdc_rssi_ptr < crdc_window) {
6378250003Sadrian        return;
6379250003Sadrian    }
6380250003Sadrian
6381250003Sadrian    avg_rssi[0] = ar9300_crdc_avg_rssi(ah, 0);
6382250003Sadrian    avg_rssi[1] = ar9300_crdc_avg_rssi(ah, 1);
6383250003Sadrian    avg_rssi_diff = avg_rssi[1] - avg_rssi[0];
6384250003Sadrian
6385250003Sadrian    HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "crdc: avg: %02d %02d ",
6386250003Sadrian        avg_rssi[0], avg_rssi[1]);
6387250003Sadrian
6388250003Sadrian    if ((avg_rssi[0] < crdc_rssi_thresh) &&
6389250003Sadrian        (avg_rssi[1] < crdc_rssi_thresh)) {
6390250003Sadrian        ar9300_crdc_activate(ah, 0, 0);
6391250003Sadrian    } else {
6392250003Sadrian        if (ABS(avg_rssi_diff) >= crdc_diff_thresh) {
6393250003Sadrian            ar9300_crdc_activate(ah, avg_rssi_diff, 1);
6394250003Sadrian        } else {
6395250003Sadrian            ar9300_crdc_activate(ah, 0, 1);
6396250003Sadrian        }
6397250003Sadrian    }
6398250003Sadrian}
6399250003Sadrian#endif
6400250003Sadrian
6401250003Sadrian#if ATH_ANT_DIV_COMB
6402250003SadrianHAL_BOOL
6403250008Sadrianar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, const struct ieee80211_channel *chan)
6404250003Sadrian{
6405250003Sadrian    u_int32_t value;
6406250003Sadrian    u_int32_t regval;
6407250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
6408250003Sadrian    HAL_CHANNEL_INTERNAL *ichan;
6409250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
6410250003Sadrian    HAL_CAPABILITIES *pcap = &ahpriv->ah_caps;
6411250003Sadrian
6412301094Sadrian    HALDEBUG(ah, HAL_DEBUG_RESET | HAL_DEBUG_BT_COEX,
6413301094Sadrian      "%s: called; enable=%d\n", __func__, enable);
6414301094Sadrian
6415250003Sadrian    if (AR_SREV_POSEIDON(ah)) {
6416250003Sadrian        // Make sure this scheme is only used for WB225(Astra)
6417250003Sadrian        ahp->ah_lna_div_use_bt_ant_enable = enable;
6418250003Sadrian
6419250003Sadrian        ichan = ar9300_check_chan(ah, chan);
6420250003Sadrian        if ( ichan == AH_NULL ) {
6421250003Sadrian            HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n",
6422250008Sadrian                     __func__, chan->ic_freq, chan->ic_flags);
6423250003Sadrian            return AH_FALSE;
6424250003Sadrian        }
6425250003Sadrian
6426250003Sadrian        if ( enable == TRUE ) {
6427250008Sadrian            pcap->halAntDivCombSupport = TRUE;
6428250003Sadrian        } else {
6429250008Sadrian            pcap->halAntDivCombSupport = pcap->halAntDivCombSupportOrg;
6430250003Sadrian        }
6431250003Sadrian
6432250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
6433250003Sadrian#define AR_SWITCH_TABLE_COM2_ALL_S (0)
6434250003Sadrian        value = ar9300_ant_ctrl_common2_get(ah, IS_CHAN_2GHZ(ichan));
6435250003Sadrian        if ( enable == TRUE ) {
6436250003Sadrian            value &= ~AR_SWITCH_TABLE_COM2_ALL;
6437250008Sadrian            value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable;
6438250003Sadrian        }
6439272292Sadrian	HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value);
6440250003Sadrian        OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
6441250003Sadrian
6442250003Sadrian        value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control);
6443250003Sadrian        /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */
6444250003Sadrian        regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
6445250003Sadrian        regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */
6446250003Sadrian        regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S;
6447250003Sadrian        /* enable_lnadiv */
6448250003Sadrian        regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK);
6449250003Sadrian        regval |= ((value >> 6) & 0x1) <<
6450250003Sadrian                  MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT;
6451250003Sadrian        if ( enable == TRUE ) {
6452250003Sadrian            regval |= ANT_DIV_ENABLE;
6453250003Sadrian        }
6454250003Sadrian        OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
6455250003Sadrian
6456250003Sadrian        /* enable fast_div */
6457250003Sadrian        regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
6458250003Sadrian        regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);
6459250003Sadrian        regval |= ((value >> 7) & 0x1) <<
6460250003Sadrian                  BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT;
6461250003Sadrian        if ( enable == TRUE ) {
6462250003Sadrian            regval |= FAST_DIV_ENABLE;
6463250003Sadrian        }
6464250003Sadrian        OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
6465250003Sadrian
6466250003Sadrian        if ( AR_SREV_POSEIDON_11_OR_LATER(ah) ) {
6467250008Sadrian            if (pcap->halAntDivCombSupport) {
6468250003Sadrian                /* If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning */
6469250003Sadrian                regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
6470250003Sadrian                /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */
6471250003Sadrian                regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |
6472250003Sadrian                             MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |
6473250003Sadrian                             MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK |
6474250003Sadrian                             MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK));
6475250003Sadrian                regval |= (HAL_ANT_DIV_COMB_LNA1 <<
6476250003Sadrian                           MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
6477250003Sadrian                regval |= (HAL_ANT_DIV_COMB_LNA2 <<
6478250003Sadrian                           MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
6479250003Sadrian                OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
6480250003Sadrian            }
6481250003Sadrian        }
6482250003Sadrian
6483250003Sadrian        return AH_TRUE;
6484301094Sadrian    } else if (AR_SREV_APHRODITE(ah)) {
6485301094Sadrian        ahp->ah_lna_div_use_bt_ant_enable = enable;
6486301094Sadrian        if (enable) {
6487301094Sadrian                OS_REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, ANT_DIV_ENABLE);
6488301094Sadrian                OS_REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT));
6489301094Sadrian                OS_REG_SET_BIT(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
6490301094Sadrian                OS_REG_SET_BIT(ah, AR_PHY_RESTART, RESTART__ENABLE_ANT_FAST_DIV_M2FLAG__MASK);
6491301094Sadrian                OS_REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
6492301094Sadrian        } else {
6493301094Sadrian                OS_REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, ANT_DIV_ENABLE);
6494301094Sadrian                OS_REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT));
6495301094Sadrian                OS_REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
6496301094Sadrian                OS_REG_CLR_BIT(ah, AR_PHY_RESTART, RESTART__ENABLE_ANT_FAST_DIV_M2FLAG__MASK);
6497301094Sadrian                OS_REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
6498301094Sadrian
6499301094Sadrian                regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
6500301094Sadrian                regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |
6501301094Sadrian                             MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |
6502301094Sadrian                             MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK |
6503301094Sadrian                             MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK));
6504301094Sadrian                regval |= (HAL_ANT_DIV_COMB_LNA1 <<
6505301094Sadrian                           MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
6506301094Sadrian                regval |= (HAL_ANT_DIV_COMB_LNA2 <<
6507301094Sadrian                           MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
6508301094Sadrian
6509301094Sadrian                OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
6510301094Sadrian        }
6511250003Sadrian        return AH_TRUE;
6512250003Sadrian    }
6513301094Sadrian    return AH_TRUE;
6514250003Sadrian}
6515250003Sadrian#endif /* ATH_ANT_DIV_COMB */
6516