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