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