xref: /freebsd/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c (revision dead34f82219b4017effc3a2e50ae3476870f6ab)
176bd547bSAdrian Chadd /*
276bd547bSAdrian Chadd  * Copyright (c) 2013 Qualcomm Atheros, Inc.
376bd547bSAdrian Chadd  *
476bd547bSAdrian Chadd  * Permission to use, copy, modify, and/or distribute this software for any
576bd547bSAdrian Chadd  * purpose with or without fee is hereby granted, provided that the above
676bd547bSAdrian Chadd  * copyright notice and this permission notice appear in all copies.
776bd547bSAdrian Chadd  *
876bd547bSAdrian Chadd  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
976bd547bSAdrian Chadd  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1076bd547bSAdrian Chadd  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1176bd547bSAdrian Chadd  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1276bd547bSAdrian Chadd  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1376bd547bSAdrian Chadd  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1476bd547bSAdrian Chadd  * PERFORMANCE OF THIS SOFTWARE.
1576bd547bSAdrian Chadd  */
1676bd547bSAdrian Chadd 
1776bd547bSAdrian Chadd 
1876bd547bSAdrian Chadd 
1976bd547bSAdrian Chadd #include "opt_ah.h"
2076bd547bSAdrian Chadd 
2176bd547bSAdrian Chadd #include "ah.h"
2276bd547bSAdrian Chadd #include "ah_internal.h"
2376bd547bSAdrian Chadd #include "ah_devid.h"
2476bd547bSAdrian Chadd #include "ah_desc.h"
2576bd547bSAdrian Chadd 
2676bd547bSAdrian Chadd #include "ar9300.h"
2776bd547bSAdrian Chadd #include "ar9300reg.h"
2876bd547bSAdrian Chadd #include "ar9300phy.h"
2976bd547bSAdrian Chadd #include "ar9300desc.h"
3076bd547bSAdrian Chadd 
3176bd547bSAdrian Chadd #define FIX_NOISE_FLOOR     1
3276bd547bSAdrian Chadd 
3376bd547bSAdrian Chadd 
3476bd547bSAdrian Chadd /* Additional Time delay to wait after activiting the Base band */
3576bd547bSAdrian Chadd #define BASE_ACTIVATE_DELAY         100     /* usec */
3676bd547bSAdrian Chadd #define RTC_PLL_SETTLE_DELAY        100     /* usec */
3776bd547bSAdrian Chadd #define COEF_SCALE_S                24
3876bd547bSAdrian Chadd #define HT40_CHANNEL_CENTER_SHIFT   10      /* MHz      */
3976bd547bSAdrian Chadd 
4076bd547bSAdrian Chadd #define DELPT 32
4176bd547bSAdrian Chadd 
42e113789bSAdrian Chadd /* XXX Duplicates! (in ar9300desc.h) */
43e113789bSAdrian Chadd #if 0
4476bd547bSAdrian Chadd extern  HAL_BOOL ar9300_reset_tx_queue(struct ath_hal *ah, u_int q);
4576bd547bSAdrian Chadd extern  u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q);
46e113789bSAdrian Chadd #endif
4776bd547bSAdrian Chadd 
4876bd547bSAdrian Chadd 
4976bd547bSAdrian Chadd #define MAX_MEASUREMENT 8
5076bd547bSAdrian Chadd #define MAXIQCAL 3
5176bd547bSAdrian Chadd struct coeff_t {
5276bd547bSAdrian Chadd     int32_t mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
5376bd547bSAdrian Chadd     int32_t phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
5476bd547bSAdrian Chadd     int32_t iqc_coeff[2];
5576bd547bSAdrian Chadd     int last_nmeasurement;
5676bd547bSAdrian Chadd     HAL_BOOL last_cal;
5776bd547bSAdrian Chadd };
5876bd547bSAdrian Chadd 
5976bd547bSAdrian Chadd static HAL_BOOL ar9300_tx_iq_cal_hw_run(struct ath_hal *ah);
6076bd547bSAdrian Chadd static void ar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan,
6176bd547bSAdrian Chadd        int iqcal_idx, int max_iqcal, HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr);
6276bd547bSAdrian Chadd static void ar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan,
6376bd547bSAdrian Chadd        u_int32_t num_chains, struct coeff_t *coeff, HAL_BOOL is_cal_reusable);
6476bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
6576bd547bSAdrian Chadd static void ar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan);
6676bd547bSAdrian Chadd #endif
6776bd547bSAdrian Chadd 
6876bd547bSAdrian Chadd 
6976bd547bSAdrian Chadd static inline void ar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, int column);
70e113789bSAdrian Chadd static inline void ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan);
71e113789bSAdrian Chadd static inline HAL_BOOL ar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_corr);
7276bd547bSAdrian Chadd static inline void ar9300_init_user_settings(struct ath_hal *ah);
7376bd547bSAdrian Chadd 
7476bd547bSAdrian Chadd #ifdef HOST_OFFLOAD
7576bd547bSAdrian Chadd /*
7676bd547bSAdrian Chadd  * For usb offload solution, some USB registers must be tuned
7776bd547bSAdrian Chadd  * to gain better stability/performance but these registers
7876bd547bSAdrian Chadd  * might be changed while doing wlan reset so do this here
7976bd547bSAdrian Chadd  */
8076bd547bSAdrian Chadd #define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah) \
8176bd547bSAdrian Chadd do { \
8276bd547bSAdrian Chadd     if (AR_SREV_HORNET(__ah) || AR_SREV_WASP(__ah)) { \
8376bd547bSAdrian Chadd         volatile u_int32_t *usb_ctrl_r1 = (u_int32_t *) 0xb8116c84; \
8476bd547bSAdrian Chadd         volatile u_int32_t *usb_ctrl_r2 = (u_int32_t *) 0xb8116c88; \
8576bd547bSAdrian Chadd         *usb_ctrl_r1 = (*usb_ctrl_r1 & 0xffefffff); \
8676bd547bSAdrian Chadd         *usb_ctrl_r2 = (*usb_ctrl_r2 & 0xfc1fffff) | (1 << 21) | (3 << 22); \
8776bd547bSAdrian Chadd     } \
8876bd547bSAdrian Chadd } while (0)
8976bd547bSAdrian Chadd #else
9076bd547bSAdrian Chadd #define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah)
9176bd547bSAdrian Chadd #endif
9276bd547bSAdrian Chadd 
93f0949f0cSAdrian Chadd /*
94f0949f0cSAdrian Chadd  * Note: the below is the version that ships with ath9k.
95f0949f0cSAdrian Chadd  * The original HAL version is above.
96f0949f0cSAdrian Chadd  */
97f0949f0cSAdrian Chadd 
98f0949f0cSAdrian Chadd static void
ar9300_disable_pll_lock_detect(struct ath_hal * ah)99f0949f0cSAdrian Chadd ar9300_disable_pll_lock_detect(struct ath_hal *ah)
100f0949f0cSAdrian Chadd {
101f0949f0cSAdrian Chadd 	/*
102f0949f0cSAdrian Chadd 	 * On AR9330 and AR9340 devices, some PHY registers must be
103f0949f0cSAdrian Chadd 	 * tuned to gain better stability/performance. These registers
104f0949f0cSAdrian Chadd 	 * might be changed while doing wlan reset so the registers must
105f0949f0cSAdrian Chadd 	 * be reprogrammed after each reset.
106f0949f0cSAdrian Chadd 	 */
107f0949f0cSAdrian Chadd 	if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah)) {
108f0949f0cSAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_RESET, "%s: called\n", __func__);
109f0949f0cSAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_PHY_USB_CTRL1, (1 << 20));
110f0949f0cSAdrian Chadd 		OS_REG_RMW(ah, AR_PHY_USB_CTRL2,
111f0949f0cSAdrian Chadd 		    (1 << 21) | (0xf << 22),
112f0949f0cSAdrian Chadd 		    (1 << 21) | (0x3 << 22));
113f0949f0cSAdrian Chadd 	}
114f0949f0cSAdrian Chadd }
115f0949f0cSAdrian Chadd 
11676bd547bSAdrian Chadd static inline void
ar9300_attach_hw_platform(struct ath_hal * ah)11776bd547bSAdrian Chadd ar9300_attach_hw_platform(struct ath_hal *ah)
11876bd547bSAdrian Chadd {
11976bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
12076bd547bSAdrian Chadd 
12176bd547bSAdrian Chadd     ahp->ah_hwp = HAL_TRUE_CHIP;
12276bd547bSAdrian Chadd     return;
12376bd547bSAdrian Chadd }
12476bd547bSAdrian Chadd 
12576bd547bSAdrian Chadd /* Adjust various register settings based on half/quarter rate clock setting.
12676bd547bSAdrian Chadd  * This includes: +USEC, TX/RX latency,
12776bd547bSAdrian Chadd  *                + IFS params: slot, eifs, misc etc.
12876bd547bSAdrian Chadd  * SIFS stays the same.
12976bd547bSAdrian Chadd  */
13076bd547bSAdrian Chadd static void
ar9300_set_ifs_timing(struct ath_hal * ah,struct ieee80211_channel * chan)131e113789bSAdrian Chadd ar9300_set_ifs_timing(struct ath_hal *ah, struct ieee80211_channel *chan)
13276bd547bSAdrian Chadd {
13376bd547bSAdrian Chadd     u_int32_t tx_lat, rx_lat, usec, slot, regval, eifs;
13476bd547bSAdrian Chadd 
13576bd547bSAdrian Chadd     regval = OS_REG_READ(ah, AR_USEC);
13676bd547bSAdrian Chadd     regval &= ~(AR_USEC_RX_LATENCY | AR_USEC_TX_LATENCY | AR_USEC_USEC);
137e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_HALF(chan)) { /* half rates */
13876bd547bSAdrian Chadd         slot = ar9300_mac_to_clks(ah, AR_SLOT_HALF);
13976bd547bSAdrian Chadd         eifs = ar9300_mac_to_clks(ah, AR_EIFS_HALF);
14076bd547bSAdrian Chadd         if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */
14176bd547bSAdrian Chadd             rx_lat = SM(AR_RX_LATENCY_HALF_FAST_CLOCK, AR_USEC_RX_LATENCY);
14276bd547bSAdrian Chadd             tx_lat = SM(AR_TX_LATENCY_HALF_FAST_CLOCK, AR_USEC_TX_LATENCY);
14376bd547bSAdrian Chadd             usec = SM(AR_USEC_HALF_FAST_CLOCK, AR_USEC_USEC);
14476bd547bSAdrian Chadd         } else {
14576bd547bSAdrian Chadd             rx_lat = SM(AR_RX_LATENCY_HALF, AR_USEC_RX_LATENCY);
14676bd547bSAdrian Chadd             tx_lat = SM(AR_TX_LATENCY_HALF, AR_USEC_TX_LATENCY);
14776bd547bSAdrian Chadd             usec = SM(AR_USEC_HALF, AR_USEC_USEC);
14876bd547bSAdrian Chadd         }
14976bd547bSAdrian Chadd     } else { /* quarter rate */
15076bd547bSAdrian Chadd         slot = ar9300_mac_to_clks(ah, AR_SLOT_QUARTER);
15176bd547bSAdrian Chadd         eifs = ar9300_mac_to_clks(ah, AR_EIFS_QUARTER);
15276bd547bSAdrian Chadd         if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */
15376bd547bSAdrian Chadd             rx_lat = SM(AR_RX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_RX_LATENCY);
15476bd547bSAdrian Chadd             tx_lat = SM(AR_TX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_TX_LATENCY);
15576bd547bSAdrian Chadd             usec = SM(AR_USEC_QUARTER_FAST_CLOCK, AR_USEC_USEC);
15676bd547bSAdrian Chadd         } else {
15776bd547bSAdrian Chadd             rx_lat = SM(AR_RX_LATENCY_QUARTER, AR_USEC_RX_LATENCY);
15876bd547bSAdrian Chadd             tx_lat = SM(AR_TX_LATENCY_QUARTER, AR_USEC_TX_LATENCY);
15976bd547bSAdrian Chadd             usec = SM(AR_USEC_QUARTER, AR_USEC_USEC);
16076bd547bSAdrian Chadd         }
16176bd547bSAdrian Chadd     }
16276bd547bSAdrian Chadd 
16376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_USEC, (usec | regval | tx_lat | rx_lat));
16476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);
16576bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);
16676bd547bSAdrian Chadd }
16776bd547bSAdrian Chadd 
16876bd547bSAdrian Chadd 
16976bd547bSAdrian Chadd /*
17076bd547bSAdrian Chadd  * This inline function configures the chip either
17176bd547bSAdrian Chadd  * to encrypt/decrypt management frames or pass thru
17276bd547bSAdrian Chadd  */
17376bd547bSAdrian Chadd static inline void
ar9300_init_mfp(struct ath_hal * ah)17476bd547bSAdrian Chadd ar9300_init_mfp(struct ath_hal * ah)
17576bd547bSAdrian Chadd {
17676bd547bSAdrian Chadd     u_int32_t   mfpcap, mfp_qos;
17776bd547bSAdrian Chadd 
17876bd547bSAdrian Chadd     ath_hal_getcapability(ah, HAL_CAP_MFP, 0, &mfpcap);
17976bd547bSAdrian Chadd 
18076bd547bSAdrian Chadd     if (mfpcap == HAL_MFP_QOSDATA) {
18176bd547bSAdrian Chadd         /* Treat like legacy hardware. Do not touch the MFP registers. */
18276bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET, "%s forced to use QOSDATA\n", __func__);
18376bd547bSAdrian Chadd         return;
18476bd547bSAdrian Chadd     }
18576bd547bSAdrian Chadd 
18676bd547bSAdrian Chadd     /* MFP support (Sowl 1.0 or greater) */
18776bd547bSAdrian Chadd     if (mfpcap == HAL_MFP_HW_CRYPTO) {
18876bd547bSAdrian Chadd         /* configure hardware MFP support */
18976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET, "%s using HW crypto\n", __func__);
19076bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
19176bd547bSAdrian Chadd             AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, AR_AES_MUTE_MASK1_FC_MGMT_MFP);
19276bd547bSAdrian Chadd         OS_REG_RMW(ah,
19376bd547bSAdrian Chadd             AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE,
19476bd547bSAdrian Chadd             AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
19576bd547bSAdrian Chadd         /*
19676bd547bSAdrian Chadd         * Mask used to construct AAD for CCMP-AES
19776bd547bSAdrian Chadd         * Cisco spec defined bits 0-3 as mask
19876bd547bSAdrian Chadd         * IEEE802.11w defined as bit 4.
19976bd547bSAdrian Chadd         */
20076bd547bSAdrian Chadd         if (ath_hal_get_mfp_qos(ah)) {
20176bd547bSAdrian Chadd             mfp_qos = AR_MFP_QOS_MASK_IEEE;
20276bd547bSAdrian Chadd         } else {
20376bd547bSAdrian Chadd             mfp_qos = AR_MFP_QOS_MASK_CISCO;
20476bd547bSAdrian Chadd         }
20576bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah,
20676bd547bSAdrian Chadd             AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_QOS, mfp_qos);
20776bd547bSAdrian Chadd     } else if (mfpcap == HAL_MFP_PASSTHRU) {
20876bd547bSAdrian Chadd         /* Disable en/decrypt by hardware */
20976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET, "%s using passthru\n", __func__);
21076bd547bSAdrian Chadd         OS_REG_RMW(ah,
21176bd547bSAdrian Chadd             AR_PCU_MISC_MODE2,
21276bd547bSAdrian Chadd             AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT,
21376bd547bSAdrian Chadd             AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
21476bd547bSAdrian Chadd     }
21576bd547bSAdrian Chadd }
21676bd547bSAdrian Chadd 
21776bd547bSAdrian Chadd void
ar9300_get_channel_centers(struct ath_hal * ah,const struct ieee80211_channel * chan,CHAN_CENTERS * centers)218e113789bSAdrian Chadd ar9300_get_channel_centers(struct ath_hal *ah, const struct ieee80211_channel *chan,
21976bd547bSAdrian Chadd     CHAN_CENTERS *centers)
22076bd547bSAdrian Chadd {
22176bd547bSAdrian Chadd     int8_t      extoff;
22276bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
223e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
22476bd547bSAdrian Chadd 
225e113789bSAdrian Chadd     if (!IEEE80211_IS_CHAN_HT40(chan)) {
22676bd547bSAdrian Chadd         centers->ctl_center = centers->ext_center =
227e113789bSAdrian Chadd         centers->synth_center = ichan->channel;
22876bd547bSAdrian Chadd         return;
22976bd547bSAdrian Chadd     }
23076bd547bSAdrian Chadd 
231e113789bSAdrian Chadd     HALASSERT(IEEE80211_IS_CHAN_HT40(chan));
23276bd547bSAdrian Chadd 
23376bd547bSAdrian Chadd     /*
23476bd547bSAdrian Chadd      * In 20/40 phy mode, the center frequency is
23576bd547bSAdrian Chadd      * "between" the primary and extension channels.
23676bd547bSAdrian Chadd      */
237e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_HT40U(chan)) {
238e113789bSAdrian Chadd         centers->synth_center = ichan->channel + HT40_CHANNEL_CENTER_SHIFT;
23976bd547bSAdrian Chadd         extoff = 1;
24076bd547bSAdrian Chadd     } else {
241e113789bSAdrian Chadd         centers->synth_center = ichan->channel - HT40_CHANNEL_CENTER_SHIFT;
24276bd547bSAdrian Chadd         extoff = -1;
24376bd547bSAdrian Chadd     }
24476bd547bSAdrian Chadd 
24576bd547bSAdrian Chadd     centers->ctl_center =
24676bd547bSAdrian Chadd         centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
24776bd547bSAdrian Chadd     centers->ext_center =
24876bd547bSAdrian Chadd         centers->synth_center +
24976bd547bSAdrian Chadd         (extoff * ((ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_20) ?
25076bd547bSAdrian Chadd             HT40_CHANNEL_CENTER_SHIFT : 15));
25176bd547bSAdrian Chadd }
25276bd547bSAdrian Chadd 
25376bd547bSAdrian Chadd /*
25476bd547bSAdrian Chadd  * Read the noise-floor values from the HW.
25576bd547bSAdrian Chadd  * Specifically, read the minimum clear-channel assessment value for
25676bd547bSAdrian Chadd  * each chain, for both the control and extension channels.
25776bd547bSAdrian Chadd  * (The received power level during clear-channel periods is the
25876bd547bSAdrian Chadd  * noise floor.)
25976bd547bSAdrian Chadd  * These noise floor values computed by the HW will be stored in the
26076bd547bSAdrian Chadd  * NF history buffer.
26176bd547bSAdrian Chadd  * The HW sometimes produces bogus NF values.  To avoid using these
26276bd547bSAdrian Chadd  * bogus values, the NF data is (a) range-limited, and (b) filtered.
26376bd547bSAdrian Chadd  * However, this data-processing is done when reading the NF values
26476bd547bSAdrian Chadd  * out of the history buffer.  The history buffer stores the raw values.
26576bd547bSAdrian Chadd  * This allows the NF history buffer to be used to check for interference.
26676bd547bSAdrian Chadd  * A single high NF reading might be a bogus HW value, but if the NF
26776bd547bSAdrian Chadd  * readings are consistently high, it must be due to interference.
26876bd547bSAdrian Chadd  * This is the purpose of storing raw NF values in the history buffer,
26976bd547bSAdrian Chadd  * rather than processed values.  By looking at a history of NF values
27076bd547bSAdrian Chadd  * that have not been range-limited, we can check if they are consistently
27176bd547bSAdrian Chadd  * high (due to interference).
27276bd547bSAdrian Chadd  */
27376bd547bSAdrian Chadd #define AH_NF_SIGN_EXTEND(nf)      \
27476bd547bSAdrian Chadd     ((nf) & 0x100) ?               \
27576bd547bSAdrian Chadd         0 - (((nf) ^ 0x1ff) + 1) : \
27676bd547bSAdrian Chadd         (nf)
27776bd547bSAdrian Chadd void
ar9300_upload_noise_floor(struct ath_hal * ah,int is_2g,int16_t nfarray[HAL_NUM_NF_READINGS])27876bd547bSAdrian Chadd ar9300_upload_noise_floor(struct ath_hal *ah, int is_2g,
279e113789bSAdrian Chadd     int16_t nfarray[HAL_NUM_NF_READINGS])
28076bd547bSAdrian Chadd {
28176bd547bSAdrian Chadd     int16_t nf;
28276bd547bSAdrian Chadd     int chan, chain;
283e113789bSAdrian Chadd     u_int32_t regs[HAL_NUM_NF_READINGS] = {
28476bd547bSAdrian Chadd         /* control channel */
28576bd547bSAdrian Chadd         AR_PHY_CCA_0,     /* chain 0 */
28676bd547bSAdrian Chadd         AR_PHY_CCA_1,     /* chain 1 */
28776bd547bSAdrian Chadd         AR_PHY_CCA_2,     /* chain 2 */
28876bd547bSAdrian Chadd         /* extension channel */
28976bd547bSAdrian Chadd         AR_PHY_EXT_CCA,   /* chain 0 */
29076bd547bSAdrian Chadd         AR_PHY_EXT_CCA_1, /* chain 1 */
29176bd547bSAdrian Chadd         AR_PHY_EXT_CCA_2, /* chain 2 */
29276bd547bSAdrian Chadd     };
29376bd547bSAdrian Chadd     u_int8_t chainmask;
29476bd547bSAdrian Chadd 
29576bd547bSAdrian Chadd     /*
29676bd547bSAdrian Chadd      * Within a given channel (ctl vs. ext), the CH0, CH1, and CH2
29776bd547bSAdrian Chadd      * masks and shifts are the same, though they differ for the
29876bd547bSAdrian Chadd      * control vs. extension channels.
29976bd547bSAdrian Chadd      */
30076bd547bSAdrian Chadd     u_int32_t masks[2] = {
30176bd547bSAdrian Chadd         AR_PHY_MINCCA_PWR,     /* control channel */
30276bd547bSAdrian Chadd         AR_PHY_EXT_MINCCA_PWR, /* extention channel */
30376bd547bSAdrian Chadd     };
30476bd547bSAdrian Chadd     u_int8_t shifts[2] = {
30576bd547bSAdrian Chadd         AR_PHY_MINCCA_PWR_S,     /* control channel */
30676bd547bSAdrian Chadd         AR_PHY_EXT_MINCCA_PWR_S, /* extention channel */
30776bd547bSAdrian Chadd     };
30876bd547bSAdrian Chadd 
30976bd547bSAdrian Chadd     /*
31076bd547bSAdrian Chadd      * Force NF calibration for all chains.
31176bd547bSAdrian Chadd      */
31276bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
31376bd547bSAdrian Chadd         chainmask = 0x01;
31427e2ad46SAdrian Chadd     } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(ah)) {
31576bd547bSAdrian Chadd         chainmask = 0x03;
31676bd547bSAdrian Chadd     } else {
31776bd547bSAdrian Chadd         chainmask = 0x07;
31876bd547bSAdrian Chadd     }
31976bd547bSAdrian Chadd 
32076bd547bSAdrian Chadd     for (chan = 0; chan < 2 /*ctl,ext*/; chan++) {
32176bd547bSAdrian Chadd         for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
32276bd547bSAdrian Chadd             int i;
32376bd547bSAdrian Chadd 
32476bd547bSAdrian Chadd             if (!((chainmask >> chain) & 0x1)) {
32576bd547bSAdrian Chadd                 continue;
32676bd547bSAdrian Chadd             }
32776bd547bSAdrian Chadd             i = chan * AR9300_MAX_CHAINS + chain;
32876bd547bSAdrian Chadd             nf = (OS_REG_READ(ah, regs[i]) & masks[chan]) >> shifts[chan];
32976bd547bSAdrian Chadd             nfarray[i] = AH_NF_SIGN_EXTEND(nf);
33076bd547bSAdrian Chadd         }
33176bd547bSAdrian Chadd     }
33276bd547bSAdrian Chadd }
33376bd547bSAdrian Chadd 
33476bd547bSAdrian Chadd /* ar9300_get_min_cca_pwr -
33576bd547bSAdrian Chadd  * Used by the scan function for a quick read of the noise floor.
33676bd547bSAdrian Chadd  * This is used to detect presence of CW interference such as video bridge.
33776bd547bSAdrian Chadd  * The noise floor is assumed to have been already started during reset
33876bd547bSAdrian Chadd  * called during channel change. The function checks if the noise floor
33976bd547bSAdrian Chadd  * reading is done. In case it has been done, it reads the noise floor value.
34076bd547bSAdrian Chadd  * If the noise floor calibration has not been finished, it assumes this is
34176bd547bSAdrian Chadd  * due to presence of CW interference an returns a high value for noise floor,
34276bd547bSAdrian Chadd  * derived from the CW interference threshold + margin fudge factor.
34376bd547bSAdrian Chadd  */
34476bd547bSAdrian Chadd #define BAD_SCAN_NF_MARGIN (30)
ar9300_get_min_cca_pwr(struct ath_hal * ah)34576bd547bSAdrian Chadd int16_t ar9300_get_min_cca_pwr(struct ath_hal *ah)
34676bd547bSAdrian Chadd {
34776bd547bSAdrian Chadd     int16_t nf;
348e113789bSAdrian Chadd //    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
34976bd547bSAdrian Chadd 
350899d1cacSAdrian Chadd 
35176bd547bSAdrian Chadd     if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) {
35276bd547bSAdrian Chadd         nf = MS(OS_REG_READ(ah, AR_PHY_CCA_0), AR9280_PHY_MINCCA_PWR);
35376bd547bSAdrian Chadd         if (nf & 0x100) {
35476bd547bSAdrian Chadd             nf = 0 - ((nf ^ 0x1ff) + 1);
35576bd547bSAdrian Chadd         }
35676bd547bSAdrian Chadd     } else {
35776bd547bSAdrian Chadd         /* NF calibration is not done, assume CW interference */
358e113789bSAdrian Chadd         nf = AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta +
35976bd547bSAdrian Chadd             BAD_SCAN_NF_MARGIN;
36076bd547bSAdrian Chadd     }
36176bd547bSAdrian Chadd     return nf;
36276bd547bSAdrian Chadd }
36376bd547bSAdrian Chadd 
36476bd547bSAdrian Chadd 
36576bd547bSAdrian Chadd /*
36676bd547bSAdrian Chadd  * Noise Floor values for all chains.
36776bd547bSAdrian Chadd  * Most recently updated values from the NF history buffer are used.
36876bd547bSAdrian Chadd  */
ar9300_chain_noise_floor(struct ath_hal * ah,int16_t * nf_buf,struct ieee80211_channel * chan,int is_scan)36976bd547bSAdrian Chadd void ar9300_chain_noise_floor(struct ath_hal *ah, int16_t *nf_buf,
370e113789bSAdrian Chadd     struct ieee80211_channel *chan, int is_scan)
37176bd547bSAdrian Chadd {
37276bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
37376bd547bSAdrian Chadd     int i, nf_hist_len, recent_nf_index = 0;
37476bd547bSAdrian Chadd     HAL_NFCAL_HIST_FULL *h;
37576bd547bSAdrian Chadd     u_int8_t rx_chainmask = ahp->ah_rx_chainmask | (ahp->ah_rx_chainmask << 3);
37676bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
37776bd547bSAdrian Chadd     HALASSERT(ichan);
37876bd547bSAdrian Chadd 
37976bd547bSAdrian Chadd #ifdef ATH_NF_PER_CHAN
38076bd547bSAdrian Chadd     /* Fill 0 if valid internal channel is not found */
38176bd547bSAdrian Chadd     if (ichan == AH_NULL) {
382e113789bSAdrian Chadd         OS_MEMZERO(nf_buf, sizeof(nf_buf[0])*HAL_NUM_NF_READINGS);
38376bd547bSAdrian Chadd         return;
38476bd547bSAdrian Chadd     }
38576bd547bSAdrian Chadd     h = &ichan->nf_cal_hist;
38676bd547bSAdrian Chadd     nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;
38776bd547bSAdrian Chadd #else
38876bd547bSAdrian Chadd     /*
38976bd547bSAdrian Chadd      * If a scan is not in progress, then the most recent value goes
39076bd547bSAdrian Chadd      * into ahpriv->nf_cal_hist.  If a scan is in progress, then
39176bd547bSAdrian Chadd      * the most recent value goes into ichan->nf_cal_hist.
39276bd547bSAdrian Chadd      * Thus, return the value from ahpriv->nf_cal_hist if there's
39376bd547bSAdrian Chadd      * no scan, and if the specified channel is the current channel.
39476bd547bSAdrian Chadd      * Otherwise, return the noise floor from ichan->nf_cal_hist.
39576bd547bSAdrian Chadd      */
396e113789bSAdrian Chadd     if ((!is_scan) && chan == AH_PRIVATE(ah)->ah_curchan) {
39776bd547bSAdrian Chadd         h = &AH_PRIVATE(ah)->nf_cal_hist;
39876bd547bSAdrian Chadd         nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;
39976bd547bSAdrian Chadd     } else {
40076bd547bSAdrian Chadd         /* Fill 0 if valid internal channel is not found */
40176bd547bSAdrian Chadd         if (ichan == AH_NULL) {
402e113789bSAdrian Chadd             OS_MEMZERO(nf_buf, sizeof(nf_buf[0])*HAL_NUM_NF_READINGS);
40376bd547bSAdrian Chadd             return;
40476bd547bSAdrian Chadd         }
40576bd547bSAdrian Chadd        /*
40676bd547bSAdrian Chadd         * It is okay to treat a HAL_NFCAL_HIST_SMALL struct as if it were a
40776bd547bSAdrian Chadd         * HAL_NFCAL_HIST_FULL struct, as long as only the index 0 of the
408e113789bSAdrian Chadd         * nf_cal_buffer is used (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1])
40976bd547bSAdrian Chadd         */
41076bd547bSAdrian Chadd         h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;
41176bd547bSAdrian Chadd         nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL;
41276bd547bSAdrian Chadd     }
41376bd547bSAdrian Chadd #endif
41476bd547bSAdrian Chadd     /* Get most recently updated values from nf cal history buffer */
41576bd547bSAdrian Chadd     recent_nf_index =
41676bd547bSAdrian Chadd         (h->base.curr_index) ? h->base.curr_index - 1 : nf_hist_len - 1;
41776bd547bSAdrian Chadd 
418e113789bSAdrian Chadd     for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
41976bd547bSAdrian Chadd         /* Fill 0 for unsupported chains */
42076bd547bSAdrian Chadd         if (!(rx_chainmask & (1 << i))) {
42176bd547bSAdrian Chadd             nf_buf[i] = 0;
42276bd547bSAdrian Chadd             continue;
42376bd547bSAdrian Chadd         }
42476bd547bSAdrian Chadd         nf_buf[i] = h->nf_cal_buffer[recent_nf_index][i];
42576bd547bSAdrian Chadd     }
42676bd547bSAdrian Chadd }
42776bd547bSAdrian Chadd 
428899d1cacSAdrian Chadd /*
429899d1cacSAdrian Chadd  * Return the current NF value in register.
430899d1cacSAdrian Chadd  * If the current NF cal is not completed, return 0.
431899d1cacSAdrian Chadd  */
ar9300_get_nf_from_reg(struct ath_hal * ah,struct ieee80211_channel * chan,int wait_time)432899d1cacSAdrian Chadd int16_t ar9300_get_nf_from_reg(struct ath_hal *ah, struct ieee80211_channel *chan, int wait_time)
433899d1cacSAdrian Chadd {
434899d1cacSAdrian Chadd     int16_t nfarray[HAL_NUM_NF_READINGS] = {0};
435899d1cacSAdrian Chadd     int is_2g = 0;
436899d1cacSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = NULL;
437899d1cacSAdrian Chadd 
438899d1cacSAdrian Chadd     ichan = ath_hal_checkchannel(ah, chan);
439899d1cacSAdrian Chadd     if (ichan == NULL)
440899d1cacSAdrian Chadd         return (0);
441899d1cacSAdrian Chadd 
442899d1cacSAdrian Chadd     if (wait_time <= 0) {
443899d1cacSAdrian Chadd         return 0;
444899d1cacSAdrian Chadd     }
445899d1cacSAdrian Chadd 
446899d1cacSAdrian Chadd     if (!ath_hal_waitfor(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF, 0, wait_time)) {
447899d1cacSAdrian Chadd         ath_hal_printf(ah, "%s: NF cal is not complete in %dus", __func__, wait_time);
448899d1cacSAdrian Chadd         return 0;
449899d1cacSAdrian Chadd     }
450899d1cacSAdrian Chadd     is_2g = !! (IS_CHAN_2GHZ(ichan));
451899d1cacSAdrian Chadd     ar9300_upload_noise_floor(ah, is_2g, nfarray);
452899d1cacSAdrian Chadd 
453899d1cacSAdrian Chadd     return nfarray[0];
454899d1cacSAdrian Chadd }
45576bd547bSAdrian Chadd 
45676bd547bSAdrian Chadd /*
45776bd547bSAdrian Chadd  * Pick up the medium one in the noise floor buffer and update the
45876bd547bSAdrian Chadd  * corresponding range for valid noise floor values
45976bd547bSAdrian Chadd  */
46076bd547bSAdrian Chadd static int16_t
ar9300_get_nf_hist_mid(struct ath_hal * ah,HAL_NFCAL_HIST_FULL * h,int reading,int hist_len)46176bd547bSAdrian Chadd ar9300_get_nf_hist_mid(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, int reading,
46276bd547bSAdrian Chadd     int hist_len)
46376bd547bSAdrian Chadd {
46476bd547bSAdrian Chadd     int16_t nfval;
46576bd547bSAdrian Chadd     int16_t sort[HAL_NF_CAL_HIST_LEN_FULL]; /* upper bound for hist_len */
46676bd547bSAdrian Chadd     int i, j;
46776bd547bSAdrian Chadd 
468899d1cacSAdrian Chadd 
46976bd547bSAdrian Chadd     for (i = 0; i < hist_len; i++) {
47076bd547bSAdrian Chadd         sort[i] = h->nf_cal_buffer[i][reading];
471e113789bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_NFCAL,
47276bd547bSAdrian Chadd             "nf_cal_buffer[%d][%d] = %d\n", i, reading, (int)sort[i]);
47376bd547bSAdrian Chadd     }
47476bd547bSAdrian Chadd     for (i = 0; i < hist_len - 1; i++) {
47576bd547bSAdrian Chadd         for (j = 1; j < hist_len - i; j++) {
47676bd547bSAdrian Chadd             if (sort[j] > sort[j - 1]) {
47776bd547bSAdrian Chadd                 nfval = sort[j];
47876bd547bSAdrian Chadd                 sort[j] = sort[j - 1];
47976bd547bSAdrian Chadd                 sort[j - 1] = nfval;
48076bd547bSAdrian Chadd             }
48176bd547bSAdrian Chadd         }
48276bd547bSAdrian Chadd     }
48376bd547bSAdrian Chadd     nfval = sort[(hist_len - 1) >> 1];
48476bd547bSAdrian Chadd 
48576bd547bSAdrian Chadd     return nfval;
48676bd547bSAdrian Chadd }
48776bd547bSAdrian Chadd 
ar9300_limit_nf_range(struct ath_hal * ah,int16_t nf)48876bd547bSAdrian Chadd static int16_t ar9300_limit_nf_range(struct ath_hal *ah, int16_t nf)
48976bd547bSAdrian Chadd {
490e113789bSAdrian Chadd     if (nf < AH9300(ah)->nfp->min) {
491e113789bSAdrian Chadd         return AH9300(ah)->nfp->nominal;
492e113789bSAdrian Chadd     } else if (nf > AH9300(ah)->nfp->max) {
493e113789bSAdrian Chadd         return AH9300(ah)->nfp->max;
49476bd547bSAdrian Chadd     }
49576bd547bSAdrian Chadd     return nf;
49676bd547bSAdrian Chadd }
49776bd547bSAdrian Chadd 
49876bd547bSAdrian Chadd #ifndef ATH_NF_PER_CHAN
49976bd547bSAdrian Chadd inline static void
ar9300_reset_nf_hist_buff(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * ichan)50076bd547bSAdrian Chadd ar9300_reset_nf_hist_buff(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
50176bd547bSAdrian Chadd {
50276bd547bSAdrian Chadd     HAL_CHAN_NFCAL_HIST *h = &ichan->nf_cal_hist;
50376bd547bSAdrian Chadd     HAL_NFCAL_HIST_FULL *home = &AH_PRIVATE(ah)->nf_cal_hist;
50476bd547bSAdrian Chadd     int i;
50576bd547bSAdrian Chadd 
50676bd547bSAdrian Chadd     /*
50776bd547bSAdrian Chadd      * Copy the value for the channel in question into the home-channel
50876bd547bSAdrian Chadd      * NF history buffer.  The channel NF is probably a value filled in by
50976bd547bSAdrian Chadd      * a prior background channel scan, but if no scan has been done then
51076bd547bSAdrian Chadd      * it is the nominal noise floor filled in by ath_hal_init_NF_buffer
51176bd547bSAdrian Chadd      * for this chip and the channel's band.
51276bd547bSAdrian Chadd      * Replicate this channel NF into all entries of the home-channel NF
51376bd547bSAdrian Chadd      * history buffer.
51476bd547bSAdrian Chadd      * If the channel NF was filled in by a channel scan, it has not had
51576bd547bSAdrian Chadd      * bounds limits applied to it yet - do so now.  It is important to
51676bd547bSAdrian Chadd      * apply bounds limits to the priv_nf value that gets loaded into the
51776bd547bSAdrian Chadd      * WLAN chip's min_cca_pwr register field.  It is also necessary to
51876bd547bSAdrian Chadd      * apply bounds limits to the nf_cal_buffer[] elements.  Since we are
51976bd547bSAdrian Chadd      * replicating a single NF reading into all nf_cal_buffer elements,
52076bd547bSAdrian Chadd      * if the single reading were above the CW_INT threshold, the CW_INT
52176bd547bSAdrian Chadd      * check in ar9300_get_nf would immediately conclude that CW interference
52276bd547bSAdrian Chadd      * is present, even though we're not supposed to set CW_INT unless
52376bd547bSAdrian Chadd      * NF values are _consistently_ above the CW_INT threshold.
52476bd547bSAdrian Chadd      * Applying the bounds limits to the nf_cal_buffer contents fixes this
52576bd547bSAdrian Chadd      * problem.
52676bd547bSAdrian Chadd      */
527e113789bSAdrian Chadd     for (i = 0; i < HAL_NUM_NF_READINGS; i ++) {
52876bd547bSAdrian Chadd         int j;
52976bd547bSAdrian Chadd         int16_t nf;
53076bd547bSAdrian Chadd         /*
53176bd547bSAdrian Chadd          * No need to set curr_index, since it already has a value in
53276bd547bSAdrian Chadd          * the range [0..HAL_NF_CAL_HIST_LEN_FULL), and all nf_cal_buffer
53376bd547bSAdrian Chadd          * values will be the same.
53476bd547bSAdrian Chadd          */
53576bd547bSAdrian Chadd         nf = ar9300_limit_nf_range(ah, h->nf_cal_buffer[0][i]);
53676bd547bSAdrian Chadd         for (j = 0; j < HAL_NF_CAL_HIST_LEN_FULL; j++) {
53776bd547bSAdrian Chadd             home->nf_cal_buffer[j][i] = nf;
53876bd547bSAdrian Chadd         }
53976bd547bSAdrian Chadd         AH_PRIVATE(ah)->nf_cal_hist.base.priv_nf[i] = nf;
54076bd547bSAdrian Chadd     }
54176bd547bSAdrian Chadd }
54276bd547bSAdrian Chadd #endif
54376bd547bSAdrian Chadd 
54476bd547bSAdrian Chadd /*
54576bd547bSAdrian Chadd  *  Update the noise floor buffer as a ring buffer
54676bd547bSAdrian Chadd  */
54776bd547bSAdrian Chadd static int16_t
ar9300_update_nf_hist_buff(struct ath_hal * ah,HAL_NFCAL_HIST_FULL * h,int16_t * nfarray,int hist_len)54876bd547bSAdrian Chadd ar9300_update_nf_hist_buff(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h,
54976bd547bSAdrian Chadd    int16_t *nfarray, int hist_len)
55076bd547bSAdrian Chadd {
55176bd547bSAdrian Chadd     int i, nr;
55276bd547bSAdrian Chadd     int16_t nf_no_lim_chain0;
55376bd547bSAdrian Chadd 
55476bd547bSAdrian Chadd     nf_no_lim_chain0 = ar9300_get_nf_hist_mid(ah, h, 0, hist_len);
55576bd547bSAdrian Chadd 
556e113789bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] BEFORE\n", __func__, __LINE__);
55776bd547bSAdrian Chadd     for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) {
558e113789bSAdrian Chadd         for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
559e113789bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_NFCAL,
56076bd547bSAdrian Chadd                 "nf_cal_buffer[%d][%d] = %d\n",
56176bd547bSAdrian Chadd                 nr, i, (int)h->nf_cal_buffer[nr][i]);
56276bd547bSAdrian Chadd         }
56376bd547bSAdrian Chadd     }
564e113789bSAdrian Chadd     for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
56576bd547bSAdrian Chadd         h->nf_cal_buffer[h->base.curr_index][i] = nfarray[i];
56676bd547bSAdrian Chadd         h->base.priv_nf[i] = ar9300_limit_nf_range(
56776bd547bSAdrian Chadd             ah, ar9300_get_nf_hist_mid(ah, h, i, hist_len));
56876bd547bSAdrian Chadd     }
569e113789bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] AFTER\n", __func__, __LINE__);
57076bd547bSAdrian Chadd     for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) {
571e113789bSAdrian Chadd         for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
572e113789bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_NFCAL,
57376bd547bSAdrian Chadd                 "nf_cal_buffer[%d][%d] = %d\n",
57476bd547bSAdrian Chadd                 nr, i, (int)h->nf_cal_buffer[nr][i]);
57576bd547bSAdrian Chadd         }
57676bd547bSAdrian Chadd     }
57776bd547bSAdrian Chadd 
57876bd547bSAdrian Chadd     if (++h->base.curr_index >= hist_len) {
57976bd547bSAdrian Chadd         h->base.curr_index = 0;
58076bd547bSAdrian Chadd     }
58176bd547bSAdrian Chadd 
58276bd547bSAdrian Chadd     return nf_no_lim_chain0;
58376bd547bSAdrian Chadd }
58476bd547bSAdrian Chadd 
585e113789bSAdrian Chadd #ifdef UNUSED
58676bd547bSAdrian Chadd static HAL_BOOL
get_noise_floor_thresh(struct ath_hal * ah,const HAL_CHANNEL_INTERNAL * chan,int16_t * nft)58776bd547bSAdrian Chadd get_noise_floor_thresh(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *chan,
58876bd547bSAdrian Chadd     int16_t *nft)
58976bd547bSAdrian Chadd {
59076bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
59176bd547bSAdrian Chadd 
592899d1cacSAdrian Chadd 
59376bd547bSAdrian Chadd     switch (chan->channel_flags & CHANNEL_ALL_NOTURBO) {
59476bd547bSAdrian Chadd     case CHANNEL_A:
59576bd547bSAdrian Chadd     case CHANNEL_A_HT20:
59676bd547bSAdrian Chadd     case CHANNEL_A_HT40PLUS:
59776bd547bSAdrian Chadd     case CHANNEL_A_HT40MINUS:
59876bd547bSAdrian Chadd         *nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_5);
59976bd547bSAdrian Chadd         break;
60076bd547bSAdrian Chadd     case CHANNEL_B:
60176bd547bSAdrian Chadd     case CHANNEL_G:
60276bd547bSAdrian Chadd     case CHANNEL_G_HT20:
60376bd547bSAdrian Chadd     case CHANNEL_G_HT40PLUS:
60476bd547bSAdrian Chadd     case CHANNEL_G_HT40MINUS:
60576bd547bSAdrian Chadd         *nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_2);
60676bd547bSAdrian Chadd         break;
60776bd547bSAdrian Chadd     default:
60876bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel flags 0x%x\n",
60976bd547bSAdrian Chadd                 __func__, chan->channel_flags);
61076bd547bSAdrian Chadd         return AH_FALSE;
61176bd547bSAdrian Chadd     }
61276bd547bSAdrian Chadd     return AH_TRUE;
61376bd547bSAdrian Chadd }
61476bd547bSAdrian Chadd #endif
61576bd547bSAdrian Chadd 
61676bd547bSAdrian Chadd /*
61776bd547bSAdrian Chadd  * Read the NF and check it against the noise floor threshhold
61876bd547bSAdrian Chadd  */
61976bd547bSAdrian Chadd #define IS(_c, _f)       (((_c)->channel_flags & _f) || 0)
62076bd547bSAdrian Chadd static int
ar9300_store_new_nf(struct ath_hal * ah,struct ieee80211_channel * chan,int is_scan)621e113789bSAdrian Chadd ar9300_store_new_nf(struct ath_hal *ah, struct ieee80211_channel *chan,
622e113789bSAdrian Chadd   int is_scan)
62376bd547bSAdrian Chadd {
624e113789bSAdrian Chadd //    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
62576bd547bSAdrian Chadd     int nf_hist_len;
62676bd547bSAdrian Chadd     int16_t nf_no_lim;
627e113789bSAdrian Chadd     int16_t nfarray[HAL_NUM_NF_READINGS] = {0};
62876bd547bSAdrian Chadd     HAL_NFCAL_HIST_FULL *h;
62976bd547bSAdrian Chadd     int is_2g = 0;
630e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
631e113789bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
63276bd547bSAdrian Chadd 
63376bd547bSAdrian Chadd     if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
63476bd547bSAdrian Chadd         u_int32_t tsf32, nf_cal_dur_tsf;
63576bd547bSAdrian Chadd         /*
63676bd547bSAdrian Chadd          * The reason the NF calibration did not complete may just be that
63776bd547bSAdrian Chadd          * not enough time has passed since the NF calibration was started,
63876bd547bSAdrian Chadd          * because under certain conditions (when first moving to a new
63976bd547bSAdrian Chadd          * channel) the NF calibration may be checked very repeatedly.
64076bd547bSAdrian Chadd          * Or, there may be CW interference keeping the NF calibration
64176bd547bSAdrian Chadd          * from completing.  Check the delta time between when the NF
64276bd547bSAdrian Chadd          * calibration was started and now to see whether the NF calibration
64376bd547bSAdrian Chadd          * should have already completed (but hasn't, probably due to CW
64476bd547bSAdrian Chadd          * interference), or hasn't had enough time to finish yet.
64576bd547bSAdrian Chadd          */
64676bd547bSAdrian Chadd         /*
64776bd547bSAdrian Chadd          * AH_NF_CAL_DUR_MAX_TSF - A conservative maximum time that the
64876bd547bSAdrian Chadd          *     HW should need to finish a NF calibration.  If the HW
64976bd547bSAdrian Chadd          *     does not complete a NF calibration within this time period,
65076bd547bSAdrian Chadd          *     there must be a problem - probably CW interference.
65176bd547bSAdrian Chadd          * AH_NF_CAL_PERIOD_MAX_TSF - A conservative maximum time between
65276bd547bSAdrian Chadd          *     check of the HW's NF calibration being finished.
65376bd547bSAdrian Chadd          *     If the difference between the current TSF and the TSF
65476bd547bSAdrian Chadd          *     recorded when the NF calibration started is larger than this
65576bd547bSAdrian Chadd          *     value, the TSF must have been reset.
65676bd547bSAdrian Chadd          *     In general, we expect the TSF to only be reset during
65776bd547bSAdrian Chadd          *     regular operation for STAs, not for APs.  However, an
65876bd547bSAdrian Chadd          *     AP's TSF could be reset when joining an IBSS.
65976bd547bSAdrian Chadd          *     There's an outside chance that this could result in the
66076bd547bSAdrian Chadd          *     CW_INT flag being erroneously set, if the TSF adjustment
66176bd547bSAdrian Chadd          *     is smaller than AH_NF_CAL_PERIOD_MAX_TSF but larger than
66276bd547bSAdrian Chadd          *     AH_NF_CAL_DUR_TSF.  However, even if this does happen,
66376bd547bSAdrian Chadd          *     it shouldn't matter, as the IBSS case shouldn't be
66476bd547bSAdrian Chadd          *     concerned about CW_INT.
66576bd547bSAdrian Chadd          */
66676bd547bSAdrian Chadd         /* AH_NF_CAL_DUR_TSF - 90 sec in usec units */
66776bd547bSAdrian Chadd         #define AH_NF_CAL_DUR_TSF (90 * 1000 * 1000)
66876bd547bSAdrian Chadd         /* AH_NF_CAL_PERIOD_MAX_TSF - 180 sec in usec units */
66976bd547bSAdrian Chadd         #define AH_NF_CAL_PERIOD_MAX_TSF (180 * 1000 * 1000)
67076bd547bSAdrian Chadd         /* wraparound handled by using unsigned values */
67176bd547bSAdrian Chadd         tsf32 = ar9300_get_tsf32(ah);
67276bd547bSAdrian Chadd         nf_cal_dur_tsf = tsf32 - AH9300(ah)->nf_tsf32;
67376bd547bSAdrian Chadd         if (nf_cal_dur_tsf > AH_NF_CAL_PERIOD_MAX_TSF) {
67476bd547bSAdrian Chadd             /*
67576bd547bSAdrian Chadd              * The TSF must have gotten reset during the NF cal -
67676bd547bSAdrian Chadd              * just reset the NF TSF timestamp, so the next time
67776bd547bSAdrian Chadd              * this function is called, the timestamp comparison
67876bd547bSAdrian Chadd              * will be valid.
67976bd547bSAdrian Chadd              */
68076bd547bSAdrian Chadd             AH9300(ah)->nf_tsf32 = tsf32;
68176bd547bSAdrian Chadd         } else if (nf_cal_dur_tsf > AH_NF_CAL_DUR_TSF) {
68276bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
68376bd547bSAdrian Chadd                 "%s: NF did not complete in calibration window\n", __func__);
68476bd547bSAdrian Chadd             /* the NF incompletion is probably due to CW interference */
685e113789bSAdrian Chadd             chan->ic_state |= IEEE80211_CHANSTATE_CWINT;
68676bd547bSAdrian Chadd         }
68776bd547bSAdrian Chadd         return 0; /* HW's NF measurement not finished */
68876bd547bSAdrian Chadd     }
689e113789bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_NFCAL,
690e113789bSAdrian Chadd         "%s[%d] chan %d\n", __func__, __LINE__, ichan->channel);
691e113789bSAdrian Chadd     is_2g = !! IS_CHAN_2GHZ(ichan);
69276bd547bSAdrian Chadd     ar9300_upload_noise_floor(ah, is_2g, nfarray);
69376bd547bSAdrian Chadd 
69476bd547bSAdrian Chadd     /* Update the NF buffer for each chain masked by chainmask */
69576bd547bSAdrian Chadd #ifdef ATH_NF_PER_CHAN
696e113789bSAdrian Chadd     h = &ichan->nf_cal_hist;
69776bd547bSAdrian Chadd     nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;
69876bd547bSAdrian Chadd #else
69976bd547bSAdrian Chadd     if (is_scan) {
70076bd547bSAdrian Chadd         /*
70176bd547bSAdrian Chadd          * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct
70276bd547bSAdrian Chadd          * rather than a HAL_NFCAL_HIST_FULL struct.
70376bd547bSAdrian Chadd          * As long as we only use the first history element of nf_cal_buffer
704e113789bSAdrian Chadd          * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use
70576bd547bSAdrian Chadd          * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably.
70676bd547bSAdrian Chadd          */
707e113789bSAdrian Chadd         h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;
70876bd547bSAdrian Chadd         nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL;
70976bd547bSAdrian Chadd     } else {
71076bd547bSAdrian Chadd         h = &AH_PRIVATE(ah)->nf_cal_hist;
71176bd547bSAdrian Chadd         nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;
71276bd547bSAdrian Chadd     }
71376bd547bSAdrian Chadd #endif
71476bd547bSAdrian Chadd 
71576bd547bSAdrian Chadd     /*
71676bd547bSAdrian Chadd      * nf_no_lim = median value from NF history buffer without bounds limits,
71776bd547bSAdrian Chadd      * priv_nf = median value from NF history buffer with bounds limits.
71876bd547bSAdrian Chadd      */
71976bd547bSAdrian Chadd     nf_no_lim = ar9300_update_nf_hist_buff(ah, h, nfarray, nf_hist_len);
720e113789bSAdrian Chadd     ichan->rawNoiseFloor = h->base.priv_nf[0];
72176bd547bSAdrian Chadd 
72276bd547bSAdrian Chadd     /* check if there is interference */
723e113789bSAdrian Chadd //    ichan->channel_flags &= (~CHANNEL_CW_INT);
72476bd547bSAdrian Chadd     /*
72576bd547bSAdrian Chadd      * Use AR9300_EMULATION to check for emulation purpose as PCIE Device ID
72676bd547bSAdrian Chadd      * 0xABCD is recognized as valid Osprey as WAR in some EVs.
72776bd547bSAdrian Chadd      */
728e113789bSAdrian Chadd     if (nf_no_lim > ahp->nfp->nominal + ahp->nf_cw_int_delta) {
72976bd547bSAdrian Chadd         /*
73076bd547bSAdrian Chadd          * Since this CW interference check is being applied to the
73176bd547bSAdrian Chadd          * median element of the NF history buffer, this indicates that
73276bd547bSAdrian Chadd          * the CW interference is persistent.  A single high NF reading
73376bd547bSAdrian Chadd          * will not show up in the median, and thus will not cause the
73476bd547bSAdrian Chadd          * CW_INT flag to be set.
73576bd547bSAdrian Chadd          */
736e113789bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_NFCAL,
73776bd547bSAdrian Chadd             "%s: NF Cal: CW interferer detected through NF: %d\n",
73876bd547bSAdrian Chadd             __func__, nf_no_lim);
739e113789bSAdrian Chadd         chan->ic_state |= IEEE80211_CHANSTATE_CWINT;
74076bd547bSAdrian Chadd     }
74176bd547bSAdrian Chadd     return 1; /* HW's NF measurement finished */
74276bd547bSAdrian Chadd }
74376bd547bSAdrian Chadd #undef IS
74476bd547bSAdrian Chadd 
74576bd547bSAdrian Chadd static inline void
ar9300_get_delta_slope_values(struct ath_hal * ah,u_int32_t coef_scaled,u_int32_t * coef_mantissa,u_int32_t * coef_exponent)74676bd547bSAdrian Chadd ar9300_get_delta_slope_values(struct ath_hal *ah, u_int32_t coef_scaled,
74776bd547bSAdrian Chadd     u_int32_t *coef_mantissa, u_int32_t *coef_exponent)
74876bd547bSAdrian Chadd {
74976bd547bSAdrian Chadd     u_int32_t coef_exp, coef_man;
75076bd547bSAdrian Chadd 
75176bd547bSAdrian Chadd     /*
75276bd547bSAdrian Chadd      * ALGO -> coef_exp = 14-floor(log2(coef));
75376bd547bSAdrian Chadd      * floor(log2(x)) is the highest set bit position
75476bd547bSAdrian Chadd      */
75576bd547bSAdrian Chadd     for (coef_exp = 31; coef_exp > 0; coef_exp--) {
75676bd547bSAdrian Chadd         if ((coef_scaled >> coef_exp) & 0x1) {
75776bd547bSAdrian Chadd             break;
75876bd547bSAdrian Chadd         }
75976bd547bSAdrian Chadd     }
76076bd547bSAdrian Chadd     /* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */
76176bd547bSAdrian Chadd     HALASSERT(coef_exp);
76276bd547bSAdrian Chadd     coef_exp = 14 - (coef_exp - COEF_SCALE_S);
76376bd547bSAdrian Chadd 
76476bd547bSAdrian Chadd 
76576bd547bSAdrian Chadd     /*
76676bd547bSAdrian Chadd      * ALGO -> coef_man = floor(coef* 2^coef_exp+0.5);
76776bd547bSAdrian Chadd      * The coefficient is already shifted up for scaling
76876bd547bSAdrian Chadd      */
76976bd547bSAdrian Chadd     coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));
77076bd547bSAdrian Chadd 
77176bd547bSAdrian Chadd     *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp);
77276bd547bSAdrian Chadd     *coef_exponent = coef_exp - 16;
77376bd547bSAdrian Chadd }
77476bd547bSAdrian Chadd 
77576bd547bSAdrian Chadd #define MAX_ANALOG_START        319             /* XXX */
77676bd547bSAdrian Chadd 
77776bd547bSAdrian Chadd /*
77876bd547bSAdrian Chadd  * Delta slope coefficient computation.
77976bd547bSAdrian Chadd  * Required for OFDM operation.
78076bd547bSAdrian Chadd  */
78176bd547bSAdrian Chadd static void
ar9300_set_delta_slope(struct ath_hal * ah,struct ieee80211_channel * chan)782e113789bSAdrian Chadd ar9300_set_delta_slope(struct ath_hal *ah, struct ieee80211_channel *chan)
78376bd547bSAdrian Chadd {
78476bd547bSAdrian Chadd     u_int32_t coef_scaled, ds_coef_exp, ds_coef_man;
78576bd547bSAdrian Chadd     u_int32_t fclk = COEFF; /* clock * 2.5 */
78676bd547bSAdrian Chadd 
78776bd547bSAdrian Chadd     u_int32_t clock_mhz_scaled = 0x1000000 * fclk;
78876bd547bSAdrian Chadd     CHAN_CENTERS centers;
78976bd547bSAdrian Chadd 
79076bd547bSAdrian Chadd     /*
79176bd547bSAdrian Chadd      * half and quarter rate can divide the scaled clock by 2 or 4
79276bd547bSAdrian Chadd      * scale for selected channel bandwidth
79376bd547bSAdrian Chadd      */
794e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_HALF(chan)) {
79576bd547bSAdrian Chadd         clock_mhz_scaled = clock_mhz_scaled >> 1;
796e113789bSAdrian Chadd     } else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
79776bd547bSAdrian Chadd         clock_mhz_scaled = clock_mhz_scaled >> 2;
79876bd547bSAdrian Chadd     }
79976bd547bSAdrian Chadd 
80076bd547bSAdrian Chadd     /*
80176bd547bSAdrian Chadd      * ALGO -> coef = 1e8/fcarrier*fclock/40;
80276bd547bSAdrian Chadd      * scaled coef to provide precision for this floating calculation
80376bd547bSAdrian Chadd      */
80476bd547bSAdrian Chadd     ar9300_get_channel_centers(ah, chan, &centers);
80576bd547bSAdrian Chadd     coef_scaled = clock_mhz_scaled / centers.synth_center;
80676bd547bSAdrian Chadd 
80776bd547bSAdrian Chadd     ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp);
80876bd547bSAdrian Chadd 
80976bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
81076bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
81176bd547bSAdrian Chadd 
81276bd547bSAdrian Chadd     /*
81376bd547bSAdrian Chadd      * For Short GI,
81476bd547bSAdrian Chadd      * scaled coeff is 9/10 that of normal coeff
81576bd547bSAdrian Chadd      */
81676bd547bSAdrian Chadd     coef_scaled = (9 * coef_scaled) / 10;
81776bd547bSAdrian Chadd 
81876bd547bSAdrian Chadd     ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp);
81976bd547bSAdrian Chadd 
82076bd547bSAdrian Chadd     /* for short gi */
82176bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_MAN, ds_coef_man);
82276bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_EXP, ds_coef_exp);
82376bd547bSAdrian Chadd }
82476bd547bSAdrian Chadd 
825e113789bSAdrian Chadd #define IS(_c, _f)       (IEEE80211_IS_ ## _f(_c))
82676bd547bSAdrian Chadd 
827e113789bSAdrian Chadd /*
828e113789bSAdrian Chadd  * XXX FreeBSD: This should be turned into something generic in ath_hal!
829e113789bSAdrian Chadd  */
830e113789bSAdrian Chadd HAL_CHANNEL_INTERNAL *
ar9300_check_chan(struct ath_hal * ah,const struct ieee80211_channel * chan)831e113789bSAdrian Chadd ar9300_check_chan(struct ath_hal *ah, const struct ieee80211_channel *chan)
83276bd547bSAdrian Chadd {
83394d5d4adSAdrian Chadd 
83494d5d4adSAdrian Chadd     if (chan == NULL) {
83594d5d4adSAdrian Chadd         return AH_NULL;
83694d5d4adSAdrian Chadd     }
83794d5d4adSAdrian Chadd 
838e113789bSAdrian Chadd     if ((IS(chan, CHAN_2GHZ) ^ IS(chan, CHAN_5GHZ)) == 0) {
83976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CHANNEL,
84076bd547bSAdrian Chadd             "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n",
841e113789bSAdrian Chadd             __func__, chan->ic_freq , chan->ic_flags);
84276bd547bSAdrian Chadd         return AH_NULL;
84376bd547bSAdrian Chadd     }
84476bd547bSAdrian Chadd 
845e113789bSAdrian Chadd     /*
846e113789bSAdrian Chadd      * FreeBSD sets multiple flags, so this will fail.
847e113789bSAdrian Chadd      */
848e113789bSAdrian Chadd #if 0
849e113789bSAdrian Chadd     if ((IS(chan, CHAN_OFDM) ^ IS(chan, CHAN_CCK) ^ IS(chan, CHAN_DYN) ^
850e113789bSAdrian Chadd          IS(chan, CHAN_HT20) ^ IS(chan, CHAN_HT40U) ^
851e113789bSAdrian Chadd          IS(chan, CHAN_HT40D)) == 0)
85276bd547bSAdrian Chadd     {
85376bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CHANNEL,
85476bd547bSAdrian Chadd             "%s: invalid channel %u/0x%x; not marked as "
855e113789bSAdrian Chadd             "OFDM or CCK or DYN or HT20 or HT40PLUS or HT40MINUS\n",
856e113789bSAdrian Chadd             __func__, chan->ic_freq , chan->ic_flags);
85776bd547bSAdrian Chadd         return AH_NULL;
85876bd547bSAdrian Chadd     }
859e113789bSAdrian Chadd #endif
86076bd547bSAdrian Chadd 
86176bd547bSAdrian Chadd     return (ath_hal_checkchannel(ah, chan));
86276bd547bSAdrian Chadd }
86376bd547bSAdrian Chadd #undef IS
86476bd547bSAdrian Chadd 
86576bd547bSAdrian Chadd static void
ar9300_set_11n_regs(struct ath_hal * ah,struct ieee80211_channel * chan,HAL_HT_MACMODE macmode)866e113789bSAdrian Chadd ar9300_set_11n_regs(struct ath_hal *ah, struct ieee80211_channel *chan,
86776bd547bSAdrian Chadd     HAL_HT_MACMODE macmode)
86876bd547bSAdrian Chadd {
86976bd547bSAdrian Chadd     u_int32_t phymode;
870e113789bSAdrian Chadd //    struct ath_hal_9300 *ahp = AH9300(ah);
87176bd547bSAdrian Chadd     u_int32_t enable_dac_fifo;
87276bd547bSAdrian Chadd 
87376bd547bSAdrian Chadd     /* XXX */
87476bd547bSAdrian Chadd     enable_dac_fifo =
87576bd547bSAdrian Chadd         OS_REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO;
87676bd547bSAdrian Chadd 
87776bd547bSAdrian Chadd     /* Enable 11n HT, 20 MHz */
87876bd547bSAdrian Chadd     phymode =
87976bd547bSAdrian Chadd         AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_SHORT_GI_40
88076bd547bSAdrian Chadd         | enable_dac_fifo;
88176bd547bSAdrian Chadd     /* Configure baseband for dynamic 20/40 operation */
882e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_HT40(chan)) {
88376bd547bSAdrian Chadd         phymode |= AR_PHY_GC_DYN2040_EN;
88476bd547bSAdrian Chadd         /* Configure control (primary) channel at +-10MHz */
885e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_HT40U(chan)) {
88676bd547bSAdrian Chadd             phymode |= AR_PHY_GC_DYN2040_PRI_CH;
88776bd547bSAdrian Chadd         }
88876bd547bSAdrian Chadd 
889e113789bSAdrian Chadd #if 0
89076bd547bSAdrian Chadd         /* Configure 20/25 spacing */
89176bd547bSAdrian Chadd         if (ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_25) {
89276bd547bSAdrian Chadd             phymode |= AR_PHY_GC_DYN2040_EXT_CH;
89376bd547bSAdrian Chadd         }
894e113789bSAdrian Chadd #endif
89576bd547bSAdrian Chadd     }
89676bd547bSAdrian Chadd 
89776bd547bSAdrian Chadd     /* make sure we preserve INI settings */
89876bd547bSAdrian Chadd     phymode |= OS_REG_READ(ah, AR_PHY_GEN_CTRL);
89976bd547bSAdrian Chadd 
90076bd547bSAdrian Chadd     /* EV 62881/64991 - turn off Green Field detection for Maverick STA beta */
90176bd547bSAdrian Chadd     phymode &= ~AR_PHY_GC_GF_DETECT_EN;
90276bd547bSAdrian Chadd 
90376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode);
90476bd547bSAdrian Chadd 
90576bd547bSAdrian Chadd     /* Set IFS timing for half/quarter rates */
906e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) {
90776bd547bSAdrian Chadd         u_int32_t modeselect = OS_REG_READ(ah, AR_PHY_MODE);
90876bd547bSAdrian Chadd 
909e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_HALF(chan)) {
91076bd547bSAdrian Chadd             modeselect |= AR_PHY_MS_HALF_RATE;
911e113789bSAdrian Chadd         } else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
91276bd547bSAdrian Chadd             modeselect |= AR_PHY_MS_QUARTER_RATE;
91376bd547bSAdrian Chadd         }
91476bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_MODE, modeselect);
91576bd547bSAdrian Chadd 
91676bd547bSAdrian Chadd         ar9300_set_ifs_timing(ah, chan);
91776bd547bSAdrian Chadd         OS_REG_RMW_FIELD(
91876bd547bSAdrian Chadd             ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 0x3);
91976bd547bSAdrian Chadd     }
92076bd547bSAdrian Chadd 
92176bd547bSAdrian Chadd     /* Configure MAC for 20/40 operation */
92276bd547bSAdrian Chadd     ar9300_set_11n_mac2040(ah, macmode);
92376bd547bSAdrian Chadd 
92476bd547bSAdrian Chadd     /* global transmit timeout (25 TUs default)*/
92576bd547bSAdrian Chadd     /* XXX - put this elsewhere??? */
92676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
92776bd547bSAdrian Chadd 
92876bd547bSAdrian Chadd     /* carrier sense timeout */
92976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
93076bd547bSAdrian Chadd }
93176bd547bSAdrian Chadd 
93276bd547bSAdrian Chadd /*
93376bd547bSAdrian Chadd  * Spur mitigation for MRC CCK
93476bd547bSAdrian Chadd  */
93576bd547bSAdrian Chadd static void
ar9300_spur_mitigate_mrc_cck(struct ath_hal * ah,struct ieee80211_channel * chan)936e113789bSAdrian Chadd ar9300_spur_mitigate_mrc_cck(struct ath_hal *ah, struct ieee80211_channel *chan)
93776bd547bSAdrian Chadd {
93876bd547bSAdrian Chadd     int i;
93976bd547bSAdrian Chadd     /* spur_freq_for_osprey - hardcoded by Systems team for now. */
94076bd547bSAdrian Chadd     u_int32_t spur_freq_for_osprey[4] = { 2420, 2440, 2464, 2480 };
94176bd547bSAdrian Chadd     u_int32_t spur_freq_for_jupiter[2] = { 2440, 2464};
94276bd547bSAdrian Chadd     int cur_bb_spur, negative = 0, cck_spur_freq;
94376bd547bSAdrian Chadd     u_int8_t* spur_fbin_ptr = NULL;
94476bd547bSAdrian Chadd     int synth_freq;
94576bd547bSAdrian Chadd     int range = 10;
94676bd547bSAdrian Chadd     int max_spurcounts = OSPREY_EEPROM_MODAL_SPURS;
947e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
94876bd547bSAdrian Chadd 
94976bd547bSAdrian Chadd     /*
95076bd547bSAdrian Chadd      * Need to verify range +/- 10 MHz in control channel, otherwise spur
95176bd547bSAdrian Chadd      * is out-of-band and can be ignored.
95276bd547bSAdrian Chadd      */
95376bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) ||
95476bd547bSAdrian Chadd         AR_SREV_WASP(ah)  || AR_SREV_SCORPION(ah)) {
95576bd547bSAdrian Chadd         spur_fbin_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1);
95676bd547bSAdrian Chadd         if (spur_fbin_ptr[0] == 0) {
95776bd547bSAdrian Chadd             return;      /* No spur in the mode */
95876bd547bSAdrian Chadd         }
959e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_HT40(chan)) {
96076bd547bSAdrian Chadd             range = 19;
96176bd547bSAdrian Chadd             if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH)
96276bd547bSAdrian Chadd                 == 0x0)
96376bd547bSAdrian Chadd             {
964e113789bSAdrian Chadd                 synth_freq = ichan->channel + 10;
96576bd547bSAdrian Chadd             } else {
966e113789bSAdrian Chadd                 synth_freq = ichan->channel - 10;
96776bd547bSAdrian Chadd             }
96876bd547bSAdrian Chadd         } else {
96976bd547bSAdrian Chadd             range = 10;
970e113789bSAdrian Chadd             synth_freq = ichan->channel;
97176bd547bSAdrian Chadd         }
97276bd547bSAdrian Chadd     } else if(AR_SREV_JUPITER(ah)) {
97376bd547bSAdrian Chadd         range = 5;
97476bd547bSAdrian Chadd         max_spurcounts = 2; /* Hardcoded by Jupiter Systems team for now. */
975e113789bSAdrian Chadd         synth_freq = ichan->channel;
97676bd547bSAdrian Chadd     } else {
97776bd547bSAdrian Chadd         range = 10;
97876bd547bSAdrian Chadd         max_spurcounts = 4; /* Hardcoded by Osprey Systems team for now. */
979e113789bSAdrian Chadd         synth_freq = ichan->channel;
98076bd547bSAdrian Chadd     }
98176bd547bSAdrian Chadd 
98276bd547bSAdrian Chadd     for (i = 0; i < max_spurcounts; i++) {
98376bd547bSAdrian Chadd         negative = 0;
98476bd547bSAdrian Chadd 
98576bd547bSAdrian Chadd         if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) ||
98676bd547bSAdrian Chadd             AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {
98776bd547bSAdrian Chadd             cur_bb_spur =
98876bd547bSAdrian Chadd                 FBIN2FREQ(spur_fbin_ptr[i], HAL_FREQ_BAND_2GHZ) - synth_freq;
98976bd547bSAdrian Chadd         } else if(AR_SREV_JUPITER(ah)) {
99076bd547bSAdrian Chadd             cur_bb_spur = spur_freq_for_jupiter[i] - synth_freq;
99176bd547bSAdrian Chadd         } else {
99276bd547bSAdrian Chadd             cur_bb_spur = spur_freq_for_osprey[i] - synth_freq;
99376bd547bSAdrian Chadd         }
99476bd547bSAdrian Chadd 
99576bd547bSAdrian Chadd         if (cur_bb_spur < 0) {
99676bd547bSAdrian Chadd             negative = 1;
99776bd547bSAdrian Chadd             cur_bb_spur = -cur_bb_spur;
99876bd547bSAdrian Chadd         }
99976bd547bSAdrian Chadd         if (cur_bb_spur < range) {
100076bd547bSAdrian Chadd             cck_spur_freq = (int)((cur_bb_spur << 19) / 11);
100176bd547bSAdrian Chadd             if (negative == 1) {
100276bd547bSAdrian Chadd                 cck_spur_freq = -cck_spur_freq;
100376bd547bSAdrian Chadd             }
100476bd547bSAdrian Chadd             cck_spur_freq = cck_spur_freq & 0xfffff;
100576bd547bSAdrian Chadd             /*OS_REG_WRITE_field(ah, BB_agc_control.ycok_max, 0x7);*/
100676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
100776bd547bSAdrian Chadd                 AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7);
100876bd547bSAdrian Chadd             /*OS_REG_WRITE_field(ah, BB_cck_spur_mit.spur_rssi_thr, 0x7f);*/
100976bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
101076bd547bSAdrian Chadd                 AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f);
101176bd547bSAdrian Chadd             /*OS_REG_WRITE(ah, BB_cck_spur_mit.spur_filter_type, 0x2);*/
101276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
101376bd547bSAdrian Chadd                 AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE, 0x2);
101476bd547bSAdrian Chadd             /*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x1);*/
101576bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
101676bd547bSAdrian Chadd                 AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x1);
101776bd547bSAdrian Chadd             /*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, cck_spur_freq);*/
101876bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
101976bd547bSAdrian Chadd                 AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ,
102076bd547bSAdrian Chadd                 cck_spur_freq);
102176bd547bSAdrian Chadd             return;
102276bd547bSAdrian Chadd         }
102376bd547bSAdrian Chadd     }
102476bd547bSAdrian Chadd 
102576bd547bSAdrian Chadd     /*OS_REG_WRITE(ah, BB_agc_control.ycok_max, 0x5);*/
102676bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5);
102776bd547bSAdrian Chadd     /*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x0);*/
102876bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
102976bd547bSAdrian Chadd         AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0);
103076bd547bSAdrian Chadd     /*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, 0x0);*/
103176bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
103276bd547bSAdrian Chadd         AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0x0);
103376bd547bSAdrian Chadd }
103476bd547bSAdrian Chadd 
103576bd547bSAdrian Chadd /* Spur mitigation for OFDM */
103676bd547bSAdrian Chadd static void
ar9300_spur_mitigate_ofdm(struct ath_hal * ah,struct ieee80211_channel * chan)1037e113789bSAdrian Chadd ar9300_spur_mitigate_ofdm(struct ath_hal *ah, struct ieee80211_channel *chan)
103876bd547bSAdrian Chadd {
103976bd547bSAdrian Chadd     int synth_freq;
104076bd547bSAdrian Chadd     int range = 10;
104176bd547bSAdrian Chadd     int freq_offset = 0;
104276bd547bSAdrian Chadd     int spur_freq_sd = 0;
104376bd547bSAdrian Chadd     int spur_subchannel_sd = 0;
104476bd547bSAdrian Chadd     int spur_delta_phase = 0;
104576bd547bSAdrian Chadd     int mask_index = 0;
104676bd547bSAdrian Chadd     int i;
104776bd547bSAdrian Chadd     int mode;
104876bd547bSAdrian Chadd     u_int8_t* spur_chans_ptr;
1049e113789bSAdrian Chadd     struct ath_hal_9300 *ahp;
1050e113789bSAdrian Chadd     ahp = AH9300(ah);
1051e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
105276bd547bSAdrian Chadd 
1053e113789bSAdrian Chadd     if (IS_CHAN_5GHZ(ichan)) {
105476bd547bSAdrian Chadd         spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 0);
105576bd547bSAdrian Chadd         mode = 0;
105676bd547bSAdrian Chadd     } else {
105776bd547bSAdrian Chadd         spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1);
105876bd547bSAdrian Chadd         mode = 1;
105976bd547bSAdrian Chadd     }
106076bd547bSAdrian Chadd 
1061e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_HT40(chan)) {
106276bd547bSAdrian Chadd         range = 19;
106376bd547bSAdrian Chadd         if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH)
106476bd547bSAdrian Chadd             == 0x0)
106576bd547bSAdrian Chadd         {
1066e113789bSAdrian Chadd             synth_freq = ichan->channel - 10;
106776bd547bSAdrian Chadd         } else {
1068e113789bSAdrian Chadd             synth_freq = ichan->channel + 10;
106976bd547bSAdrian Chadd         }
107076bd547bSAdrian Chadd     } else {
107176bd547bSAdrian Chadd         range = 10;
1072e113789bSAdrian Chadd         synth_freq = ichan->channel;
107376bd547bSAdrian Chadd     }
107476bd547bSAdrian Chadd 
107576bd547bSAdrian Chadd     /* Clean all spur register fields */
107676bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0);
107776bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, 0);
107876bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0);
107976bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
108076bd547bSAdrian Chadd         AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 0);
108176bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
108276bd547bSAdrian Chadd         AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0);
108376bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
108476bd547bSAdrian Chadd         AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0);
108576bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0);
108676bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 0);
108776bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
108876bd547bSAdrian Chadd         AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 0);
108976bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0);
109076bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0);
109176bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0);
109276bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
109376bd547bSAdrian Chadd         AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0);
109476bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
109576bd547bSAdrian Chadd         AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0);
109676bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
109776bd547bSAdrian Chadd         AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0);
109876bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
109976bd547bSAdrian Chadd         AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0);
110076bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
110176bd547bSAdrian Chadd         AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0);
110276bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah,
110376bd547bSAdrian Chadd         AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0);
110476bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0);
110576bd547bSAdrian Chadd 
110676bd547bSAdrian Chadd     i = 0;
110776bd547bSAdrian Chadd     while (spur_chans_ptr[i] && i < 5) {
110876bd547bSAdrian Chadd         freq_offset = FBIN2FREQ(spur_chans_ptr[i], mode) - synth_freq;
110976bd547bSAdrian Chadd         if (abs(freq_offset) < range) {
111076bd547bSAdrian Chadd             /*
111176bd547bSAdrian Chadd             printf(
111276bd547bSAdrian Chadd                 "Spur Mitigation for OFDM: Synth Frequency = %d, "
111376bd547bSAdrian Chadd                 "Spur Frequency = %d\n",
111476bd547bSAdrian Chadd                 synth_freq, FBIN2FREQ(spur_chans_ptr[i], mode));
111576bd547bSAdrian Chadd              */
1116e113789bSAdrian Chadd             if (IEEE80211_IS_CHAN_HT40(chan)) {
111776bd547bSAdrian Chadd                 if (freq_offset < 0) {
111876bd547bSAdrian Chadd                     if (OS_REG_READ_FIELD(
111976bd547bSAdrian Chadd                         ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
112076bd547bSAdrian Chadd                     {
112176bd547bSAdrian Chadd                         spur_subchannel_sd = 1;
112276bd547bSAdrian Chadd                     } else {
112376bd547bSAdrian Chadd                         spur_subchannel_sd = 0;
112476bd547bSAdrian Chadd                     }
112576bd547bSAdrian Chadd                     spur_freq_sd = ((freq_offset + 10) << 9) / 11;
112676bd547bSAdrian Chadd                 } else {
112776bd547bSAdrian Chadd                     if (OS_REG_READ_FIELD(ah,
112876bd547bSAdrian Chadd                         AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
112976bd547bSAdrian Chadd                     {
113076bd547bSAdrian Chadd                         spur_subchannel_sd = 0;
113176bd547bSAdrian Chadd                     } else {
113276bd547bSAdrian Chadd                         spur_subchannel_sd = 1;
113376bd547bSAdrian Chadd                     }
113476bd547bSAdrian Chadd                     spur_freq_sd = ((freq_offset - 10) << 9) / 11;
113576bd547bSAdrian Chadd                 }
113676bd547bSAdrian Chadd                 spur_delta_phase = (freq_offset << 17) / 5;
113776bd547bSAdrian Chadd             } else {
113876bd547bSAdrian Chadd                 spur_subchannel_sd = 0;
113976bd547bSAdrian Chadd                 spur_freq_sd = (freq_offset << 9) / 11;
114076bd547bSAdrian Chadd                 spur_delta_phase = (freq_offset << 18) / 5;
114176bd547bSAdrian Chadd             }
114276bd547bSAdrian Chadd             spur_freq_sd = spur_freq_sd & 0x3ff;
114376bd547bSAdrian Chadd             spur_delta_phase = spur_delta_phase & 0xfffff;
114476bd547bSAdrian Chadd             /*
114576bd547bSAdrian Chadd             printf(
114676bd547bSAdrian Chadd                 "spur_subchannel_sd = %d, spur_freq_sd = 0x%x, "
114776bd547bSAdrian Chadd                 "spur_delta_phase = 0x%x\n", spur_subchannel_sd,
114876bd547bSAdrian Chadd                 spur_freq_sd, spur_delta_phase);
114976bd547bSAdrian Chadd              */
115076bd547bSAdrian Chadd 
115176bd547bSAdrian Chadd             /* OFDM Spur mitigation */
115276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
115376bd547bSAdrian Chadd                 AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0x1);
115476bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
115576bd547bSAdrian Chadd                 AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd);
115676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
115776bd547bSAdrian Chadd                 AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE,
115876bd547bSAdrian Chadd                 spur_delta_phase);
115976bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
116076bd547bSAdrian Chadd                 AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD,
116176bd547bSAdrian Chadd                 spur_subchannel_sd);
116276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
116376bd547bSAdrian Chadd                 AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0x1);
116476bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
116576bd547bSAdrian Chadd                 AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR,
116676bd547bSAdrian Chadd                 0x1);
116776bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
116876bd547bSAdrian Chadd                 AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0x1);
116976bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
117076bd547bSAdrian Chadd                 AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34);
117176bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
117276bd547bSAdrian Chadd                 AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1);
117376bd547bSAdrian Chadd 
117476bd547bSAdrian Chadd             /*
117576bd547bSAdrian Chadd              * Do not subtract spur power from noise floor for wasp.
117676bd547bSAdrian Chadd              * This causes the maximum client test (on Veriwave) to fail
117776bd547bSAdrian Chadd              * when run on spur channel (2464 MHz).
117876bd547bSAdrian Chadd              * Refer to ev#82746 and ev#82744.
117976bd547bSAdrian Chadd              */
118076bd547bSAdrian Chadd             if (!AR_SREV_WASP(ah) && (OS_REG_READ_FIELD(ah, AR_PHY_MODE,
118176bd547bSAdrian Chadd                                            AR_PHY_MODE_DYNAMIC) == 0x1)) {
118276bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
118376bd547bSAdrian Chadd                     AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1);
118476bd547bSAdrian Chadd             }
118576bd547bSAdrian Chadd 
118676bd547bSAdrian Chadd             mask_index = (freq_offset << 4) / 5;
118776bd547bSAdrian Chadd             if (mask_index < 0) {
118876bd547bSAdrian Chadd                 mask_index = mask_index - 1;
118976bd547bSAdrian Chadd             }
119076bd547bSAdrian Chadd             mask_index = mask_index & 0x7f;
119176bd547bSAdrian Chadd             /*printf("Bin 0x%x\n", mask_index);*/
119276bd547bSAdrian Chadd 
119376bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
119476bd547bSAdrian Chadd                 AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0x1);
119576bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
119676bd547bSAdrian Chadd                 AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0x1);
119776bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
119876bd547bSAdrian Chadd                 AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1);
119976bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
120076bd547bSAdrian Chadd                 AR_PHY_PILOT_SPUR_MASK,
120176bd547bSAdrian Chadd                 AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index);
120276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
120376bd547bSAdrian Chadd                 AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A,
120476bd547bSAdrian Chadd                 mask_index);
120576bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
120676bd547bSAdrian Chadd                 AR_PHY_CHAN_SPUR_MASK,
120776bd547bSAdrian Chadd                 AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index);
120876bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
120976bd547bSAdrian Chadd                 AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A,
121076bd547bSAdrian Chadd                 0xc);
121176bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
121276bd547bSAdrian Chadd                 AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A,
121376bd547bSAdrian Chadd                 0xc);
121476bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
121576bd547bSAdrian Chadd                 AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0);
121676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
121776bd547bSAdrian Chadd                 AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff);
121876bd547bSAdrian Chadd             /*
121976bd547bSAdrian Chadd             printf("BB_timing_control_4 = 0x%x\n",
122076bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_TIMING4));
122176bd547bSAdrian Chadd             printf("BB_timing_control_11 = 0x%x\n",
122276bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_TIMING11));
122376bd547bSAdrian Chadd             printf("BB_ext_chan_scorr_thr = 0x%x\n",
122476bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_SFCORR_EXT));
122576bd547bSAdrian Chadd             printf("BB_spur_mask_controls = 0x%x\n",
122676bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_SPUR_REG));
122776bd547bSAdrian Chadd             printf("BB_pilot_spur_mask = 0x%x\n",
122876bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_PILOT_SPUR_MASK));
122976bd547bSAdrian Chadd             printf("BB_chan_spur_mask = 0x%x\n",
123076bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_CHAN_SPUR_MASK));
123176bd547bSAdrian Chadd             printf("BB_vit_spur_mask_A = 0x%x\n",
123276bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_SPUR_MASK_A));
123376bd547bSAdrian Chadd              */
123476bd547bSAdrian Chadd             break;
123576bd547bSAdrian Chadd         }
123676bd547bSAdrian Chadd         i++;
123776bd547bSAdrian Chadd     }
123876bd547bSAdrian Chadd }
123976bd547bSAdrian Chadd 
124076bd547bSAdrian Chadd 
124176bd547bSAdrian Chadd /*
124276bd547bSAdrian Chadd  * Convert to baseband spur frequency given input channel frequency
124376bd547bSAdrian Chadd  * and compute register settings below.
124476bd547bSAdrian Chadd  */
124576bd547bSAdrian Chadd static void
ar9300_spur_mitigate(struct ath_hal * ah,struct ieee80211_channel * chan)1246e113789bSAdrian Chadd ar9300_spur_mitigate(struct ath_hal *ah, struct ieee80211_channel *chan)
124776bd547bSAdrian Chadd {
124876bd547bSAdrian Chadd     ar9300_spur_mitigate_ofdm(ah, chan);
124976bd547bSAdrian Chadd     ar9300_spur_mitigate_mrc_cck(ah, chan);
125076bd547bSAdrian Chadd }
125176bd547bSAdrian Chadd 
125276bd547bSAdrian Chadd /**************************************************************
125376bd547bSAdrian Chadd  * ar9300_channel_change
125476bd547bSAdrian Chadd  * Assumes caller wants to change channel, and not reset.
125576bd547bSAdrian Chadd  */
125676bd547bSAdrian Chadd static inline HAL_BOOL
ar9300_channel_change(struct ath_hal * ah,struct ieee80211_channel * chan,HAL_CHANNEL_INTERNAL * ichan,HAL_HT_MACMODE macmode)1257e113789bSAdrian Chadd ar9300_channel_change(struct ath_hal *ah, struct ieee80211_channel *chan,
125876bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode)
125976bd547bSAdrian Chadd {
126076bd547bSAdrian Chadd 
126176bd547bSAdrian Chadd     u_int32_t synth_delay, qnum;
126276bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
126376bd547bSAdrian Chadd 
126476bd547bSAdrian Chadd     /* TX must be stopped by now */
126576bd547bSAdrian Chadd     for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
126676bd547bSAdrian Chadd         if (ar9300_num_tx_pending(ah, qnum)) {
126776bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_QUEUE,
126876bd547bSAdrian Chadd                 "%s: Transmit frames pending on queue %d\n", __func__, qnum);
126976bd547bSAdrian Chadd             HALASSERT(0);
127076bd547bSAdrian Chadd             return AH_FALSE;
127176bd547bSAdrian Chadd         }
127276bd547bSAdrian Chadd     }
127376bd547bSAdrian Chadd 
127476bd547bSAdrian Chadd 
127576bd547bSAdrian Chadd     /*
127676bd547bSAdrian Chadd      * Kill last Baseband Rx Frame - Request analog bus grant
127776bd547bSAdrian Chadd      */
127876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
127976bd547bSAdrian Chadd     if (!ath_hal_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
1280e113789bSAdrian Chadd             AR_PHY_RFBUS_GRANT_EN))
128176bd547bSAdrian Chadd     {
1282e113789bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_PHYIO,
128376bd547bSAdrian Chadd             "%s: Could not kill baseband RX\n", __func__);
128476bd547bSAdrian Chadd         return AH_FALSE;
128576bd547bSAdrian Chadd     }
128676bd547bSAdrian Chadd 
128776bd547bSAdrian Chadd 
128876bd547bSAdrian Chadd     /* Setup 11n MAC/Phy mode registers */
128976bd547bSAdrian Chadd     ar9300_set_11n_regs(ah, chan, macmode);
129076bd547bSAdrian Chadd 
129176bd547bSAdrian Chadd     /*
129276bd547bSAdrian Chadd      * Change the synth
129376bd547bSAdrian Chadd      */
1294e113789bSAdrian Chadd     if (!ahp->ah_rf_hal.set_channel(ah, chan)) {
129576bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: failed to set channel\n", __func__);
129676bd547bSAdrian Chadd         return AH_FALSE;
129776bd547bSAdrian Chadd     }
129876bd547bSAdrian Chadd 
129976bd547bSAdrian Chadd     /*
130076bd547bSAdrian Chadd      * Some registers get reinitialized during ATH_INI_POST INI programming.
130176bd547bSAdrian Chadd      */
130276bd547bSAdrian Chadd     ar9300_init_user_settings(ah);
130376bd547bSAdrian Chadd 
130476bd547bSAdrian Chadd     /*
130576bd547bSAdrian Chadd      * Setup the transmit power values.
130676bd547bSAdrian Chadd      *
130776bd547bSAdrian Chadd      * After the public to private hal channel mapping, ichan contains the
130876bd547bSAdrian Chadd      * valid regulatory power value.
130976bd547bSAdrian Chadd      * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan.
131076bd547bSAdrian Chadd      */
131176bd547bSAdrian Chadd     if (ar9300_eeprom_set_transmit_power(
1312e113789bSAdrian Chadd          ah, &ahp->ah_eeprom, chan, ath_hal_getctl(ah, chan),
131376bd547bSAdrian Chadd          ath_hal_getantennaallowed(ah, chan),
131476bd547bSAdrian Chadd          ath_hal_get_twice_max_regpower(AH_PRIVATE(ah), ichan, chan),
1315e113789bSAdrian Chadd          AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit)) != HAL_OK)
131676bd547bSAdrian Chadd     {
131776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
131876bd547bSAdrian Chadd             "%s: error init'ing transmit power\n", __func__);
131976bd547bSAdrian Chadd         return AH_FALSE;
132076bd547bSAdrian Chadd     }
132176bd547bSAdrian Chadd 
132276bd547bSAdrian Chadd     /*
132376bd547bSAdrian Chadd      * Release the RFBus Grant.
132476bd547bSAdrian Chadd      */
132576bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
132676bd547bSAdrian Chadd 
132776bd547bSAdrian Chadd     /*
132876bd547bSAdrian Chadd      * Write spur immunity and delta slope for OFDM enabled modes (A, G, Turbo)
132976bd547bSAdrian Chadd      */
1330e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) {
1331e113789bSAdrian Chadd         ar9300_set_delta_slope(ah, chan);
133276bd547bSAdrian Chadd     } else {
133376bd547bSAdrian Chadd         /* Set to Ini default */
133476bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_TIMING3, 0x9c0a9f6b);
133576bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_SGI_DELTA, 0x00046384);
133676bd547bSAdrian Chadd     }
133776bd547bSAdrian Chadd 
133876bd547bSAdrian Chadd     ar9300_spur_mitigate(ah, chan);
133976bd547bSAdrian Chadd 
134076bd547bSAdrian Chadd 
134176bd547bSAdrian Chadd     /*
134276bd547bSAdrian Chadd      * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN).
134376bd547bSAdrian Chadd      * Read the phy active delay register. Value is in 100ns increments.
134476bd547bSAdrian Chadd      */
134576bd547bSAdrian Chadd     synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
1346e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_CCK(chan)) {
134776bd547bSAdrian Chadd         synth_delay = (4 * synth_delay) / 22;
134876bd547bSAdrian Chadd     } else {
134976bd547bSAdrian Chadd         synth_delay /= 10;
135076bd547bSAdrian Chadd     }
135176bd547bSAdrian Chadd 
135276bd547bSAdrian Chadd     OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY);
135376bd547bSAdrian Chadd 
135476bd547bSAdrian Chadd     /*
135576bd547bSAdrian Chadd      * Do calibration.
135676bd547bSAdrian Chadd      */
135776bd547bSAdrian Chadd 
135876bd547bSAdrian Chadd     return AH_TRUE;
135976bd547bSAdrian Chadd }
136076bd547bSAdrian Chadd 
136176bd547bSAdrian Chadd void
ar9300_set_operating_mode(struct ath_hal * ah,int opmode)136276bd547bSAdrian Chadd ar9300_set_operating_mode(struct ath_hal *ah, int opmode)
136376bd547bSAdrian Chadd {
136476bd547bSAdrian Chadd     u_int32_t val;
136576bd547bSAdrian Chadd 
136676bd547bSAdrian Chadd     val = OS_REG_READ(ah, AR_STA_ID1);
136776bd547bSAdrian Chadd     val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
136876bd547bSAdrian Chadd     switch (opmode) {
136976bd547bSAdrian Chadd     case HAL_M_HOSTAP:
137076bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_STA_ID1,
137176bd547bSAdrian Chadd             val | AR_STA_ID1_STA_AP | AR_STA_ID1_KSRCH_MODE);
137276bd547bSAdrian Chadd         OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
137376bd547bSAdrian Chadd         break;
137476bd547bSAdrian Chadd     case HAL_M_IBSS:
137576bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_STA_ID1,
137676bd547bSAdrian Chadd             val | AR_STA_ID1_ADHOC | AR_STA_ID1_KSRCH_MODE);
137776bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
137876bd547bSAdrian Chadd         break;
137976bd547bSAdrian Chadd     case HAL_M_STA:
138076bd547bSAdrian Chadd     case HAL_M_MONITOR:
138176bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
138276bd547bSAdrian Chadd         break;
138376bd547bSAdrian Chadd     }
138476bd547bSAdrian Chadd }
138576bd547bSAdrian Chadd 
138676bd547bSAdrian Chadd /* XXX need the logic for Osprey */
13876a101ebeSIan Lepore void
ar9300_init_pll(struct ath_hal * ah,struct ieee80211_channel * chan)1388e113789bSAdrian Chadd ar9300_init_pll(struct ath_hal *ah, struct ieee80211_channel *chan)
138976bd547bSAdrian Chadd {
139076bd547bSAdrian Chadd     u_int32_t pll;
139176bd547bSAdrian Chadd     u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz;
1392e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = NULL;
1393e113789bSAdrian Chadd 
1394e113789bSAdrian Chadd     if (chan)
1395e113789bSAdrian Chadd         ichan = ath_hal_checkchannel(ah, chan);
139676bd547bSAdrian Chadd 
139776bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah)) {
139876bd547bSAdrian Chadd         if (clk_25mhz) {
139976bd547bSAdrian Chadd             /* Hornet uses PLL_CONTROL_2. Xtal is 25MHz for Hornet.
140076bd547bSAdrian Chadd              * REFDIV set to 0x1.
140176bd547bSAdrian Chadd              * $xtal_freq = 25;
140276bd547bSAdrian Chadd              * $PLL2_div = (704/$xtal_freq); # 176 * 4 = 704.
140376bd547bSAdrian Chadd              * MAC and BB run at 176 MHz.
140476bd547bSAdrian Chadd              * $PLL2_divint = int($PLL2_div);
140576bd547bSAdrian Chadd              * $PLL2_divfrac = $PLL2_div - $PLL2_divint;
140676bd547bSAdrian Chadd              * $PLL2_divfrac = int($PLL2_divfrac * 0x4000); # 2^14
140776bd547bSAdrian Chadd              * $PLL2_Val = ($PLL2_divint & 0x3f) << 19 | (0x1) << 14 |
140876bd547bSAdrian Chadd              *     $PLL2_divfrac & 0x3fff;
140976bd547bSAdrian Chadd              * Therefore, $PLL2_Val = 0xe04a3d
141076bd547bSAdrian Chadd              */
141176bd547bSAdrian Chadd #define DPLL2_KD_VAL            0x1D
141276bd547bSAdrian Chadd #define DPLL2_KI_VAL            0x06
141376bd547bSAdrian Chadd #define DPLL3_PHASE_SHIFT_VAL   0x1
141476bd547bSAdrian Chadd 
141576bd547bSAdrian Chadd             /* Rewrite DDR PLL2 and PLL3 */
141676bd547bSAdrian Chadd             /* program DDR PLL ki and kd value, ki=0x6, kd=0x1d */
141776bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x18e82f01);
141876bd547bSAdrian Chadd 
141976bd547bSAdrian Chadd             /* program DDR PLL phase_shift to 0x1 */
142076bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3,
142176bd547bSAdrian Chadd                 AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
142276bd547bSAdrian Chadd 
142376bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
142476bd547bSAdrian Chadd             OS_DELAY(1000);
142576bd547bSAdrian Chadd 
142676bd547bSAdrian Chadd             /* program refdiv, nint, frac to RTC register */
142776bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0xe04a3d);
142876bd547bSAdrian Chadd 
142976bd547bSAdrian Chadd             /* program BB PLL ki and kd value, ki=0x6, kd=0x1d */
143076bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
143176bd547bSAdrian Chadd                 AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL);
143276bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
143376bd547bSAdrian Chadd                 AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL);
143476bd547bSAdrian Chadd 
143576bd547bSAdrian Chadd             /* program BB PLL phase_shift to 0x1 */
143676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3,
143776bd547bSAdrian Chadd                 AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
143876bd547bSAdrian Chadd         } else { /* 40MHz */
143976bd547bSAdrian Chadd #undef  DPLL2_KD_VAL
144076bd547bSAdrian Chadd #undef  DPLL2_KI_VAL
144176bd547bSAdrian Chadd #define DPLL2_KD_VAL            0x3D
144276bd547bSAdrian Chadd #define DPLL2_KI_VAL            0x06
144376bd547bSAdrian Chadd             /* Rewrite DDR PLL2 and PLL3 */
144476bd547bSAdrian Chadd             /* program DDR PLL ki and kd value, ki=0x6, kd=0x3d */
144576bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x19e82f01);
144676bd547bSAdrian Chadd 
144776bd547bSAdrian Chadd             /* program DDR PLL phase_shift to 0x1 */
144876bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3,
144976bd547bSAdrian Chadd                 AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
145076bd547bSAdrian Chadd 
145176bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
145276bd547bSAdrian Chadd             OS_DELAY(1000);
145376bd547bSAdrian Chadd 
145476bd547bSAdrian Chadd             /* program refdiv, nint, frac to RTC register */
145576bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
145676bd547bSAdrian Chadd 
145776bd547bSAdrian Chadd             /* program BB PLL ki and kd value, ki=0x6, kd=0x3d */
145876bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
145976bd547bSAdrian Chadd                 AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL);
146076bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
146176bd547bSAdrian Chadd                 AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL);
146276bd547bSAdrian Chadd 
146376bd547bSAdrian Chadd             /* program BB PLL phase_shift to 0x1 */
146476bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3,
146576bd547bSAdrian Chadd                 AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
146676bd547bSAdrian Chadd         }
146776bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
146876bd547bSAdrian Chadd         OS_DELAY(1000);
146976bd547bSAdrian Chadd     } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
147076bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_PLL_PWD, 0x1);
147176bd547bSAdrian Chadd 
147276bd547bSAdrian Chadd         /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
147376bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
147476bd547bSAdrian Chadd             AR_PHY_BB_DPLL2_KD, 0x40);
147576bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
147676bd547bSAdrian Chadd             AR_PHY_BB_DPLL2_KI, 0x4);
147776bd547bSAdrian Chadd 
147876bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1,
147976bd547bSAdrian Chadd             AR_PHY_BB_DPLL1_REFDIV, 0x5);
148076bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1,
148176bd547bSAdrian Chadd             AR_PHY_BB_DPLL1_NINI, 0x58);
148276bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1,
148376bd547bSAdrian Chadd             AR_PHY_BB_DPLL1_NFRAC, 0x0);
148476bd547bSAdrian Chadd 
148576bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
148676bd547bSAdrian Chadd             AR_PHY_BB_DPLL2_OUTDIV, 0x1);
148776bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
148876bd547bSAdrian Chadd             AR_PHY_BB_DPLL2_LOCAL_PLL, 0x1);
148976bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
149076bd547bSAdrian Chadd             AR_PHY_BB_DPLL2_EN_NEGTRIG, 0x1);
149176bd547bSAdrian Chadd 
149276bd547bSAdrian Chadd         /* program BB PLL phase_shift to 0x6 */
149376bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3,
149476bd547bSAdrian Chadd             AR_PHY_BB_DPLL3_PHASE_SHIFT, 0x6);
149576bd547bSAdrian Chadd 
149676bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,
149776bd547bSAdrian Chadd             AR_PHY_BB_DPLL2_PLL_PWD, 0x0);
149876bd547bSAdrian Chadd         OS_DELAY(1000);
149976bd547bSAdrian Chadd 
150076bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
150176bd547bSAdrian Chadd         OS_DELAY(1000);
150227e2ad46SAdrian Chadd     } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
150376bd547bSAdrian Chadd #define SRIF_PLL 1
150476bd547bSAdrian Chadd         u_int32_t regdata, pll2_divint, pll2_divfrac;
150576bd547bSAdrian Chadd 
150676bd547bSAdrian Chadd #ifndef SRIF_PLL
150776bd547bSAdrian Chadd 	u_int32_t pll2_clkmode;
150876bd547bSAdrian Chadd #endif
150976bd547bSAdrian Chadd 
151076bd547bSAdrian Chadd #ifdef SRIF_PLL
151176bd547bSAdrian Chadd         u_int32_t refdiv;
151276bd547bSAdrian Chadd #endif
151376bd547bSAdrian Chadd         if (clk_25mhz) {
151476bd547bSAdrian Chadd #ifndef SRIF_PLL
151576bd547bSAdrian Chadd             pll2_divint = 0x1c;
151676bd547bSAdrian Chadd             pll2_divfrac = 0xa3d7;
151776bd547bSAdrian Chadd #else
151827e2ad46SAdrian Chadd             if (AR_SREV_HONEYBEE(ah)) {
151927e2ad46SAdrian Chadd                 pll2_divint = 0x1c;
152027e2ad46SAdrian Chadd                 pll2_divfrac = 0xa3d2;
152127e2ad46SAdrian Chadd                 refdiv = 1;
152227e2ad46SAdrian Chadd             } else {
152376bd547bSAdrian Chadd                 pll2_divint = 0x54;
152476bd547bSAdrian Chadd                 pll2_divfrac = 0x1eb85;
152576bd547bSAdrian Chadd                 refdiv = 3;
152627e2ad46SAdrian Chadd             }
152776bd547bSAdrian Chadd #endif
152876bd547bSAdrian Chadd         } else {
152976bd547bSAdrian Chadd #ifndef SRIF_PLL
153076bd547bSAdrian Chadd             pll2_divint = 0x11;
153176bd547bSAdrian Chadd             pll2_divfrac = 0x26666;
153276bd547bSAdrian Chadd #else
153376bd547bSAdrian Chadd             if (AR_SREV_WASP(ah)) {
153476bd547bSAdrian Chadd                 pll2_divint = 88;
153576bd547bSAdrian Chadd                 pll2_divfrac = 0;
153676bd547bSAdrian Chadd                 refdiv = 5;
153776bd547bSAdrian Chadd             } else {
153876bd547bSAdrian Chadd                 pll2_divint = 0x11;
153976bd547bSAdrian Chadd                 pll2_divfrac = 0x26666;
154076bd547bSAdrian Chadd                 refdiv = 1;
154176bd547bSAdrian Chadd             }
154276bd547bSAdrian Chadd #endif
154376bd547bSAdrian Chadd         }
154476bd547bSAdrian Chadd #ifndef SRIF_PLL
154576bd547bSAdrian Chadd         pll2_clkmode = 0x3d;
154676bd547bSAdrian Chadd #endif
154776bd547bSAdrian Chadd         /* PLL programming through SRIF Local Mode */
154876bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); /* Bypass mode */
154976bd547bSAdrian Chadd         OS_DELAY(1000);
155076bd547bSAdrian Chadd         do {
155176bd547bSAdrian Chadd             regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);
155227e2ad46SAdrian Chadd             if (AR_SREV_HONEYBEE(ah)) {
155327e2ad46SAdrian Chadd                 regdata = regdata | (0x1 << 22);
155427e2ad46SAdrian Chadd             } else {
155576bd547bSAdrian Chadd                 regdata = regdata | (0x1 << 16);
155627e2ad46SAdrian Chadd             }
155776bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 1 */
155876bd547bSAdrian Chadd             OS_DELAY(100);
155976bd547bSAdrian Chadd             /* override int, frac, refdiv */
156076bd547bSAdrian Chadd #ifndef SRIF_PLL
156176bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL,
156276bd547bSAdrian Chadd                 ((1 << 27) | (pll2_divint << 18) | pll2_divfrac));
156376bd547bSAdrian Chadd #else
156476bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL,
156576bd547bSAdrian Chadd                 ((refdiv << 27) | (pll2_divint << 18) | pll2_divfrac));
156676bd547bSAdrian Chadd #endif
156776bd547bSAdrian Chadd             OS_DELAY(100);
156876bd547bSAdrian Chadd             regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);
156976bd547bSAdrian Chadd #ifndef SRIF_PLL
157076bd547bSAdrian Chadd             regdata = (regdata & 0x80071fff) |
157176bd547bSAdrian Chadd                 (0x1 << 30) | (0x1 << 13) | (0x6 << 26) | (pll2_clkmode << 19);
157276bd547bSAdrian Chadd #else
157376bd547bSAdrian Chadd             if (AR_SREV_WASP(ah)) {
157476bd547bSAdrian Chadd                 regdata = (regdata & 0x80071fff) |
157576bd547bSAdrian Chadd                     (0x1 << 30) | (0x1 << 13) | (0x4 << 26) | (0x18 << 19);
157627e2ad46SAdrian Chadd             } else if (AR_SREV_HONEYBEE(ah)) {
157727e2ad46SAdrian Chadd                 /*
157827e2ad46SAdrian Chadd                  * Kd=10, Ki=2, Outdiv=1, Local PLL=0, Phase Shift=4
157927e2ad46SAdrian Chadd                  */
158027e2ad46SAdrian Chadd                 regdata = (regdata & 0x01c00fff) |
158127e2ad46SAdrian Chadd                     (0x1 << 31) | (0x2 << 29) | (0xa << 25) | (0x1 << 19) | (0x6 << 12);
158276bd547bSAdrian Chadd             } else {
158376bd547bSAdrian Chadd                 regdata = (regdata & 0x80071fff) |
158476bd547bSAdrian Chadd                     (0x3 << 30) | (0x1 << 13) | (0x4 << 26) | (0x60 << 19);
158576bd547bSAdrian Chadd             }
158676bd547bSAdrian Chadd #endif
158776bd547bSAdrian Chadd             /* Ki, Kd, Local PLL, Outdiv */
158876bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata);
158976bd547bSAdrian Chadd             regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);
159027e2ad46SAdrian Chadd             if (AR_SREV_HONEYBEE(ah)) {
159127e2ad46SAdrian Chadd                 regdata = (regdata & 0xffbfffff);
159227e2ad46SAdrian Chadd             } else {
159376bd547bSAdrian Chadd                 regdata = (regdata & 0xfffeffff);
159427e2ad46SAdrian Chadd             }
159576bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 0 */
159676bd547bSAdrian Chadd             OS_DELAY(1000);
159776bd547bSAdrian Chadd             if (AR_SREV_WASP(ah)) {
159876bd547bSAdrian Chadd                 /* clear do measure */
159976bd547bSAdrian Chadd                 regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);
160076bd547bSAdrian Chadd                 regdata &= ~(1 << 30);
160176bd547bSAdrian Chadd                 OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);
160276bd547bSAdrian Chadd                 OS_DELAY(100);
160376bd547bSAdrian Chadd 
160476bd547bSAdrian Chadd                 /* set do measure */
160576bd547bSAdrian Chadd                 regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);
160676bd547bSAdrian Chadd                 regdata |= (1 << 30);
160776bd547bSAdrian Chadd                 OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);
160876bd547bSAdrian Chadd 
160976bd547bSAdrian Chadd                 /* wait for measure done */
161076bd547bSAdrian Chadd                 do {
161176bd547bSAdrian Chadd                     regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL4);
161276bd547bSAdrian Chadd                 } while ((regdata & (1 << 3)) == 0);
161376bd547bSAdrian Chadd 
161476bd547bSAdrian Chadd                 /* clear do measure */
161576bd547bSAdrian Chadd                 regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);
161676bd547bSAdrian Chadd                 regdata &= ~(1 << 30);
161776bd547bSAdrian Chadd                 OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);
161876bd547bSAdrian Chadd 
161976bd547bSAdrian Chadd                 /* get measure sqsum dvc */
162076bd547bSAdrian Chadd                 regdata = (OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3) & 0x007FFFF8) >> 3;
162176bd547bSAdrian Chadd             } else {
162276bd547bSAdrian Chadd                 break;
162376bd547bSAdrian Chadd             }
162476bd547bSAdrian Chadd         } while (regdata >= 0x40000);
162576bd547bSAdrian Chadd 
162676bd547bSAdrian Chadd         /* Remove from Bypass mode */
162776bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
162876bd547bSAdrian Chadd         OS_DELAY(1000);
162976bd547bSAdrian Chadd     } else {
163076bd547bSAdrian Chadd         pll = SM(0x5, AR_RTC_PLL_REFDIV);
163176bd547bSAdrian Chadd 
163276bd547bSAdrian Chadd         /* Supposedly not needed on Osprey */
163376bd547bSAdrian Chadd #if 0
163476bd547bSAdrian Chadd         if (chan && IS_CHAN_HALF_RATE(chan)) {
163576bd547bSAdrian Chadd             pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
163676bd547bSAdrian Chadd         } else if (chan && IS_CHAN_QUARTER_RATE(chan)) {
163776bd547bSAdrian Chadd             pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
163876bd547bSAdrian Chadd         }
163976bd547bSAdrian Chadd #endif
1640e113789bSAdrian Chadd         if (ichan && IS_CHAN_5GHZ(ichan)) {
164176bd547bSAdrian Chadd             pll |= SM(0x28, AR_RTC_PLL_DIV);
164276bd547bSAdrian Chadd             /*
164376bd547bSAdrian Chadd              * When doing fast clock, set PLL to 0x142c
164476bd547bSAdrian Chadd              */
164576bd547bSAdrian Chadd             if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {
164676bd547bSAdrian Chadd                 pll = 0x142c;
164776bd547bSAdrian Chadd             }
164876bd547bSAdrian Chadd         } else {
164976bd547bSAdrian Chadd             pll |= SM(0x2c, AR_RTC_PLL_DIV);
165076bd547bSAdrian Chadd         }
165176bd547bSAdrian Chadd 
165276bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
165376bd547bSAdrian Chadd     }
165476bd547bSAdrian Chadd 
165576bd547bSAdrian Chadd     /* TODO:
165676bd547bSAdrian Chadd      * For multi-band owl, switch between bands by reiniting the PLL.
165776bd547bSAdrian Chadd      */
165876bd547bSAdrian Chadd     OS_DELAY(RTC_PLL_SETTLE_DELAY);
165976bd547bSAdrian Chadd 
166076bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK,
166176bd547bSAdrian Chadd         AR_RTC_FORCE_DERIVED_CLK | AR_RTC_PCIE_RST_PWDN_EN);
166276bd547bSAdrian Chadd 
166327e2ad46SAdrian Chadd     /* XXX TODO: honeybee? */
166476bd547bSAdrian Chadd     if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {
166576bd547bSAdrian Chadd         if (clk_25mhz) {
166676bd547bSAdrian Chadd             OS_REG_WRITE(ah,
166776bd547bSAdrian Chadd                 AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); /* 32KHz sleep clk */
166876bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
166976bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);
167076bd547bSAdrian Chadd         } else {
167176bd547bSAdrian Chadd             OS_REG_WRITE(ah,
167276bd547bSAdrian Chadd                 AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); /* 32KHz sleep clk */
167376bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
167476bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);
167576bd547bSAdrian Chadd         }
167676bd547bSAdrian Chadd         OS_DELAY(100);
167776bd547bSAdrian Chadd     }
167876bd547bSAdrian Chadd }
167976bd547bSAdrian Chadd 
168076bd547bSAdrian Chadd static inline HAL_BOOL
ar9300_set_reset(struct ath_hal * ah,int type)168176bd547bSAdrian Chadd ar9300_set_reset(struct ath_hal *ah, int type)
168276bd547bSAdrian Chadd {
168376bd547bSAdrian Chadd     u_int32_t rst_flags;
168476bd547bSAdrian Chadd     u_int32_t tmp_reg;
1685899d1cacSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
168676bd547bSAdrian Chadd 
168776bd547bSAdrian Chadd     HALASSERT(type == HAL_RESET_WARM || type == HAL_RESET_COLD);
168876bd547bSAdrian Chadd 
168976bd547bSAdrian Chadd     /*
169076bd547bSAdrian Chadd      * RTC Force wake should be done before resetting the MAC.
169176bd547bSAdrian Chadd      * MDK/ART does it that way.
169276bd547bSAdrian Chadd      */
169376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);
169476bd547bSAdrian Chadd     OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */
169576bd547bSAdrian Chadd     OS_REG_WRITE(ah,
169676bd547bSAdrian Chadd         AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
169776bd547bSAdrian Chadd 
169876bd547bSAdrian Chadd     /* Reset AHB */
169976bd547bSAdrian Chadd     /* Bug26871 */
170076bd547bSAdrian Chadd     tmp_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE));
170176bd547bSAdrian Chadd     if (AR_SREV_WASP(ah)) {
170276bd547bSAdrian Chadd         if (tmp_reg & (AR9340_INTR_SYNC_LOCAL_TIMEOUT)) {
170376bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0);
170476bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF);
170576bd547bSAdrian Chadd         }
170676bd547bSAdrian Chadd     } else {
170776bd547bSAdrian Chadd         if (tmp_reg & (AR9300_INTR_SYNC_LOCAL_TIMEOUT | AR9300_INTR_SYNC_RADM_CPL_TIMEOUT)) {
170876bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0);
170976bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF);
171076bd547bSAdrian Chadd         }
171176bd547bSAdrian Chadd         else {
171276bd547bSAdrian Chadd             /* NO AR_RC_AHB in Osprey */
171376bd547bSAdrian Chadd             /*OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_AHB);*/
171476bd547bSAdrian Chadd         }
171576bd547bSAdrian Chadd     }
171676bd547bSAdrian Chadd 
171776bd547bSAdrian Chadd     rst_flags = AR_RTC_RC_MAC_WARM;
171876bd547bSAdrian Chadd     if (type == HAL_RESET_COLD) {
171976bd547bSAdrian Chadd         rst_flags |= AR_RTC_RC_MAC_COLD;
172076bd547bSAdrian Chadd     }
172176bd547bSAdrian Chadd 
172276bd547bSAdrian Chadd #ifdef AH_SUPPORT_HORNET
172376bd547bSAdrian Chadd     /* Hornet WAR: trigger SoC to reset WMAC if ...
172476bd547bSAdrian Chadd      * (1) doing cold reset. Ref: EV 69254
172576bd547bSAdrian Chadd      * (2) beacon pending. Ref: EV 70983
172676bd547bSAdrian Chadd      */
172776bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) &&
172876bd547bSAdrian Chadd         (ar9300_num_tx_pending(
1729e113789bSAdrian Chadd             ah, AH_PRIVATE(ah)->ah_caps.halTotalQueues - 1) != 0 ||
173076bd547bSAdrian Chadd          type == HAL_RESET_COLD))
173176bd547bSAdrian Chadd     {
173276bd547bSAdrian Chadd         u_int32_t time_out;
173376bd547bSAdrian Chadd #define AR_SOC_RST_RESET         0xB806001C
173476bd547bSAdrian Chadd #define AR_SOC_BOOT_STRAP        0xB80600AC
173576bd547bSAdrian Chadd #define AR_SOC_WLAN_RST          0x00000800 /* WLAN reset */
173676bd547bSAdrian Chadd #define REG_WRITE(_reg, _val)    *((volatile u_int32_t *)(_reg)) = (_val);
173776bd547bSAdrian Chadd #define REG_READ(_reg)           *((volatile u_int32_t *)(_reg))
173876bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Hornet SoC reset WMAC.\n", __func__);
173976bd547bSAdrian Chadd 
174076bd547bSAdrian Chadd         REG_WRITE(AR_SOC_RST_RESET,
174176bd547bSAdrian Chadd             REG_READ(AR_SOC_RST_RESET) | AR_SOC_WLAN_RST);
174276bd547bSAdrian Chadd         REG_WRITE(AR_SOC_RST_RESET,
174376bd547bSAdrian Chadd             REG_READ(AR_SOC_RST_RESET) & (~AR_SOC_WLAN_RST));
174476bd547bSAdrian Chadd 
174576bd547bSAdrian Chadd         time_out = 0;
174676bd547bSAdrian Chadd 
174776bd547bSAdrian Chadd         while (1) {
174876bd547bSAdrian Chadd             tmp_reg = REG_READ(AR_SOC_BOOT_STRAP);
174976bd547bSAdrian Chadd             if ((tmp_reg & 0x10) == 0) {
175076bd547bSAdrian Chadd                 break;
175176bd547bSAdrian Chadd             }
175276bd547bSAdrian Chadd             if (time_out > 20) {
175376bd547bSAdrian Chadd                 break;
175476bd547bSAdrian Chadd             }
175576bd547bSAdrian Chadd             OS_DELAY(10000);
175676bd547bSAdrian Chadd             time_out++;
175776bd547bSAdrian Chadd         }
175876bd547bSAdrian Chadd 
175976bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_RESET, 1);
176076bd547bSAdrian Chadd #undef REG_READ
176176bd547bSAdrian Chadd #undef REG_WRITE
176276bd547bSAdrian Chadd #undef AR_SOC_WLAN_RST
176376bd547bSAdrian Chadd #undef AR_SOC_RST_RESET
176476bd547bSAdrian Chadd #undef AR_SOC_BOOT_STRAP
176576bd547bSAdrian Chadd     }
176676bd547bSAdrian Chadd #endif /* AH_SUPPORT_HORNET */
176776bd547bSAdrian Chadd 
176876bd547bSAdrian Chadd #ifdef AH_SUPPORT_SCORPION
176976bd547bSAdrian Chadd     if (AR_SREV_SCORPION(ah)) {
177076bd547bSAdrian Chadd #define DDR_CTL_CONFIG_ADDRESS                                       0xb8000000
177176bd547bSAdrian Chadd #define DDR_CTL_CONFIG_OFFSET                                        0x0108
177276bd547bSAdrian Chadd #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MSB                           29
177376bd547bSAdrian Chadd #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB                           21
177476bd547bSAdrian Chadd #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK                          0x3fe00000
177576bd547bSAdrian Chadd #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(x)                        (((x) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) >> DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB)
177676bd547bSAdrian Chadd #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_SET(x)                        (((x) << DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK)
177776bd547bSAdrian Chadd #define MAC_DMA_CFG_ADDRESS                                          0xb8100000
177876bd547bSAdrian Chadd #define MAC_DMA_CFG_OFFSET                                           0x0014
177976bd547bSAdrian Chadd 
178076bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_REQ_MSB                                     11
178176bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_REQ_LSB                                     11
178276bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_REQ_MASK                                    0x00000800
178376bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_REQ_GET(x)                                  (((x) & MAC_DMA_CFG_HALT_REQ_MASK) >> MAC_DMA_CFG_HALT_REQ_LSB)
178476bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_REQ_SET(x)                                  (((x) << MAC_DMA_CFG_HALT_REQ_LSB) & MAC_DMA_CFG_HALT_REQ_MASK)
178576bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_ACK_MSB                                     12
178676bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_ACK_LSB                                     12
178776bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_ACK_MASK                                    0x00001000
178876bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_ACK_GET(x)                                  (((x) & MAC_DMA_CFG_HALT_ACK_MASK) >> MAC_DMA_CFG_HALT_ACK_LSB)
178976bd547bSAdrian Chadd #define MAC_DMA_CFG_HALT_ACK_SET(x)                                  (((x) << MAC_DMA_CFG_HALT_ACK_LSB) & MAC_DMA_CFG_HALT_ACK_MASK)
179076bd547bSAdrian Chadd 
179176bd547bSAdrian Chadd #define RST_RESET                                                    0xB806001c
179276bd547bSAdrian Chadd #define RTC_RESET                                                    (1<<27)
179376bd547bSAdrian Chadd 
179476bd547bSAdrian Chadd #define REG_READ(_reg)          *((volatile u_int32_t *)(_reg))
179576bd547bSAdrian Chadd #define REG_WRITE(_reg, _val)   *((volatile u_int32_t *)(_reg)) = (_val);
179676bd547bSAdrian Chadd 
179776bd547bSAdrian Chadd #define DDR_REG_READ(_ah, _reg) \
179876bd547bSAdrian Chadd 	    *((volatile u_int32_t *)( DDR_CTL_CONFIG_ADDRESS + (_reg)))
179976bd547bSAdrian Chadd #define DDR_REG_WRITE(_ah, _reg, _val) \
180076bd547bSAdrian Chadd 	    *((volatile u_int32_t *)(DDR_CTL_CONFIG_ADDRESS + (_reg))) = (_val)
180176bd547bSAdrian Chadd 
180276bd547bSAdrian Chadd 	    OS_REG_WRITE(ah,MAC_DMA_CFG_OFFSET, (OS_REG_READ(ah,MAC_DMA_CFG_OFFSET) & ~MAC_DMA_CFG_HALT_REQ_MASK) |
180376bd547bSAdrian Chadd 			    MAC_DMA_CFG_HALT_REQ_SET(1));
180476bd547bSAdrian Chadd 
180576bd547bSAdrian Chadd 	    {
180676bd547bSAdrian Chadd 		    int count;
180776bd547bSAdrian Chadd             u_int32_t data;
180876bd547bSAdrian Chadd 
180976bd547bSAdrian Chadd 		    count = 0;
181076bd547bSAdrian Chadd 		    while (!MAC_DMA_CFG_HALT_ACK_GET(OS_REG_READ(ah, MAC_DMA_CFG_OFFSET) ))
181176bd547bSAdrian Chadd 		    {
181276bd547bSAdrian Chadd 			    count++;
181376bd547bSAdrian Chadd 			    if (count > 10) {
181476bd547bSAdrian Chadd 				    ath_hal_printf(ah, "Halt ACK timeout\n");
181576bd547bSAdrian Chadd 				    break;
181676bd547bSAdrian Chadd 			    }
181776bd547bSAdrian Chadd 			    OS_DELAY(10);
181876bd547bSAdrian Chadd 		    }
181976bd547bSAdrian Chadd 
182076bd547bSAdrian Chadd 		    data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET);
18213e307100SAdrian Chadd 		    HALDEBUG(ah, HAL_DEBUG_RESET, "check DDR Activity - HIGH\n");
182276bd547bSAdrian Chadd 
182376bd547bSAdrian Chadd 		    count = 0;
182476bd547bSAdrian Chadd 		    while (DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(data)) {
182576bd547bSAdrian Chadd 			    //      AVE_DEBUG(0,"DDR Activity - HIGH\n");
18263e307100SAdrian Chadd 			    HALDEBUG(ah, HAL_DEBUG_RESET, "DDR Activity - HIGH\n");
182776bd547bSAdrian Chadd 			    count++;
182876bd547bSAdrian Chadd 			    OS_DELAY(10);
182976bd547bSAdrian Chadd 			    data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET);
183076bd547bSAdrian Chadd 			    if (count > 10) {
183176bd547bSAdrian Chadd 				    ath_hal_printf(ah, "DDR Activity timeout\n");
183276bd547bSAdrian Chadd 				    break;
183376bd547bSAdrian Chadd 			    }
183476bd547bSAdrian Chadd 		    }
183576bd547bSAdrian Chadd 	    }
183676bd547bSAdrian Chadd 
183776bd547bSAdrian Chadd 
183876bd547bSAdrian Chadd 	    {
183976bd547bSAdrian Chadd 		    //Force RTC reset
184076bd547bSAdrian Chadd 		    REG_WRITE(RST_RESET, (REG_READ(RST_RESET) | RTC_RESET));
184176bd547bSAdrian Chadd 		    OS_DELAY(10);
184276bd547bSAdrian Chadd 		    REG_WRITE(RST_RESET, (REG_READ(RST_RESET) & ~RTC_RESET));
184376bd547bSAdrian Chadd 		    OS_DELAY(10);
184476bd547bSAdrian Chadd 		    OS_REG_WRITE(ah, AR_RTC_RESET, 0);
184576bd547bSAdrian Chadd 		    OS_DELAY(10);
184676bd547bSAdrian Chadd 		    OS_REG_WRITE(ah, AR_RTC_RESET, 1);
184776bd547bSAdrian Chadd 		    OS_DELAY(10);
18483e307100SAdrian Chadd 		    HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Scorpion SoC RTC reset done.\n", __func__);
184976bd547bSAdrian Chadd 	    }
185076bd547bSAdrian Chadd #undef REG_READ
185176bd547bSAdrian Chadd #undef REG_WRITE
185276bd547bSAdrian Chadd     }
185376bd547bSAdrian Chadd #endif  /* AH_SUPPORT_SCORPION */
185476bd547bSAdrian Chadd 
185576bd547bSAdrian Chadd     /*
185676bd547bSAdrian Chadd      * Set Mac(BB,Phy) Warm Reset
185776bd547bSAdrian Chadd      */
185876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RTC_RC, rst_flags);
185976bd547bSAdrian Chadd 
186076bd547bSAdrian Chadd     OS_DELAY(50); /* XXX 50 usec */
186176bd547bSAdrian Chadd 
186276bd547bSAdrian Chadd     /*
186376bd547bSAdrian Chadd      * Clear resets and force wakeup
186476bd547bSAdrian Chadd      */
186576bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RTC_RC, 0);
1866e113789bSAdrian Chadd     if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) {
186776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
186876bd547bSAdrian Chadd             "%s: RTC stuck in MAC reset\n", __FUNCTION__);
186976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
187076bd547bSAdrian Chadd             "%s: AR_RTC_RC = 0x%x\n", __func__, OS_REG_READ(ah, AR_RTC_RC));
187176bd547bSAdrian Chadd         return AH_FALSE;
187276bd547bSAdrian Chadd     }
187376bd547bSAdrian Chadd 
187476bd547bSAdrian Chadd     /* Clear AHB reset */
187576bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0);
1876f0949f0cSAdrian Chadd     ar9300_disable_pll_lock_detect(ah);
187776bd547bSAdrian Chadd 
187876bd547bSAdrian Chadd     ar9300_attach_hw_platform(ah);
187976bd547bSAdrian Chadd 
1880899d1cacSAdrian Chadd     ahp->ah_chip_reset_done = 1;
188176bd547bSAdrian Chadd     return AH_TRUE;
188276bd547bSAdrian Chadd }
188376bd547bSAdrian Chadd 
188476bd547bSAdrian Chadd static inline HAL_BOOL
ar9300_set_reset_power_on(struct ath_hal * ah)188576bd547bSAdrian Chadd ar9300_set_reset_power_on(struct ath_hal *ah)
188676bd547bSAdrian Chadd {
188776bd547bSAdrian Chadd     /* Force wake */
188876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);
188976bd547bSAdrian Chadd     OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */
189076bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,
189176bd547bSAdrian Chadd         AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
189276bd547bSAdrian Chadd     /*
189376bd547bSAdrian Chadd      * RTC reset and clear. Some delay in between is needed
189476bd547bSAdrian Chadd      * to give the chip time to settle.
189576bd547bSAdrian Chadd      */
189676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RTC_RESET, 0);
189776bd547bSAdrian Chadd     OS_DELAY(2);
189876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RTC_RESET, 1);
189976bd547bSAdrian Chadd 
190076bd547bSAdrian Chadd     /*
190176bd547bSAdrian Chadd      * Poll till RTC is ON
190276bd547bSAdrian Chadd      */
190376bd547bSAdrian Chadd     if (!ath_hal_wait(ah,
190476bd547bSAdrian Chadd              AR_RTC_STATUS, AR_RTC_STATUS_M,
1905e113789bSAdrian Chadd              AR_RTC_STATUS_ON))
190676bd547bSAdrian Chadd     {
190776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
1908e113789bSAdrian Chadd             "%s: RTC not waking up for %d\n", __FUNCTION__, 1000);
190976bd547bSAdrian Chadd         return AH_FALSE;
191076bd547bSAdrian Chadd     }
191176bd547bSAdrian Chadd 
191276bd547bSAdrian Chadd     /*
191376bd547bSAdrian Chadd      * Read Revisions from Chip right after RTC is on for the first time.
191476bd547bSAdrian Chadd      * This helps us detect the chip type early and initialize it accordingly.
191576bd547bSAdrian Chadd      */
191676bd547bSAdrian Chadd     ar9300_read_revisions(ah);
191776bd547bSAdrian Chadd 
191876bd547bSAdrian Chadd     /*
191976bd547bSAdrian Chadd      * Warm reset if we aren't really powering on,
192076bd547bSAdrian Chadd      * just restarting the driver.
192176bd547bSAdrian Chadd      */
192276bd547bSAdrian Chadd     return ar9300_set_reset(ah, HAL_RESET_WARM);
192376bd547bSAdrian Chadd }
192476bd547bSAdrian Chadd 
192576bd547bSAdrian Chadd /*
192676bd547bSAdrian Chadd  * Write the given reset bit mask into the reset register
192776bd547bSAdrian Chadd  */
192876bd547bSAdrian Chadd HAL_BOOL
ar9300_set_reset_reg(struct ath_hal * ah,u_int32_t type)192976bd547bSAdrian Chadd ar9300_set_reset_reg(struct ath_hal *ah, u_int32_t type)
193076bd547bSAdrian Chadd {
193176bd547bSAdrian Chadd     HAL_BOOL ret = AH_FALSE;
193276bd547bSAdrian Chadd 
193376bd547bSAdrian Chadd     /*
193476bd547bSAdrian Chadd      * Set force wake
193576bd547bSAdrian Chadd      */
193676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);
193776bd547bSAdrian Chadd     OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */
193876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,
193976bd547bSAdrian Chadd         AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
194076bd547bSAdrian Chadd 
194176bd547bSAdrian Chadd     switch (type) {
194276bd547bSAdrian Chadd     case HAL_RESET_POWER_ON:
194376bd547bSAdrian Chadd         ret = ar9300_set_reset_power_on(ah);
194476bd547bSAdrian Chadd         break;
194576bd547bSAdrian Chadd     case HAL_RESET_WARM:
194676bd547bSAdrian Chadd     case HAL_RESET_COLD:
194776bd547bSAdrian Chadd         ret = ar9300_set_reset(ah, type);
194876bd547bSAdrian Chadd         break;
194976bd547bSAdrian Chadd     default:
195076bd547bSAdrian Chadd         break;
195176bd547bSAdrian Chadd     }
195276bd547bSAdrian Chadd 
195376bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
1954e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {
195576bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
195676bd547bSAdrian Chadd     }
195776bd547bSAdrian Chadd #endif
195876bd547bSAdrian Chadd 
195976bd547bSAdrian Chadd     return ret;
196076bd547bSAdrian Chadd }
196176bd547bSAdrian Chadd 
196276bd547bSAdrian Chadd /*
196376bd547bSAdrian Chadd  * Places the PHY and Radio chips into reset.  A full reset
196476bd547bSAdrian Chadd  * must be called to leave this state.  The PCI/MAC/PCU are
196576bd547bSAdrian Chadd  * not placed into reset as we must receive interrupt to
196676bd547bSAdrian Chadd  * re-enable the hardware.
196776bd547bSAdrian Chadd  */
196876bd547bSAdrian Chadd HAL_BOOL
ar9300_phy_disable(struct ath_hal * ah)196976bd547bSAdrian Chadd ar9300_phy_disable(struct ath_hal *ah)
197076bd547bSAdrian Chadd {
197176bd547bSAdrian Chadd     if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) {
197276bd547bSAdrian Chadd         return AH_FALSE;
197376bd547bSAdrian Chadd     }
197476bd547bSAdrian Chadd 
197576bd547bSAdrian Chadd #ifdef ATH_SUPPORT_LED
197676bd547bSAdrian Chadd #define REG_READ(_reg)          *((volatile u_int32_t *)(_reg))
197776bd547bSAdrian Chadd #define REG_WRITE(_reg, _val)   *((volatile u_int32_t *)(_reg)) = (_val);
197876bd547bSAdrian Chadd #define ATH_GPIO_OE             0xB8040000
197976bd547bSAdrian Chadd #define ATH_GPIO_OUT            0xB8040008 /* GPIO Ouput Value reg.*/
198076bd547bSAdrian Chadd     if (AR_SREV_WASP(ah)) {
198176bd547bSAdrian Chadd         if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {
198276bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13)));
198376bd547bSAdrian Chadd         }
198476bd547bSAdrian Chadd         else {
198576bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));
198676bd547bSAdrian Chadd         }
198776bd547bSAdrian Chadd     }
198876bd547bSAdrian Chadd     else if (AR_SREV_SCORPION(ah)) {
198976bd547bSAdrian Chadd         if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {
199076bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13)));
199176bd547bSAdrian Chadd         }
199276bd547bSAdrian Chadd         else {
199376bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));
199476bd547bSAdrian Chadd         }
199576bd547bSAdrian Chadd         /* Turn off JMPST led */
199676bd547bSAdrian Chadd         REG_WRITE(ATH_GPIO_OUT, (REG_READ(ATH_GPIO_OUT) | (0x1 << 15)));
199776bd547bSAdrian Chadd     }
199827e2ad46SAdrian Chadd     else if (AR_SREV_HONEYBEE(ah)) {
199927e2ad46SAdrian Chadd         REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));
200027e2ad46SAdrian Chadd     }
200176bd547bSAdrian Chadd #undef REG_READ
200276bd547bSAdrian Chadd #undef REG_WRITE
200376bd547bSAdrian Chadd #endif
200476bd547bSAdrian Chadd 
200576bd547bSAdrian Chadd     if ( AR_SREV_OSPREY(ah) ) {
200676bd547bSAdrian Chadd         OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1), 0x0, 0x1f);
200776bd547bSAdrian Chadd     }
200876bd547bSAdrian Chadd 
200976bd547bSAdrian Chadd 
201076bd547bSAdrian Chadd     ar9300_init_pll(ah, AH_NULL);
2011f0949f0cSAdrian Chadd     ar9300_disable_pll_lock_detect(ah);
201276bd547bSAdrian Chadd 
201376bd547bSAdrian Chadd     return AH_TRUE;
201476bd547bSAdrian Chadd }
201576bd547bSAdrian Chadd 
201676bd547bSAdrian Chadd /*
201776bd547bSAdrian Chadd  * Places all of hardware into reset
201876bd547bSAdrian Chadd  */
201976bd547bSAdrian Chadd HAL_BOOL
ar9300_disable(struct ath_hal * ah)202076bd547bSAdrian Chadd ar9300_disable(struct ath_hal *ah)
202176bd547bSAdrian Chadd {
202276bd547bSAdrian Chadd     if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {
202376bd547bSAdrian Chadd         return AH_FALSE;
202476bd547bSAdrian Chadd     }
202576bd547bSAdrian Chadd     if (!ar9300_set_reset_reg(ah, HAL_RESET_COLD)) {
202676bd547bSAdrian Chadd         return AH_FALSE;
202776bd547bSAdrian Chadd     }
202876bd547bSAdrian Chadd 
202976bd547bSAdrian Chadd     ar9300_init_pll(ah, AH_NULL);
203076bd547bSAdrian Chadd 
203176bd547bSAdrian Chadd     return AH_TRUE;
203276bd547bSAdrian Chadd }
203376bd547bSAdrian Chadd 
203476bd547bSAdrian Chadd /*
203576bd547bSAdrian Chadd  * TODO: Only write the PLL if we're changing to or from CCK mode
203676bd547bSAdrian Chadd  *
203776bd547bSAdrian Chadd  * WARNING: The order of the PLL and mode registers must be correct.
203876bd547bSAdrian Chadd  */
203976bd547bSAdrian Chadd static inline void
ar9300_set_rf_mode(struct ath_hal * ah,struct ieee80211_channel * chan)2040e113789bSAdrian Chadd ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan)
204176bd547bSAdrian Chadd {
204276bd547bSAdrian Chadd     u_int32_t rf_mode = 0;
204376bd547bSAdrian Chadd 
204476bd547bSAdrian Chadd     if (chan == AH_NULL) {
204576bd547bSAdrian Chadd         return;
204676bd547bSAdrian Chadd     }
204776bd547bSAdrian Chadd     switch (AH9300(ah)->ah_hwp) {
204876bd547bSAdrian Chadd     case HAL_TRUE_CHIP:
2049e113789bSAdrian Chadd         rf_mode |= (IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_G(chan)) ?
205076bd547bSAdrian Chadd             AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
205176bd547bSAdrian Chadd         break;
205276bd547bSAdrian Chadd     default:
205376bd547bSAdrian Chadd         HALASSERT(0);
205476bd547bSAdrian Chadd         break;
205576bd547bSAdrian Chadd     }
205676bd547bSAdrian Chadd     /*  Phy mode bits for 5GHz channels requiring Fast Clock */
205776bd547bSAdrian Chadd     if ( IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {
205876bd547bSAdrian Chadd         rf_mode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
205976bd547bSAdrian Chadd     }
206076bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_MODE, rf_mode);
206176bd547bSAdrian Chadd }
206276bd547bSAdrian Chadd 
206376bd547bSAdrian Chadd /*
206476bd547bSAdrian Chadd  * Places the hardware into reset and then pulls it out of reset
206576bd547bSAdrian Chadd  */
206676bd547bSAdrian Chadd HAL_BOOL
ar9300_chip_reset(struct ath_hal * ah,struct ieee80211_channel * chan,HAL_RESET_TYPE reset_type)20678c01c3dcSAdrian Chadd ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_RESET_TYPE reset_type)
206876bd547bSAdrian Chadd {
206976bd547bSAdrian Chadd     struct ath_hal_9300     *ahp = AH9300(ah);
20702dc7b713SAdrian Chadd     int type = HAL_RESET_WARM;
2071e113789bSAdrian Chadd 
2072e113789bSAdrian Chadd     OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);
207376bd547bSAdrian Chadd 
207476bd547bSAdrian Chadd     /*
207576bd547bSAdrian Chadd      * Warm reset is optimistic.
20762dc7b713SAdrian Chadd      *
20772dc7b713SAdrian Chadd      * If the TX/RX DMA engines aren't shut down (eg, they're
20782dc7b713SAdrian Chadd      * wedged) then we're better off doing a full cold reset
20792dc7b713SAdrian Chadd      * to try and shake that condition.
208076bd547bSAdrian Chadd      */
20812dc7b713SAdrian Chadd     if (ahp->ah_chip_full_sleep ||
20822dc7b713SAdrian Chadd         (ah->ah_config.ah_force_full_reset == 1) ||
20838c01c3dcSAdrian Chadd         (reset_type == HAL_RESET_FORCE_COLD) ||
20848c01c3dcSAdrian Chadd         (reset_type == HAL_RESET_BBPANIC) ||
20852dc7b713SAdrian Chadd         OS_REG_READ(ah, AR_Q_TXE) ||
20862dc7b713SAdrian Chadd         (OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) {
20878c01c3dcSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_RESET,
20888c01c3dcSAdrian Chadd               "%s: full reset; reset_type=%d, full_sleep=%d\n",
20898c01c3dcSAdrian Chadd               __func__, reset_type, ahp->ah_chip_full_sleep);
20902dc7b713SAdrian Chadd             type = HAL_RESET_COLD;
20912dc7b713SAdrian Chadd     }
20922dc7b713SAdrian Chadd 
20932dc7b713SAdrian Chadd     if (!ar9300_set_reset_reg(ah, type)) {
209476bd547bSAdrian Chadd         return AH_FALSE;
209576bd547bSAdrian Chadd     }
209676bd547bSAdrian Chadd 
209776bd547bSAdrian Chadd     /* Bring out of sleep mode (AGAIN) */
209876bd547bSAdrian Chadd     if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {
209976bd547bSAdrian Chadd         return AH_FALSE;
210076bd547bSAdrian Chadd     }
210176bd547bSAdrian Chadd 
210276bd547bSAdrian Chadd     ahp->ah_chip_full_sleep = AH_FALSE;
210376bd547bSAdrian Chadd 
210476bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah)) {
210576bd547bSAdrian Chadd         ar9300_internal_regulator_apply(ah);
210676bd547bSAdrian Chadd     }
210776bd547bSAdrian Chadd 
210876bd547bSAdrian Chadd     ar9300_init_pll(ah, chan);
210976bd547bSAdrian Chadd 
211076bd547bSAdrian Chadd     /*
211176bd547bSAdrian Chadd      * Perform warm reset before the mode/PLL/turbo registers
211276bd547bSAdrian Chadd      * are changed in order to deactivate the radio.  Mode changes
211376bd547bSAdrian Chadd      * with an active radio can result in corrupted shifts to the
211476bd547bSAdrian Chadd      * radio device.
211576bd547bSAdrian Chadd      */
211676bd547bSAdrian Chadd     ar9300_set_rf_mode(ah, chan);
211776bd547bSAdrian Chadd 
211876bd547bSAdrian Chadd     return AH_TRUE;
211976bd547bSAdrian Chadd }
212076bd547bSAdrian Chadd 
212176bd547bSAdrian Chadd /* ar9300_setup_calibration
212276bd547bSAdrian Chadd  * Setup HW to collect samples used for current cal
212376bd547bSAdrian Chadd  */
212476bd547bSAdrian Chadd inline static void
ar9300_setup_calibration(struct ath_hal * ah,HAL_CAL_LIST * curr_cal)212576bd547bSAdrian Chadd ar9300_setup_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal)
212676bd547bSAdrian Chadd {
212776bd547bSAdrian Chadd     /* Select calibration to run */
212876bd547bSAdrian Chadd     switch (curr_cal->cal_data->cal_type) {
212976bd547bSAdrian Chadd     case IQ_MISMATCH_CAL:
213076bd547bSAdrian Chadd         /* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */
213176bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4,
213276bd547bSAdrian Chadd             AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
213376bd547bSAdrian Chadd             curr_cal->cal_data->cal_count_max);
213476bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
213576bd547bSAdrian Chadd 
213676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
213776bd547bSAdrian Chadd             "%s: starting IQ Mismatch Calibration\n", __func__);
213876bd547bSAdrian Chadd 
213976bd547bSAdrian Chadd         /* Kick-off cal */
214076bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
214176bd547bSAdrian Chadd 
214276bd547bSAdrian Chadd         break;
214376bd547bSAdrian Chadd     case TEMP_COMP_CAL:
214476bd547bSAdrian Chadd         if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) ||
214576bd547bSAdrian Chadd             AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {
214676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
214776bd547bSAdrian Chadd                 AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1);
214876bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
214976bd547bSAdrian Chadd                 AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1);
215076bd547bSAdrian Chadd         } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
215176bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
215276bd547bSAdrian Chadd                 AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_LOCAL, 1);
215376bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
215476bd547bSAdrian Chadd                 AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_START, 1);
215576bd547bSAdrian Chadd         } else {
215676bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
215776bd547bSAdrian Chadd                 AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1);
215876bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah,
215976bd547bSAdrian Chadd                 AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1);
216076bd547bSAdrian Chadd         }
216176bd547bSAdrian Chadd 
216276bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
216376bd547bSAdrian Chadd             "%s: starting Temperature Compensation Calibration\n", __func__);
216476bd547bSAdrian Chadd         break;
216576bd547bSAdrian Chadd     default:
216676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
216776bd547bSAdrian Chadd             "%s called with incorrect calibration type.\n", __func__);
216876bd547bSAdrian Chadd     }
216976bd547bSAdrian Chadd }
217076bd547bSAdrian Chadd 
217176bd547bSAdrian Chadd /* ar9300_reset_calibration
217276bd547bSAdrian Chadd  * Initialize shared data structures and prepare a cal to be run.
217376bd547bSAdrian Chadd  */
217476bd547bSAdrian Chadd inline static void
ar9300_reset_calibration(struct ath_hal * ah,HAL_CAL_LIST * curr_cal)217576bd547bSAdrian Chadd ar9300_reset_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal)
217676bd547bSAdrian Chadd {
217776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
217876bd547bSAdrian Chadd     int i;
217976bd547bSAdrian Chadd 
218076bd547bSAdrian Chadd     /* Setup HW for new calibration */
218176bd547bSAdrian Chadd     ar9300_setup_calibration(ah, curr_cal);
218276bd547bSAdrian Chadd 
218376bd547bSAdrian Chadd     /* Change SW state to RUNNING for this calibration */
218476bd547bSAdrian Chadd     curr_cal->cal_state = CAL_RUNNING;
218576bd547bSAdrian Chadd 
218676bd547bSAdrian Chadd     /* Reset data structures shared between different calibrations */
218776bd547bSAdrian Chadd     for (i = 0; i < AR9300_MAX_CHAINS; i++) {
218876bd547bSAdrian Chadd         ahp->ah_meas0.sign[i] = 0;
218976bd547bSAdrian Chadd         ahp->ah_meas1.sign[i] = 0;
219076bd547bSAdrian Chadd         ahp->ah_meas2.sign[i] = 0;
219176bd547bSAdrian Chadd         ahp->ah_meas3.sign[i] = 0;
219276bd547bSAdrian Chadd     }
219376bd547bSAdrian Chadd 
219476bd547bSAdrian Chadd     ahp->ah_cal_samples = 0;
219576bd547bSAdrian Chadd }
219676bd547bSAdrian Chadd 
219776bd547bSAdrian Chadd #ifdef XXX_UNUSED_FUNCTION
219876bd547bSAdrian Chadd /*
219976bd547bSAdrian Chadd  * Find out which of the RX chains are enabled
220076bd547bSAdrian Chadd  */
220176bd547bSAdrian Chadd static u_int32_t
ar9300_get_rx_chain_mask(struct ath_hal * ah)220276bd547bSAdrian Chadd ar9300_get_rx_chain_mask(struct ath_hal *ah)
220376bd547bSAdrian Chadd {
220476bd547bSAdrian Chadd     u_int32_t ret_val = OS_REG_READ(ah, AR_PHY_RX_CHAINMASK);
220576bd547bSAdrian Chadd     /* The bits [2:0] indicate the rx chain mask and are to be
220676bd547bSAdrian Chadd      * interpreted as follows:
220776bd547bSAdrian Chadd      * 00x => Only chain 0 is enabled
220876bd547bSAdrian Chadd      * 01x => Chain 1 and 0 enabled
220976bd547bSAdrian Chadd      * 1xx => Chain 2,1 and 0 enabled
221076bd547bSAdrian Chadd      */
221176bd547bSAdrian Chadd     return (ret_val & 0x7);
221276bd547bSAdrian Chadd }
221376bd547bSAdrian Chadd #endif
221476bd547bSAdrian Chadd 
221576bd547bSAdrian Chadd static void
ar9300_get_nf_hist_base(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * chan,int is_scan,int16_t nf[])221676bd547bSAdrian Chadd ar9300_get_nf_hist_base(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan,
221776bd547bSAdrian Chadd     int is_scan, int16_t nf[])
221876bd547bSAdrian Chadd {
221976bd547bSAdrian Chadd     HAL_NFCAL_BASE *h_base;
222076bd547bSAdrian Chadd 
222176bd547bSAdrian Chadd #ifdef ATH_NF_PER_CHAN
222276bd547bSAdrian Chadd     h_base = &chan->nf_cal_hist.base;
222376bd547bSAdrian Chadd #else
222476bd547bSAdrian Chadd     if (is_scan) {
222576bd547bSAdrian Chadd         /*
222676bd547bSAdrian Chadd          * The channel we are currently on is not the home channel,
222776bd547bSAdrian Chadd          * so we shouldn't use the home channel NF buffer's values on
222876bd547bSAdrian Chadd          * this channel.  Instead, use the NF single value already
222976bd547bSAdrian Chadd          * read for this channel.  (Or, if we haven't read the NF for
223076bd547bSAdrian Chadd          * this channel yet, the SW default for this chip/band will
223176bd547bSAdrian Chadd          * be used.)
223276bd547bSAdrian Chadd          */
223376bd547bSAdrian Chadd         h_base = &chan->nf_cal_hist.base;
223476bd547bSAdrian Chadd     } else {
223576bd547bSAdrian Chadd         /* use the home channel NF info */
223676bd547bSAdrian Chadd         h_base = &AH_PRIVATE(ah)->nf_cal_hist.base;
223776bd547bSAdrian Chadd     }
223876bd547bSAdrian Chadd #endif
223976bd547bSAdrian Chadd     OS_MEMCPY(nf, h_base->priv_nf, sizeof(h_base->priv_nf));
224076bd547bSAdrian Chadd }
224176bd547bSAdrian Chadd 
224276bd547bSAdrian Chadd HAL_BOOL
ar9300_load_nf(struct ath_hal * ah,int16_t nf[])224376bd547bSAdrian Chadd ar9300_load_nf(struct ath_hal *ah, int16_t nf[])
224476bd547bSAdrian Chadd {
224576bd547bSAdrian Chadd     int i, j;
224676bd547bSAdrian Chadd     int32_t val;
224776bd547bSAdrian Chadd     /* XXX where are EXT regs defined */
224876bd547bSAdrian Chadd     const u_int32_t ar9300_cca_regs[] = {
224976bd547bSAdrian Chadd         AR_PHY_CCA_0,
225076bd547bSAdrian Chadd         AR_PHY_CCA_1,
225176bd547bSAdrian Chadd         AR_PHY_CCA_2,
225276bd547bSAdrian Chadd         AR_PHY_EXT_CCA,
225376bd547bSAdrian Chadd         AR_PHY_EXT_CCA_1,
225476bd547bSAdrian Chadd         AR_PHY_EXT_CCA_2,
225576bd547bSAdrian Chadd     };
225676bd547bSAdrian Chadd     u_int8_t chainmask;
225776bd547bSAdrian Chadd 
225876bd547bSAdrian Chadd     /*
225976bd547bSAdrian Chadd      * Force NF calibration for all chains, otherwise Vista station
226076bd547bSAdrian Chadd      * would conduct a bad performance
226176bd547bSAdrian Chadd      */
226276bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
226376bd547bSAdrian Chadd         chainmask = 0x9;
226427e2ad46SAdrian Chadd     } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(ah)) {
226576bd547bSAdrian Chadd         chainmask = 0x1b;
226676bd547bSAdrian Chadd     } else {
226776bd547bSAdrian Chadd         chainmask = 0x3F;
226876bd547bSAdrian Chadd     }
226976bd547bSAdrian Chadd 
227076bd547bSAdrian Chadd     /*
227176bd547bSAdrian Chadd      * Write filtered NF values into max_cca_pwr register parameter
227276bd547bSAdrian Chadd      * so we can load below.
227376bd547bSAdrian Chadd      */
2274e113789bSAdrian Chadd     for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
227576bd547bSAdrian Chadd         if (chainmask & (1 << i)) {
227676bd547bSAdrian Chadd             val = OS_REG_READ(ah, ar9300_cca_regs[i]);
227776bd547bSAdrian Chadd             val &= 0xFFFFFE00;
227876bd547bSAdrian Chadd             val |= (((u_int32_t)(nf[i]) << 1) & 0x1ff);
227976bd547bSAdrian Chadd             OS_REG_WRITE(ah, ar9300_cca_regs[i], val);
228076bd547bSAdrian Chadd         }
228176bd547bSAdrian Chadd     }
228276bd547bSAdrian Chadd 
2283e113789bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s: load %d %d %d %d %d %d\n",
2284e113789bSAdrian Chadd       __func__,
2285e113789bSAdrian Chadd       nf[0], nf[1], nf[2],
2286e113789bSAdrian Chadd       nf[3], nf[4], nf[5]);
2287e113789bSAdrian Chadd 
228876bd547bSAdrian Chadd     /*
228976bd547bSAdrian Chadd      * Load software filtered NF value into baseband internal min_cca_pwr
229076bd547bSAdrian Chadd      * variable.
229176bd547bSAdrian Chadd      */
229276bd547bSAdrian Chadd     OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
229376bd547bSAdrian Chadd     OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
229476bd547bSAdrian Chadd     OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
229576bd547bSAdrian Chadd 
229676bd547bSAdrian Chadd     /* Wait for load to complete, should be fast, a few 10s of us. */
229776bd547bSAdrian Chadd     /* Changed the max delay 250us back to 10000us, since 250us often
229876bd547bSAdrian Chadd      * results in NF load timeout and causes deaf condition
229976bd547bSAdrian Chadd      * during stress testing 12/12/2009
230076bd547bSAdrian Chadd      */
230176bd547bSAdrian Chadd     for (j = 0; j < 10000; j++) {
230276bd547bSAdrian Chadd         if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){
230376bd547bSAdrian Chadd             break;
230476bd547bSAdrian Chadd         }
230576bd547bSAdrian Chadd         OS_DELAY(10);
230676bd547bSAdrian Chadd     }
230776bd547bSAdrian Chadd     if (j == 10000) {
230876bd547bSAdrian Chadd         /*
230976bd547bSAdrian Chadd          * We timed out waiting for the noisefloor to load, probably
231076bd547bSAdrian Chadd          * due to an in-progress rx.  Simply return here and allow
231176bd547bSAdrian Chadd          * the load plenty of time to complete before the next
231276bd547bSAdrian Chadd          * calibration interval.  We need to avoid trying to load -50
231376bd547bSAdrian Chadd          * (which happens below) while the previous load is still in
231476bd547bSAdrian Chadd          * progress as this can cause rx deafness (see EV 66368,62830).
231576bd547bSAdrian Chadd          * Instead by returning here, the baseband nf cal will
231676bd547bSAdrian Chadd          * just be capped by our present noisefloor until the next
231776bd547bSAdrian Chadd          * calibration timer.
231876bd547bSAdrian Chadd          */
231976bd547bSAdrian Chadd         HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,
232076bd547bSAdrian Chadd             "%s: *** TIMEOUT while waiting for nf to load: "
232176bd547bSAdrian Chadd             "AR_PHY_AGC_CONTROL=0x%x ***\n",
232276bd547bSAdrian Chadd             __func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL));
232376bd547bSAdrian Chadd         return AH_FALSE;
232476bd547bSAdrian Chadd     }
232576bd547bSAdrian Chadd 
232676bd547bSAdrian Chadd     /*
232776bd547bSAdrian Chadd      * Restore max_cca_power register parameter again so that we're not capped
232876bd547bSAdrian Chadd      * by the median we just loaded.  This will be initial (and max) value
232976bd547bSAdrian Chadd      * of next noise floor calibration the baseband does.
233076bd547bSAdrian Chadd      */
2331e113789bSAdrian Chadd     for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
233276bd547bSAdrian Chadd         if (chainmask & (1 << i)) {
233376bd547bSAdrian Chadd             val = OS_REG_READ(ah, ar9300_cca_regs[i]);
233476bd547bSAdrian Chadd             val &= 0xFFFFFE00;
233576bd547bSAdrian Chadd             val |= (((u_int32_t)(-50) << 1) & 0x1ff);
233676bd547bSAdrian Chadd             OS_REG_WRITE(ah, ar9300_cca_regs[i], val);
233776bd547bSAdrian Chadd         }
233876bd547bSAdrian Chadd     }
233976bd547bSAdrian Chadd     return AH_TRUE;
234076bd547bSAdrian Chadd }
234176bd547bSAdrian Chadd 
234276bd547bSAdrian Chadd /* ar9300_per_calibration
234376bd547bSAdrian Chadd  * Generic calibration routine.
234476bd547bSAdrian Chadd  * Recalibrate the lower PHY chips to account for temperature/environment
234576bd547bSAdrian Chadd  * changes.
234676bd547bSAdrian Chadd  */
234776bd547bSAdrian Chadd inline static void
ar9300_per_calibration(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * ichan,u_int8_t rxchainmask,HAL_CAL_LIST * curr_cal,HAL_BOOL * is_cal_done)234876bd547bSAdrian Chadd ar9300_per_calibration(struct ath_hal *ah,  HAL_CHANNEL_INTERNAL *ichan,
234976bd547bSAdrian Chadd     u_int8_t rxchainmask, HAL_CAL_LIST *curr_cal, HAL_BOOL *is_cal_done)
235076bd547bSAdrian Chadd {
235176bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
235276bd547bSAdrian Chadd 
235376bd547bSAdrian Chadd     /* Cal is assumed not done until explicitly set below */
235476bd547bSAdrian Chadd     *is_cal_done = AH_FALSE;
235576bd547bSAdrian Chadd 
235676bd547bSAdrian Chadd     /* Calibration in progress. */
235776bd547bSAdrian Chadd     if (curr_cal->cal_state == CAL_RUNNING) {
235876bd547bSAdrian Chadd         /* Check to see if it has finished. */
235976bd547bSAdrian Chadd         if (!(OS_REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) {
236076bd547bSAdrian Chadd             int i, num_chains = 0;
236176bd547bSAdrian Chadd             for (i = 0; i < AR9300_MAX_CHAINS; i++) {
236276bd547bSAdrian Chadd                 if (rxchainmask & (1 << i)) {
236376bd547bSAdrian Chadd                     num_chains++;
236476bd547bSAdrian Chadd                 }
236576bd547bSAdrian Chadd             }
236676bd547bSAdrian Chadd 
236776bd547bSAdrian Chadd             /*
236876bd547bSAdrian Chadd              * Accumulate cal measures for active chains
236976bd547bSAdrian Chadd              */
237076bd547bSAdrian Chadd             curr_cal->cal_data->cal_collect(ah, num_chains);
237176bd547bSAdrian Chadd 
237276bd547bSAdrian Chadd             ahp->ah_cal_samples++;
237376bd547bSAdrian Chadd 
237476bd547bSAdrian Chadd             if (ahp->ah_cal_samples >= curr_cal->cal_data->cal_num_samples) {
237576bd547bSAdrian Chadd                 /*
237676bd547bSAdrian Chadd                  * Process accumulated data
237776bd547bSAdrian Chadd                  */
237876bd547bSAdrian Chadd                 curr_cal->cal_data->cal_post_proc(ah, num_chains);
237976bd547bSAdrian Chadd 
238076bd547bSAdrian Chadd                 /* Calibration has finished. */
2381e113789bSAdrian Chadd                 ichan->calValid |= curr_cal->cal_data->cal_type;
238276bd547bSAdrian Chadd                 curr_cal->cal_state = CAL_DONE;
238376bd547bSAdrian Chadd                 *is_cal_done = AH_TRUE;
238476bd547bSAdrian Chadd             } else {
238576bd547bSAdrian Chadd                 /* Set-up collection of another sub-sample until we
238676bd547bSAdrian Chadd                  * get desired number
238776bd547bSAdrian Chadd                  */
238876bd547bSAdrian Chadd                 ar9300_setup_calibration(ah, curr_cal);
238976bd547bSAdrian Chadd             }
239076bd547bSAdrian Chadd         }
2391e113789bSAdrian Chadd     } else if (!(ichan->calValid & curr_cal->cal_data->cal_type)) {
239276bd547bSAdrian Chadd         /* If current cal is marked invalid in channel, kick it off */
239376bd547bSAdrian Chadd         ar9300_reset_calibration(ah, curr_cal);
239476bd547bSAdrian Chadd     }
239576bd547bSAdrian Chadd }
239676bd547bSAdrian Chadd 
239776bd547bSAdrian Chadd static void
ar9300_start_nf_cal(struct ath_hal * ah)239876bd547bSAdrian Chadd ar9300_start_nf_cal(struct ath_hal *ah)
239976bd547bSAdrian Chadd {
2400899d1cacSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
240176bd547bSAdrian Chadd     OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
240276bd547bSAdrian Chadd     OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
240376bd547bSAdrian Chadd     OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
240476bd547bSAdrian Chadd     AH9300(ah)->nf_tsf32 = ar9300_get_tsf32(ah);
2405899d1cacSAdrian Chadd 
2406899d1cacSAdrian Chadd /*
2407899d1cacSAdrian Chadd  *  We are reading the NF values before we start the NF operation, because
2408899d1cacSAdrian Chadd  *  of that we are getting very high values like -45.
2409899d1cacSAdrian Chadd  *  This triggers the CW_INT detected and EACS module triggers the channel change
2410899d1cacSAdrian Chadd  *  chip_reset_done value is used to fix this issue.
2411899d1cacSAdrian Chadd  *  chip_reset_flag is set during the RTC reset.
2412899d1cacSAdrian Chadd  *  chip_reset_flag is cleared during the starting NF operation.
2413899d1cacSAdrian Chadd  *  if flag is set we will clear the flag and will not read the NF values.
2414899d1cacSAdrian Chadd  */
2415899d1cacSAdrian Chadd     ahp->ah_chip_reset_done = 0;
241676bd547bSAdrian Chadd }
241776bd547bSAdrian Chadd 
241876bd547bSAdrian Chadd /* ar9300_calibration
241976bd547bSAdrian Chadd  * Wrapper for a more generic Calibration routine. Primarily to abstract to
242076bd547bSAdrian Chadd  * upper layers whether there is 1 or more calibrations to be run.
242176bd547bSAdrian Chadd  */
242276bd547bSAdrian Chadd HAL_BOOL
ar9300_calibration(struct ath_hal * ah,struct ieee80211_channel * chan,u_int8_t rxchainmask,HAL_BOOL do_nf_cal,HAL_BOOL * is_cal_done,int is_scan,u_int32_t * sched_cals)2423e113789bSAdrian Chadd ar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask,
242476bd547bSAdrian Chadd     HAL_BOOL do_nf_cal, HAL_BOOL *is_cal_done, int is_scan,
242576bd547bSAdrian Chadd     u_int32_t *sched_cals)
242676bd547bSAdrian Chadd {
242776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
242876bd547bSAdrian Chadd     HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr;
242976bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
2430e113789bSAdrian Chadd     int16_t nf_buf[HAL_NUM_NF_READINGS];
243176bd547bSAdrian Chadd 
243276bd547bSAdrian Chadd     *is_cal_done = AH_TRUE;
243376bd547bSAdrian Chadd 
243476bd547bSAdrian Chadd 
243576bd547bSAdrian Chadd     /* XXX: For initial wasp bringup - disable periodic calibration */
243676bd547bSAdrian Chadd     /* Invalid channel check */
243776bd547bSAdrian Chadd     if (ichan == AH_NULL) {
243876bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CHANNEL,
243976bd547bSAdrian Chadd             "%s: invalid channel %u/0x%x; no mapping\n",
2440e113789bSAdrian Chadd             __func__, chan->ic_freq, chan->ic_flags);
244176bd547bSAdrian Chadd         return AH_FALSE;
244276bd547bSAdrian Chadd     }
244376bd547bSAdrian Chadd 
244476bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
244576bd547bSAdrian Chadd         "%s: Entering, Doing NF Cal = %d\n", __func__, do_nf_cal);
244676bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 0 Rx IQ Cal Correction 0x%08x\n",
244776bd547bSAdrian Chadd         __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
244876bd547bSAdrian Chadd     if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) {
244976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
245076bd547bSAdrian Chadd             "%s: Chain 1 Rx IQ Cal Correction 0x%08x\n",
245176bd547bSAdrian Chadd             __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B1));
245227e2ad46SAdrian Chadd         if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)) {
245376bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
245476bd547bSAdrian Chadd                 "%s: Chain 2 Rx IQ Cal Correction 0x%08x\n",
245576bd547bSAdrian Chadd                 __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B2));
245676bd547bSAdrian Chadd         }
245776bd547bSAdrian Chadd     }
245876bd547bSAdrian Chadd 
2459e113789bSAdrian Chadd     OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq);
246076bd547bSAdrian Chadd 
246176bd547bSAdrian Chadd     /* For given calibration:
246276bd547bSAdrian Chadd      * 1. Call generic cal routine
246376bd547bSAdrian Chadd      * 2. When this cal is done (is_cal_done) if we have more cals waiting
246476bd547bSAdrian Chadd      *    (eg after reset), mask this to upper layers by not propagating
246576bd547bSAdrian Chadd      *    is_cal_done if it is set to TRUE.
246676bd547bSAdrian Chadd      *    Instead, change is_cal_done to FALSE and setup the waiting cal(s)
246776bd547bSAdrian Chadd      *    to be run.
246876bd547bSAdrian Chadd      */
246976bd547bSAdrian Chadd     if (curr_cal && (curr_cal->cal_data->cal_type & *sched_cals) &&
247076bd547bSAdrian Chadd         (curr_cal->cal_state == CAL_RUNNING ||
247176bd547bSAdrian Chadd          curr_cal->cal_state == CAL_WAITING))
247276bd547bSAdrian Chadd     {
247376bd547bSAdrian Chadd         ar9300_per_calibration(ah, ichan, rxchainmask, curr_cal, is_cal_done);
247476bd547bSAdrian Chadd 
247576bd547bSAdrian Chadd         if (*is_cal_done == AH_TRUE) {
247676bd547bSAdrian Chadd             ahp->ah_cal_list_curr = curr_cal = curr_cal->cal_next;
247776bd547bSAdrian Chadd 
247876bd547bSAdrian Chadd             if (curr_cal && curr_cal->cal_state == CAL_WAITING) {
247976bd547bSAdrian Chadd                 *is_cal_done = AH_FALSE;
248076bd547bSAdrian Chadd                 ar9300_reset_calibration(ah, curr_cal);
248176bd547bSAdrian Chadd             } else {
248276bd547bSAdrian Chadd                 *sched_cals &= ~IQ_MISMATCH_CAL;
248376bd547bSAdrian Chadd             }
248476bd547bSAdrian Chadd         }
248576bd547bSAdrian Chadd     }
248676bd547bSAdrian Chadd 
248776bd547bSAdrian Chadd     /* Do NF cal only at longer intervals */
248876bd547bSAdrian Chadd     if (do_nf_cal) {
248976bd547bSAdrian Chadd         int nf_done;
249076bd547bSAdrian Chadd 
249176bd547bSAdrian Chadd         /* Get the value from the previous NF cal and update history buffer */
2492e113789bSAdrian Chadd         nf_done = ar9300_store_new_nf(ah, chan, is_scan);
2493e113789bSAdrian Chadd #if 0
249476bd547bSAdrian Chadd         if (ichan->channel_flags & CHANNEL_CW_INT) {
249576bd547bSAdrian Chadd             chan->channel_flags |= CHANNEL_CW_INT;
249676bd547bSAdrian Chadd         }
2497e113789bSAdrian Chadd #endif
2498e113789bSAdrian Chadd         chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;
249976bd547bSAdrian Chadd 
250076bd547bSAdrian Chadd         if (nf_done) {
25018a97beffSAdrian Chadd             int ret;
250276bd547bSAdrian Chadd             /*
250376bd547bSAdrian Chadd              * Load the NF from history buffer of the current channel.
250476bd547bSAdrian Chadd              * NF is slow time-variant, so it is OK to use a historical value.
250576bd547bSAdrian Chadd              */
2506e113789bSAdrian Chadd             ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);
250776bd547bSAdrian Chadd 
25088a97beffSAdrian Chadd             ret = ar9300_load_nf(ah, nf_buf);
250976bd547bSAdrian Chadd             /* start NF calibration, without updating BB NF register*/
251076bd547bSAdrian Chadd             ar9300_start_nf_cal(ah);
25118a97beffSAdrian Chadd 
25128a97beffSAdrian Chadd             /*
25138a97beffSAdrian Chadd              * If we failed the NF cal then tell the upper layer that we
25148a97beffSAdrian Chadd              * failed so we can do a full reset
25158a97beffSAdrian Chadd              */
25168a97beffSAdrian Chadd             if (! ret)
25178a97beffSAdrian Chadd                 return AH_FALSE;
251876bd547bSAdrian Chadd         }
251976bd547bSAdrian Chadd     }
252076bd547bSAdrian Chadd     return AH_TRUE;
252176bd547bSAdrian Chadd }
252276bd547bSAdrian Chadd 
252376bd547bSAdrian Chadd /* ar9300_iq_cal_collect
252476bd547bSAdrian Chadd  * Collect data from HW to later perform IQ Mismatch Calibration
252576bd547bSAdrian Chadd  */
252676bd547bSAdrian Chadd void
ar9300_iq_cal_collect(struct ath_hal * ah,u_int8_t num_chains)252776bd547bSAdrian Chadd ar9300_iq_cal_collect(struct ath_hal *ah, u_int8_t num_chains)
252876bd547bSAdrian Chadd {
252976bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
253076bd547bSAdrian Chadd     int i;
253176bd547bSAdrian Chadd 
253276bd547bSAdrian Chadd     /*
253376bd547bSAdrian Chadd      * Accumulate IQ cal measures for active chains
253476bd547bSAdrian Chadd      */
253576bd547bSAdrian Chadd     for (i = 0; i < num_chains; i++) {
253676bd547bSAdrian Chadd         ahp->ah_total_power_meas_i[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
253776bd547bSAdrian Chadd         ahp->ah_total_power_meas_q[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
253876bd547bSAdrian Chadd         ahp->ah_total_iq_corr_meas[i] =
253976bd547bSAdrian Chadd             (int32_t) OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
254076bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
254176bd547bSAdrian Chadd             "%d: Chn %d "
254276bd547bSAdrian Chadd             "Reg Offset(0x%04x)pmi=0x%08x; "
254376bd547bSAdrian Chadd             "Reg Offset(0x%04x)pmq=0x%08x; "
254476bd547bSAdrian Chadd             "Reg Offset (0x%04x)iqcm=0x%08x;\n",
254576bd547bSAdrian Chadd             ahp->ah_cal_samples,
254676bd547bSAdrian Chadd             i,
254776bd547bSAdrian Chadd             (unsigned) AR_PHY_CAL_MEAS_0(i),
254876bd547bSAdrian Chadd             ahp->ah_total_power_meas_i[i],
254976bd547bSAdrian Chadd             (unsigned) AR_PHY_CAL_MEAS_1(i),
255076bd547bSAdrian Chadd             ahp->ah_total_power_meas_q[i],
255176bd547bSAdrian Chadd             (unsigned) AR_PHY_CAL_MEAS_2(i),
255276bd547bSAdrian Chadd             ahp->ah_total_iq_corr_meas[i]);
255376bd547bSAdrian Chadd     }
255476bd547bSAdrian Chadd }
255576bd547bSAdrian Chadd 
255676bd547bSAdrian Chadd /* ar9300_iq_calibration
255776bd547bSAdrian Chadd  * Use HW data to perform IQ Mismatch Calibration
255876bd547bSAdrian Chadd  */
255976bd547bSAdrian Chadd void
ar9300_iq_calibration(struct ath_hal * ah,u_int8_t num_chains)256076bd547bSAdrian Chadd ar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains)
256176bd547bSAdrian Chadd {
256276bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
256376bd547bSAdrian Chadd     u_int32_t power_meas_q, power_meas_i, iq_corr_meas;
256476bd547bSAdrian Chadd     u_int32_t q_coff_denom, i_coff_denom;
256576bd547bSAdrian Chadd     int32_t q_coff, i_coff;
256676bd547bSAdrian Chadd     int iq_corr_neg, i;
2567899d1cacSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan;
256876bd547bSAdrian Chadd     static const u_int32_t offset_array[3] = {
256976bd547bSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_B0,
257076bd547bSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_B1,
257176bd547bSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_B2,
257276bd547bSAdrian Chadd     };
257376bd547bSAdrian Chadd 
2574899d1cacSAdrian Chadd     ichan = ath_hal_checkchannel(ah, AH_PRIVATE(ah)->ah_curchan);
2575899d1cacSAdrian Chadd 
257676bd547bSAdrian Chadd     for (i = 0; i < num_chains; i++) {
257776bd547bSAdrian Chadd         power_meas_i = ahp->ah_total_power_meas_i[i];
257876bd547bSAdrian Chadd         power_meas_q = ahp->ah_total_power_meas_q[i];
257976bd547bSAdrian Chadd         iq_corr_meas = ahp->ah_total_iq_corr_meas[i];
258076bd547bSAdrian Chadd 
258176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
258276bd547bSAdrian Chadd             "Starting IQ Cal and Correction for Chain %d\n", i);
258376bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
258476bd547bSAdrian Chadd             "Orignal: Chn %diq_corr_meas = 0x%08x\n",
258576bd547bSAdrian Chadd             i, ahp->ah_total_iq_corr_meas[i]);
258676bd547bSAdrian Chadd 
258776bd547bSAdrian Chadd         iq_corr_neg = 0;
258876bd547bSAdrian Chadd 
258976bd547bSAdrian Chadd         /* iq_corr_meas is always negative. */
259076bd547bSAdrian Chadd         if (iq_corr_meas > 0x80000000)  {
259176bd547bSAdrian Chadd             iq_corr_meas = (0xffffffff - iq_corr_meas) + 1;
259276bd547bSAdrian Chadd             iq_corr_neg = 1;
259376bd547bSAdrian Chadd         }
259476bd547bSAdrian Chadd 
259576bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
259676bd547bSAdrian Chadd             "Chn %d pwr_meas_i = 0x%08x\n", i, power_meas_i);
259776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
259876bd547bSAdrian Chadd             "Chn %d pwr_meas_q = 0x%08x\n", i, power_meas_q);
259976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
260076bd547bSAdrian Chadd             "iq_corr_neg is 0x%08x\n", iq_corr_neg);
260176bd547bSAdrian Chadd 
260276bd547bSAdrian Chadd         i_coff_denom = (power_meas_i / 2 + power_meas_q / 2) / 256;
260376bd547bSAdrian Chadd         q_coff_denom = power_meas_q / 64;
260476bd547bSAdrian Chadd 
260576bd547bSAdrian Chadd         /* Protect against divide-by-0 */
260676bd547bSAdrian Chadd         if ((i_coff_denom != 0) && (q_coff_denom != 0)) {
260776bd547bSAdrian Chadd             /* IQ corr_meas is already negated if iqcorr_neg == 1 */
260876bd547bSAdrian Chadd             i_coff = iq_corr_meas / i_coff_denom;
260976bd547bSAdrian Chadd             q_coff = power_meas_i / q_coff_denom - 64;
261076bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
261176bd547bSAdrian Chadd                 "Chn %d i_coff = 0x%08x\n", i, i_coff);
261276bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
261376bd547bSAdrian Chadd                 "Chn %d q_coff = 0x%08x\n", i, q_coff);
261476bd547bSAdrian Chadd 
261576bd547bSAdrian Chadd             /* Force bounds on i_coff */
261676bd547bSAdrian Chadd             if (i_coff >= 63) {
261776bd547bSAdrian Chadd                 i_coff = 63;
261876bd547bSAdrian Chadd             } else if (i_coff <= -63) {
261976bd547bSAdrian Chadd                 i_coff = -63;
262076bd547bSAdrian Chadd             }
262176bd547bSAdrian Chadd 
262276bd547bSAdrian Chadd             /* Negate i_coff if iq_corr_neg == 0 */
262376bd547bSAdrian Chadd             if (iq_corr_neg == 0x0) {
262476bd547bSAdrian Chadd                 i_coff = -i_coff;
262576bd547bSAdrian Chadd             }
262676bd547bSAdrian Chadd 
262776bd547bSAdrian Chadd             /* Force bounds on q_coff */
262876bd547bSAdrian Chadd             if (q_coff >= 63) {
262976bd547bSAdrian Chadd                 q_coff = 63;
263076bd547bSAdrian Chadd             } else if (q_coff <= -63) {
263176bd547bSAdrian Chadd                 q_coff = -63;
263276bd547bSAdrian Chadd             }
263376bd547bSAdrian Chadd 
263476bd547bSAdrian Chadd             i_coff = i_coff & 0x7f;
263576bd547bSAdrian Chadd             q_coff = q_coff & 0x7f;
263676bd547bSAdrian Chadd 
263776bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
263876bd547bSAdrian Chadd                 "Chn %d : i_coff = 0x%x  q_coff = 0x%x\n", i, i_coff, q_coff);
263976bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
264076bd547bSAdrian Chadd                 "Register offset (0x%04x) before update = 0x%x\n",
264176bd547bSAdrian Chadd                 offset_array[i], OS_REG_READ(ah, offset_array[i]));
264276bd547bSAdrian Chadd 
264376bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, offset_array[i],
264476bd547bSAdrian Chadd                 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff);
264576bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, offset_array[i],
264676bd547bSAdrian Chadd                 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff);
264776bd547bSAdrian Chadd 
2648899d1cacSAdrian Chadd             /* store the RX cal results */
2649899d1cacSAdrian Chadd 	    if (ichan != NULL) {
2650899d1cacSAdrian Chadd             ahp->ah_rx_cal_corr[i] = OS_REG_READ(ah, offset_array[i]) & 0x7fff;
2651899d1cacSAdrian Chadd             ahp->ah_rx_cal_complete = AH_TRUE;
2652899d1cacSAdrian Chadd             ahp->ah_rx_cal_chan = ichan->channel;
2653899d1cacSAdrian Chadd //            ahp->ah_rx_cal_chan_flag = ichan->channel_flags &~ CHANNEL_PASSIVE;
2654899d1cacSAdrian Chadd             ahp->ah_rx_cal_chan_flag = 0; /* XXX */
2655899d1cacSAdrian Chadd 	    } else {
2656899d1cacSAdrian Chadd 	        /* XXX? Is this what I should do? */
2657899d1cacSAdrian Chadd             	ahp->ah_rx_cal_complete = AH_FALSE;
2658899d1cacSAdrian Chadd 
2659899d1cacSAdrian Chadd 	    }
2660899d1cacSAdrian Chadd 
266176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
266276bd547bSAdrian Chadd                 "Register offset (0x%04x) QI COFF (bitfields 0x%08x) "
266376bd547bSAdrian Chadd                 "after update = 0x%x\n",
266476bd547bSAdrian Chadd                 offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
266576bd547bSAdrian Chadd                 OS_REG_READ(ah, offset_array[i]));
266676bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
266776bd547bSAdrian Chadd                 "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) "
266876bd547bSAdrian Chadd                 "after update = 0x%x\n",
266976bd547bSAdrian Chadd                 offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
267076bd547bSAdrian Chadd                 OS_REG_READ(ah, offset_array[i]));
267176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
267276bd547bSAdrian Chadd                 "IQ Cal and Correction done for Chain %d\n", i);
267376bd547bSAdrian Chadd         }
267476bd547bSAdrian Chadd     }
267576bd547bSAdrian Chadd 
267676bd547bSAdrian Chadd     OS_REG_SET_BIT(ah,
267776bd547bSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
267876bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
267976bd547bSAdrian Chadd         "IQ Cal and Correction (offset 0x%04x) enabled "
268076bd547bSAdrian Chadd         "(bit position 0x%08x). New Value 0x%08x\n",
268176bd547bSAdrian Chadd         (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
268276bd547bSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
268376bd547bSAdrian Chadd         OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
268476bd547bSAdrian Chadd }
268576bd547bSAdrian Chadd 
268676bd547bSAdrian Chadd /*
2687899d1cacSAdrian Chadd  * When coming back from offchan, we do not perform RX IQ Cal.
2688899d1cacSAdrian Chadd  * But the chip reset will clear all previous results
2689899d1cacSAdrian Chadd  * We store the previous results and restore here.
2690899d1cacSAdrian Chadd  */
2691899d1cacSAdrian Chadd static void
ar9300_rx_iq_cal_restore(struct ath_hal * ah)2692899d1cacSAdrian Chadd ar9300_rx_iq_cal_restore(struct ath_hal *ah)
2693899d1cacSAdrian Chadd {
2694899d1cacSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
2695899d1cacSAdrian Chadd     u_int32_t   i_coff, q_coff;
2696899d1cacSAdrian Chadd     HAL_BOOL is_restore = AH_FALSE;
2697899d1cacSAdrian Chadd     int i;
2698899d1cacSAdrian Chadd     static const u_int32_t offset_array[3] = {
2699899d1cacSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_B0,
2700899d1cacSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_B1,
2701899d1cacSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_B2,
2702899d1cacSAdrian Chadd     };
2703899d1cacSAdrian Chadd 
2704899d1cacSAdrian Chadd     for (i=0; i<AR9300_MAX_CHAINS; i++) {
2705899d1cacSAdrian Chadd         if (ahp->ah_rx_cal_corr[i]) {
2706899d1cacSAdrian Chadd             i_coff = (ahp->ah_rx_cal_corr[i] &
2707899d1cacSAdrian Chadd                         AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF) >>
2708899d1cacSAdrian Chadd                         AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S;
2709899d1cacSAdrian Chadd             q_coff = (ahp->ah_rx_cal_corr[i] &
2710899d1cacSAdrian Chadd                         AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF) >>
2711899d1cacSAdrian Chadd                         AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S;
2712899d1cacSAdrian Chadd 
2713899d1cacSAdrian Chadd             OS_REG_RMW_FIELD(ah, offset_array[i],
2714899d1cacSAdrian Chadd                 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff);
2715899d1cacSAdrian Chadd             OS_REG_RMW_FIELD(ah, offset_array[i],
2716899d1cacSAdrian Chadd                 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff);
2717899d1cacSAdrian Chadd 
2718899d1cacSAdrian Chadd             is_restore = AH_TRUE;
2719899d1cacSAdrian Chadd         }
2720899d1cacSAdrian Chadd     }
2721899d1cacSAdrian Chadd 
2722899d1cacSAdrian Chadd     if (is_restore)
2723899d1cacSAdrian Chadd         OS_REG_SET_BIT(ah,
2724899d1cacSAdrian Chadd             AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
2725899d1cacSAdrian Chadd 
2726899d1cacSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
2727899d1cacSAdrian Chadd         "%s: IQ Cal and Correction (offset 0x%04x) enabled "
2728899d1cacSAdrian Chadd         "(bit position 0x%08x). New Value 0x%08x\n",
2729899d1cacSAdrian Chadd         __func__,
2730899d1cacSAdrian Chadd         (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
2731899d1cacSAdrian Chadd         AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
2732899d1cacSAdrian Chadd         OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
2733899d1cacSAdrian Chadd }
2734899d1cacSAdrian Chadd 
2735899d1cacSAdrian Chadd /*
273676bd547bSAdrian Chadd  * Set a limit on the overall output power.  Used for dynamic
273776bd547bSAdrian Chadd  * transmit power control and the like.
273876bd547bSAdrian Chadd  *
273976bd547bSAdrian Chadd  * NB: limit is in units of 0.5 dbM.
274076bd547bSAdrian Chadd  */
274176bd547bSAdrian Chadd HAL_BOOL
ar9300_set_tx_power_limit(struct ath_hal * ah,u_int32_t limit,u_int16_t extra_txpow,u_int16_t tpc_in_db)274276bd547bSAdrian Chadd ar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit,
274376bd547bSAdrian Chadd     u_int16_t extra_txpow, u_int16_t tpc_in_db)
274476bd547bSAdrian Chadd {
274576bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
274676bd547bSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
2747e113789bSAdrian Chadd     const struct ieee80211_channel *chan = ahpriv->ah_curchan;
2748e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
274976bd547bSAdrian Chadd 
275076bd547bSAdrian Chadd     if (NULL == chan) {
275176bd547bSAdrian Chadd         return AH_FALSE;
275276bd547bSAdrian Chadd     }
2753e113789bSAdrian Chadd 
2754e113789bSAdrian Chadd     ahpriv->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);
2755e113789bSAdrian Chadd     ahpriv->ah_extraTxPow = extra_txpow;
275676bd547bSAdrian Chadd 
275776bd547bSAdrian Chadd     if(chan == NULL) {
275876bd547bSAdrian Chadd         return AH_FALSE;
275976bd547bSAdrian Chadd     }
2760e113789bSAdrian Chadd     if (ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan,
276176bd547bSAdrian Chadd         ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan),
276276bd547bSAdrian Chadd         ath_hal_get_twice_max_regpower(ahpriv, ichan, chan),
2763e113789bSAdrian Chadd         AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)) != HAL_OK)
276476bd547bSAdrian Chadd     {
276576bd547bSAdrian Chadd         return AH_FALSE;
276676bd547bSAdrian Chadd     }
276776bd547bSAdrian Chadd     return AH_TRUE;
276876bd547bSAdrian Chadd }
276976bd547bSAdrian Chadd 
277076bd547bSAdrian Chadd /*
277176bd547bSAdrian Chadd  * Exported call to check for a recent gain reading and return
277276bd547bSAdrian Chadd  * the current state of the thermal calibration gain engine.
277376bd547bSAdrian Chadd  */
277476bd547bSAdrian Chadd HAL_RFGAIN
ar9300_get_rfgain(struct ath_hal * ah)277576bd547bSAdrian Chadd ar9300_get_rfgain(struct ath_hal *ah)
277676bd547bSAdrian Chadd {
277776bd547bSAdrian Chadd     return HAL_RFGAIN_INACTIVE;
277876bd547bSAdrian Chadd }
277976bd547bSAdrian Chadd 
278076bd547bSAdrian Chadd #define HAL_GREEN_AP_RX_MASK 0x1
278176bd547bSAdrian Chadd 
278276bd547bSAdrian Chadd static inline void
ar9300_init_chain_masks(struct ath_hal * ah,int rx_chainmask,int tx_chainmask)278376bd547bSAdrian Chadd ar9300_init_chain_masks(struct ath_hal *ah, int rx_chainmask, int tx_chainmask)
278476bd547bSAdrian Chadd {
2785e113789bSAdrian Chadd     if (AH9300(ah)->green_ap_ps_on) {
278676bd547bSAdrian Chadd         rx_chainmask = HAL_GREEN_AP_RX_MASK;
278776bd547bSAdrian Chadd     }
278876bd547bSAdrian Chadd     if (rx_chainmask == 0x5) {
278976bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);
279076bd547bSAdrian Chadd     }
279176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
279276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
279376bd547bSAdrian Chadd 
279476bd547bSAdrian Chadd     /*
279576bd547bSAdrian Chadd      * Adaptive Power Management:
279676bd547bSAdrian Chadd      * Some 3 stream chips exceed the PCIe power requirements.
279776bd547bSAdrian Chadd      * This workaround will reduce power consumption by using 2 tx chains
279876bd547bSAdrian Chadd      * for 1 and 2 stream rates (5 GHz only).
279976bd547bSAdrian Chadd      *
280076bd547bSAdrian Chadd      * Set the self gen mask to 2 tx chains when APM is enabled.
280176bd547bSAdrian Chadd      *
280276bd547bSAdrian Chadd      */
2803e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_caps.halApmEnable && (tx_chainmask == 0x7)) {
280476bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
280576bd547bSAdrian Chadd     }
280676bd547bSAdrian Chadd     else {
280776bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
280876bd547bSAdrian Chadd     }
280976bd547bSAdrian Chadd 
281076bd547bSAdrian Chadd     if (tx_chainmask == 0x5) {
281176bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);
281276bd547bSAdrian Chadd     }
281376bd547bSAdrian Chadd }
281476bd547bSAdrian Chadd 
281576bd547bSAdrian Chadd /*
281676bd547bSAdrian Chadd  * Override INI values with chip specific configuration.
281776bd547bSAdrian Chadd  */
281876bd547bSAdrian Chadd static inline void
ar9300_override_ini(struct ath_hal * ah,struct ieee80211_channel * chan)2819e113789bSAdrian Chadd ar9300_override_ini(struct ath_hal *ah, struct ieee80211_channel *chan)
282076bd547bSAdrian Chadd {
282176bd547bSAdrian Chadd     u_int32_t val;
282276bd547bSAdrian Chadd     HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
282376bd547bSAdrian Chadd 
282476bd547bSAdrian Chadd     /*
282576bd547bSAdrian Chadd      * Set the RX_ABORT and RX_DIS and clear it only after
282676bd547bSAdrian Chadd      * RXE is set for MAC. This prevents frames with
282776bd547bSAdrian Chadd      * corrupted descriptor status.
282876bd547bSAdrian Chadd      */
282976bd547bSAdrian Chadd     OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
283076bd547bSAdrian Chadd     /*
283176bd547bSAdrian Chadd      * For Merlin and above, there is a new feature that allows Multicast
283276bd547bSAdrian Chadd      * search based on both MAC Address and Key ID.
283376bd547bSAdrian Chadd      * By default, this feature is enabled.
283476bd547bSAdrian Chadd      * But since the driver is not using this feature, we switch it off;
283576bd547bSAdrian Chadd      * otherwise multicast search based on MAC addr only will fail.
283676bd547bSAdrian Chadd      */
283776bd547bSAdrian Chadd     val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);
283876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PCU_MISC_MODE2,
283976bd547bSAdrian Chadd         val | AR_BUG_58603_FIX_ENABLE | AR_AGG_WEP_ENABLE);
284076bd547bSAdrian Chadd 
284176bd547bSAdrian Chadd 
284276bd547bSAdrian Chadd     /* Osprey revision specific configuration */
284376bd547bSAdrian Chadd 
284476bd547bSAdrian Chadd     /* Osprey 2.0+ - if SW RAC support is disabled, must also disable
284576bd547bSAdrian Chadd      * the Osprey 2.0 hardware RAC fix.
284676bd547bSAdrian Chadd      */
2847e113789bSAdrian Chadd     if (p_cap->halIsrRacSupport == AH_FALSE) {
284876bd547bSAdrian Chadd         OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_MISSING_TX_INTR_FIX_ENABLE);
284976bd547bSAdrian Chadd     }
285076bd547bSAdrian Chadd 
285176bd547bSAdrian Chadd     /* try to enable old pal if it is needed for h/w green tx */
285276bd547bSAdrian Chadd     ar9300_hwgreentx_set_pal_spare(ah, 1);
285376bd547bSAdrian Chadd }
285476bd547bSAdrian Chadd 
285576bd547bSAdrian Chadd static inline void
ar9300_prog_ini(struct ath_hal * ah,struct ar9300_ini_array * ini_arr,int column)285676bd547bSAdrian Chadd ar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr,
285776bd547bSAdrian Chadd     int column)
285876bd547bSAdrian Chadd {
285976bd547bSAdrian Chadd     int i, reg_writes = 0;
286076bd547bSAdrian Chadd 
286176bd547bSAdrian Chadd     /* New INI format: Array may be undefined (pre, core, post arrays) */
286276bd547bSAdrian Chadd     if (ini_arr->ia_array == NULL) {
286376bd547bSAdrian Chadd         return;
286476bd547bSAdrian Chadd     }
286576bd547bSAdrian Chadd 
286676bd547bSAdrian Chadd     /*
286776bd547bSAdrian Chadd      * New INI format: Pre, core, and post arrays for a given subsystem may be
286876bd547bSAdrian Chadd      * modal (> 2 columns) or non-modal (2 columns).
286976bd547bSAdrian Chadd      * Determine if the array is non-modal and force the column to 1.
287076bd547bSAdrian Chadd      */
287176bd547bSAdrian Chadd     if (column >= ini_arr->ia_columns) {
287276bd547bSAdrian Chadd         column = 1;
287376bd547bSAdrian Chadd     }
287476bd547bSAdrian Chadd 
287576bd547bSAdrian Chadd     for (i = 0; i < ini_arr->ia_rows; i++) {
287676bd547bSAdrian Chadd         u_int32_t reg = INI_RA(ini_arr, i, 0);
287776bd547bSAdrian Chadd         u_int32_t val = INI_RA(ini_arr, i, column);
287876bd547bSAdrian Chadd 
287976bd547bSAdrian Chadd         /*
288076bd547bSAdrian Chadd         ** Determine if this is a shift register value
288176bd547bSAdrian Chadd         ** (reg >= 0x16000 && reg < 0x17000 for Osprey) ,
288276bd547bSAdrian Chadd         ** and insert the configured delay if so.
288376bd547bSAdrian Chadd         ** -this delay is not required for Osprey (EV#71410)
288476bd547bSAdrian Chadd         */
288576bd547bSAdrian Chadd         OS_REG_WRITE(ah, reg, val);
288676bd547bSAdrian Chadd         WAR_6773(reg_writes);
288776bd547bSAdrian Chadd 
288876bd547bSAdrian Chadd     }
288976bd547bSAdrian Chadd }
289076bd547bSAdrian Chadd 
289176bd547bSAdrian Chadd static inline HAL_STATUS
ar9300_process_ini(struct ath_hal * ah,struct ieee80211_channel * chan,HAL_CHANNEL_INTERNAL * ichan,HAL_HT_MACMODE macmode)2892e113789bSAdrian Chadd ar9300_process_ini(struct ath_hal *ah, struct ieee80211_channel *chan,
289376bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode)
289476bd547bSAdrian Chadd {
289576bd547bSAdrian Chadd     int reg_writes = 0;
289676bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
289776bd547bSAdrian Chadd     u_int modes_index, modes_txgaintable_index = 0;
289876bd547bSAdrian Chadd     int i;
289976bd547bSAdrian Chadd     HAL_STATUS status;
290076bd547bSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
290176bd547bSAdrian Chadd     /* Setup the indices for the next set of register array writes */
290276bd547bSAdrian Chadd     /* TODO:
290376bd547bSAdrian Chadd      * If the channel marker is indicative of the current mode rather
290476bd547bSAdrian Chadd      * than capability, we do not need to check the phy mode below.
290576bd547bSAdrian Chadd      */
2906e113789bSAdrian Chadd #if 0
290776bd547bSAdrian Chadd     switch (chan->channel_flags & CHANNEL_ALL) {
290876bd547bSAdrian Chadd     case CHANNEL_A:
290976bd547bSAdrian Chadd     case CHANNEL_A_HT20:
291076bd547bSAdrian Chadd         if (AR_SREV_SCORPION(ah)){
291176bd547bSAdrian Chadd             if (chan->channel <= 5350){
291276bd547bSAdrian Chadd                 modes_txgaintable_index = 1;
291376bd547bSAdrian Chadd             }else if ((chan->channel > 5350) && (chan->channel <= 5600)){
291476bd547bSAdrian Chadd                 modes_txgaintable_index = 3;
291576bd547bSAdrian Chadd             }else if (chan->channel > 5600){
291676bd547bSAdrian Chadd                 modes_txgaintable_index = 5;
291776bd547bSAdrian Chadd             }
291876bd547bSAdrian Chadd         }
291976bd547bSAdrian Chadd         modes_index = 1;
292027e2ad46SAdrian Chadd         freq_index  = 1;
292176bd547bSAdrian Chadd         break;
292276bd547bSAdrian Chadd 
292376bd547bSAdrian Chadd     case CHANNEL_A_HT40PLUS:
292476bd547bSAdrian Chadd     case CHANNEL_A_HT40MINUS:
292576bd547bSAdrian Chadd         if (AR_SREV_SCORPION(ah)){
292676bd547bSAdrian Chadd             if (chan->channel <= 5350){
292776bd547bSAdrian Chadd                 modes_txgaintable_index = 2;
292876bd547bSAdrian Chadd             }else if ((chan->channel > 5350) && (chan->channel <= 5600)){
292976bd547bSAdrian Chadd                 modes_txgaintable_index = 4;
293076bd547bSAdrian Chadd             }else if (chan->channel > 5600){
293176bd547bSAdrian Chadd                 modes_txgaintable_index = 6;
293276bd547bSAdrian Chadd             }
293376bd547bSAdrian Chadd         }
293476bd547bSAdrian Chadd         modes_index = 2;
293527e2ad46SAdrian Chadd         freq_index  = 1;
293676bd547bSAdrian Chadd         break;
293776bd547bSAdrian Chadd 
293876bd547bSAdrian Chadd     case CHANNEL_PUREG:
293976bd547bSAdrian Chadd     case CHANNEL_G_HT20:
294076bd547bSAdrian Chadd     case CHANNEL_B:
294176bd547bSAdrian Chadd         if (AR_SREV_SCORPION(ah)){
294276bd547bSAdrian Chadd             modes_txgaintable_index = 8;
294327e2ad46SAdrian Chadd         }else if (AR_SREV_HONEYBEE(ah)){
294427e2ad46SAdrian Chadd 	    modes_txgaintable_index = 1;
294576bd547bSAdrian Chadd 	}
294676bd547bSAdrian Chadd         modes_index = 4;
294727e2ad46SAdrian Chadd         freq_index  = 2;
294876bd547bSAdrian Chadd         break;
294976bd547bSAdrian Chadd 
295076bd547bSAdrian Chadd     case CHANNEL_G_HT40PLUS:
295176bd547bSAdrian Chadd     case CHANNEL_G_HT40MINUS:
295276bd547bSAdrian Chadd         if (AR_SREV_SCORPION(ah)){
295376bd547bSAdrian Chadd             modes_txgaintable_index = 7;
295427e2ad46SAdrian Chadd         }else if (AR_SREV_HONEYBEE(ah)){
295527e2ad46SAdrian Chadd             modes_txgaintable_index = 1;
295676bd547bSAdrian Chadd         }
295776bd547bSAdrian Chadd         modes_index = 3;
295827e2ad46SAdrian Chadd         freq_index  = 2;
295976bd547bSAdrian Chadd         break;
296076bd547bSAdrian Chadd 
296176bd547bSAdrian Chadd     case CHANNEL_108G:
296276bd547bSAdrian Chadd         modes_index = 5;
296327e2ad46SAdrian Chadd         freq_index  = 2;
296476bd547bSAdrian Chadd         break;
296576bd547bSAdrian Chadd 
296676bd547bSAdrian Chadd     default:
296776bd547bSAdrian Chadd         HALASSERT(0);
296876bd547bSAdrian Chadd         return HAL_EINVAL;
296976bd547bSAdrian Chadd     }
2970e113789bSAdrian Chadd #endif
2971e113789bSAdrian Chadd 
2972e113789bSAdrian Chadd     /* FreeBSD */
2973e113789bSAdrian Chadd     if (IS_CHAN_5GHZ(ichan)) {
2974e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) {
2975e113789bSAdrian Chadd             if (AR_SREV_SCORPION(ah)){
2976e113789bSAdrian Chadd                 if (ichan->channel <= 5350){
2977e113789bSAdrian Chadd                     modes_txgaintable_index = 2;
2978e113789bSAdrian Chadd                 }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){
2979e113789bSAdrian Chadd                     modes_txgaintable_index = 4;
2980e113789bSAdrian Chadd                 }else if (ichan->channel > 5600){
2981e113789bSAdrian Chadd                     modes_txgaintable_index = 6;
2982e113789bSAdrian Chadd                 }
2983e113789bSAdrian Chadd             }
2984e113789bSAdrian Chadd             modes_index = 2;
2985e113789bSAdrian Chadd         } else if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_HT20(chan)) {
2986e113789bSAdrian Chadd             if (AR_SREV_SCORPION(ah)){
2987e113789bSAdrian Chadd                 if (ichan->channel <= 5350){
2988e113789bSAdrian Chadd                     modes_txgaintable_index = 1;
2989e113789bSAdrian Chadd                 }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){
2990e113789bSAdrian Chadd                     modes_txgaintable_index = 3;
2991e113789bSAdrian Chadd                 }else if (ichan->channel > 5600){
2992e113789bSAdrian Chadd                     modes_txgaintable_index = 5;
2993e113789bSAdrian Chadd                 }
2994e113789bSAdrian Chadd             }
2995e113789bSAdrian Chadd             modes_index = 1;
2996e113789bSAdrian Chadd         } else
2997e113789bSAdrian Chadd             return HAL_EINVAL;
2998e113789bSAdrian Chadd     } else if (IS_CHAN_2GHZ(ichan)) {
2999e113789bSAdrian Chadd         if (IEEE80211_IS_CHAN_108G(chan)) {
3000e113789bSAdrian Chadd             modes_index = 5;
3001e113789bSAdrian Chadd         } else if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) {
3002e113789bSAdrian Chadd             if (AR_SREV_SCORPION(ah)){
3003e113789bSAdrian Chadd                 modes_txgaintable_index = 7;
300427e2ad46SAdrian Chadd             } else if (AR_SREV_HONEYBEE(ah)){
300527e2ad46SAdrian Chadd                 modes_txgaintable_index = 1;
3006e113789bSAdrian Chadd             }
3007e113789bSAdrian Chadd             modes_index = 3;
3008e113789bSAdrian Chadd         } else if (IEEE80211_IS_CHAN_HT20(chan) || IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_PUREG(chan)) {
3009e113789bSAdrian Chadd             if (AR_SREV_SCORPION(ah)){
3010e113789bSAdrian Chadd                 modes_txgaintable_index = 8;
301127e2ad46SAdrian Chadd             } else if (AR_SREV_HONEYBEE(ah)){
301227e2ad46SAdrian Chadd                 modes_txgaintable_index = 1;
3013e113789bSAdrian Chadd             }
3014e113789bSAdrian Chadd             modes_index = 4;
3015e113789bSAdrian Chadd         } else
3016e113789bSAdrian Chadd             return HAL_EINVAL;
3017e113789bSAdrian Chadd     } else
3018e113789bSAdrian Chadd             return HAL_EINVAL;
301976bd547bSAdrian Chadd 
302076bd547bSAdrian Chadd #if 0
302176bd547bSAdrian Chadd     /* Set correct Baseband to analog shift setting to access analog chips. */
302276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
302376bd547bSAdrian Chadd #endif
302476bd547bSAdrian Chadd 
302576bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_RESET,
302676bd547bSAdrian Chadd         "ar9300_process_ini: "
302776bd547bSAdrian Chadd         "Skipping OS-REG-WRITE(ah, AR-PHY(0), 0x00000007)\n");
302876bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_RESET,
302976bd547bSAdrian Chadd         "ar9300_process_ini: no ADDac programming\n");
303076bd547bSAdrian Chadd 
303176bd547bSAdrian Chadd 
303276bd547bSAdrian Chadd     /*
303376bd547bSAdrian Chadd      * Osprey 2.0+ - new INI format.
303476bd547bSAdrian Chadd      * Each subsystem has a pre, core, and post array.
303576bd547bSAdrian Chadd      */
303676bd547bSAdrian Chadd     for (i = 0; i < ATH_INI_NUM_SPLIT; i++) {
303776bd547bSAdrian Chadd         ar9300_prog_ini(ah, &ahp->ah_ini_soc[i], modes_index);
303876bd547bSAdrian Chadd         ar9300_prog_ini(ah, &ahp->ah_ini_mac[i], modes_index);
303976bd547bSAdrian Chadd         ar9300_prog_ini(ah, &ahp->ah_ini_bb[i], modes_index);
304076bd547bSAdrian Chadd         ar9300_prog_ini(ah, &ahp->ah_ini_radio[i], modes_index);
3041615a867fSAdrian Chadd         if ((i == ATH_INI_POST) && (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah))) {
304276bd547bSAdrian Chadd             ar9300_prog_ini(ah, &ahp->ah_ini_radio_post_sys2ant, modes_index);
304376bd547bSAdrian Chadd         }
304476bd547bSAdrian Chadd 
304576bd547bSAdrian Chadd     }
304676bd547bSAdrian Chadd 
304776bd547bSAdrian Chadd 	if (!(AR_SREV_SOC(ah))) {
304876bd547bSAdrian Chadd 			/* Doubler issue : Some board doesn't work well with MCS15. Turn off doubler after freq locking is complete*/
304976bd547bSAdrian Chadd 			//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));
305076bd547bSAdrian Chadd 			OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
305176bd547bSAdrian Chadd 			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */
305276bd547bSAdrian Chadd 			//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));
305376bd547bSAdrian Chadd 
305476bd547bSAdrian Chadd 			OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
305576bd547bSAdrian Chadd 			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */
305676bd547bSAdrian Chadd 			OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
305776bd547bSAdrian Chadd 			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */
305876bd547bSAdrian Chadd 			OS_DELAY(200);
305976bd547bSAdrian Chadd 
306076bd547bSAdrian Chadd 			//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));
306176bd547bSAdrian Chadd 			OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */
306276bd547bSAdrian Chadd 			OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */
306376bd547bSAdrian Chadd 			OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */
306476bd547bSAdrian Chadd 			//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));
306576bd547bSAdrian Chadd 
306676bd547bSAdrian Chadd 			OS_DELAY(1);
306776bd547bSAdrian Chadd 
306876bd547bSAdrian Chadd 			//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));
306976bd547bSAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */
307076bd547bSAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */
307176bd547bSAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */
307276bd547bSAdrian Chadd 			//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));
307376bd547bSAdrian Chadd 
307476bd547bSAdrian Chadd 			OS_DELAY(200);
307576bd547bSAdrian Chadd 
307676bd547bSAdrian Chadd 			//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));
307776bd547bSAdrian Chadd 			OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf);
307876bd547bSAdrian Chadd 			//OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_SYNTH12, 1<< 16); /* clr charge pump */
307976bd547bSAdrian Chadd 			//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));
308076bd547bSAdrian Chadd 
308176bd547bSAdrian Chadd 			OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
308276bd547bSAdrian Chadd 			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */
308376bd547bSAdrian Chadd 			OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
308476bd547bSAdrian Chadd 			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */
308576bd547bSAdrian Chadd 			OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |
308676bd547bSAdrian Chadd 			               1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */
308776bd547bSAdrian Chadd 			//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));
308876bd547bSAdrian Chadd 		}
308976bd547bSAdrian Chadd 
309076bd547bSAdrian Chadd     /* Write rxgain Array Parameters */
309176bd547bSAdrian Chadd     REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain, 1, reg_writes);
309276bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain programming\n");
309376bd547bSAdrian Chadd 
309409ff344bSAdrian Chadd     if (AR_SREV_JUPITER_20_OR_LATER(ah)) {
309509ff344bSAdrian Chadd         /*
309609ff344bSAdrian Chadd          * CUS217 mix LNA mode.
309709ff344bSAdrian Chadd          */
309809ff344bSAdrian Chadd         if (ar9300_rx_gain_index_get(ah) == 2) {
309909ff344bSAdrian Chadd             REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bb_core, 1, reg_writes);
310009ff344bSAdrian Chadd             REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bb_postamble,
310109ff344bSAdrian Chadd                 modes_index, reg_writes);
310209ff344bSAdrian Chadd         }
310309ff344bSAdrian Chadd 
310409ff344bSAdrian Chadd         /*
310509ff344bSAdrian Chadd          * 5G-XLNA
310609ff344bSAdrian Chadd          */
310709ff344bSAdrian Chadd         if ((ar9300_rx_gain_index_get(ah) == 2) ||
310809ff344bSAdrian Chadd             (ar9300_rx_gain_index_get(ah) == 3)) {
310909ff344bSAdrian Chadd             REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_xlna, modes_index,
311009ff344bSAdrian Chadd               reg_writes);
311109ff344bSAdrian Chadd         }
311209ff344bSAdrian Chadd     }
311309ff344bSAdrian Chadd 
311476bd547bSAdrian Chadd     if (AR_SREV_SCORPION(ah)) {
311576bd547bSAdrian Chadd         /* Write rxgain bounds Array */
311676bd547bSAdrian Chadd         REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, modes_index, reg_writes);
311776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain table bounds programming\n");
311876bd547bSAdrian Chadd     }
311976bd547bSAdrian Chadd     /* UB124 xLNA settings */
312076bd547bSAdrian Chadd     if (AR_SREV_WASP(ah) && ar9300_rx_gain_index_get(ah) == 2) {
312176bd547bSAdrian Chadd #define REG_WRITE(_reg,_val)    *((volatile u_int32_t *)(_reg)) = (_val);
312276bd547bSAdrian Chadd #define REG_READ(_reg)          *((volatile u_int32_t *)(_reg))
312376bd547bSAdrian Chadd         u_int32_t val;
312476bd547bSAdrian Chadd         /* B8040000:  bit[0]=0, bit[3]=0; */
312576bd547bSAdrian Chadd         val = REG_READ(0xB8040000);
312676bd547bSAdrian Chadd         val &= 0xfffffff6;
312776bd547bSAdrian Chadd         REG_WRITE(0xB8040000, val);
312876bd547bSAdrian Chadd         /* B804002c:  bit[31:24]=0x2e; bit[7:0]=0x2f; */
312976bd547bSAdrian Chadd         val = REG_READ(0xB804002c);
313076bd547bSAdrian Chadd         val &= 0x00ffff00;
313176bd547bSAdrian Chadd         val |= 0x2e00002f;
313276bd547bSAdrian Chadd         REG_WRITE(0xB804002c, val);
313376bd547bSAdrian Chadd         /* B804006c:  bit[1]=1; */
313476bd547bSAdrian Chadd         val = REG_READ(0xB804006c);
313576bd547bSAdrian Chadd         val |= 0x2;
313676bd547bSAdrian Chadd         REG_WRITE(0xB804006c, val);
313776bd547bSAdrian Chadd #undef REG_READ
313876bd547bSAdrian Chadd #undef REG_WRITE
313976bd547bSAdrian Chadd     }
314076bd547bSAdrian Chadd 
314176bd547bSAdrian Chadd 
314276bd547bSAdrian Chadd     /* Write txgain Array Parameters */
314327e2ad46SAdrian Chadd     if (AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
314476bd547bSAdrian Chadd         REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_txgaintable_index,
314576bd547bSAdrian Chadd             reg_writes);
314676bd547bSAdrian Chadd     }else{
314776bd547bSAdrian Chadd         REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_index, reg_writes);
314876bd547bSAdrian Chadd     }
314976bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Tx Gain programming\n");
315076bd547bSAdrian Chadd 
315176bd547bSAdrian Chadd 
315276bd547bSAdrian Chadd     /* For 5GHz channels requiring Fast Clock, apply different modal values */
315376bd547bSAdrian Chadd     if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {
315476bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET,
315576bd547bSAdrian Chadd             "%s: Fast clock enabled, use special ini values\n", __func__);
315676bd547bSAdrian Chadd         REG_WRITE_ARRAY(&ahp->ah_ini_modes_additional, modes_index, reg_writes);
315776bd547bSAdrian Chadd     }
315876bd547bSAdrian Chadd 
315976bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
316076bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET,
316176bd547bSAdrian Chadd             "%s: use xtal ini for AH9300(ah)->clk_25mhz: %d\n",
316276bd547bSAdrian Chadd             __func__, AH9300(ah)->clk_25mhz);
316376bd547bSAdrian Chadd         REG_WRITE_ARRAY(
316476bd547bSAdrian Chadd             &ahp->ah_ini_modes_additional, 1/*modes_index*/, reg_writes);
316576bd547bSAdrian Chadd     }
316676bd547bSAdrian Chadd 
316776bd547bSAdrian Chadd     if (AR_SREV_WASP(ah) && (AH9300(ah)->clk_25mhz == 0)) {
316876bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Apply 40MHz ini settings\n", __func__);
316976bd547bSAdrian Chadd         REG_WRITE_ARRAY(
317076bd547bSAdrian Chadd             &ahp->ah_ini_modes_additional_40mhz, 1/*modesIndex*/, reg_writes);
317176bd547bSAdrian Chadd     }
317276bd547bSAdrian Chadd 
3173e113789bSAdrian Chadd     /* Handle Japan Channel 14 channel spreading */
3174e113789bSAdrian Chadd     if (2484 == ichan->channel) {
317576bd547bSAdrian Chadd         ar9300_prog_ini(ah, &ahp->ah_ini_japan2484, 1);
317676bd547bSAdrian Chadd     }
317776bd547bSAdrian Chadd 
317876bd547bSAdrian Chadd #if 0
3179615a867fSAdrian Chadd     /* XXX TODO! */
3180615a867fSAdrian Chadd     if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) {
318176bd547bSAdrian Chadd         ar9300_prog_ini(ah, &ahp->ah_ini_BTCOEX_MAX_TXPWR, 1);
318276bd547bSAdrian Chadd     }
318376bd547bSAdrian Chadd #endif
318476bd547bSAdrian Chadd 
318576bd547bSAdrian Chadd     /* Override INI with chip specific configuration */
318676bd547bSAdrian Chadd     ar9300_override_ini(ah, chan);
318776bd547bSAdrian Chadd 
318876bd547bSAdrian Chadd     /* Setup 11n MAC/Phy mode registers */
318976bd547bSAdrian Chadd     ar9300_set_11n_regs(ah, chan, macmode);
319076bd547bSAdrian Chadd 
319176bd547bSAdrian Chadd     /*
319276bd547bSAdrian Chadd      * Moved ar9300_init_chain_masks() here to ensure the swap bit is set before
319376bd547bSAdrian Chadd      * the pdadc table is written.  Swap must occur before any radio dependent
319476bd547bSAdrian Chadd      * replicated register access.  The pdadc curve addressing in particular
319576bd547bSAdrian Chadd      * depends on the consistent setting of the swap bit.
319676bd547bSAdrian Chadd      */
319776bd547bSAdrian Chadd     ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask);
319876bd547bSAdrian Chadd 
319976bd547bSAdrian Chadd     /*
320076bd547bSAdrian Chadd      * Setup the transmit power values.
320176bd547bSAdrian Chadd      *
320276bd547bSAdrian Chadd      * After the public to private hal channel mapping, ichan contains the
320376bd547bSAdrian Chadd      * valid regulatory power value.
320476bd547bSAdrian Chadd      * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan.
320576bd547bSAdrian Chadd      */
3206e113789bSAdrian Chadd     status = ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan,
320776bd547bSAdrian Chadd              ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan),
320876bd547bSAdrian Chadd              ath_hal_get_twice_max_regpower(ahpriv, ichan, chan),
3209e113789bSAdrian Chadd              AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit));
321076bd547bSAdrian Chadd     if (status != HAL_OK) {
321176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,
321276bd547bSAdrian Chadd             "%s: error init'ing transmit power\n", __func__);
321376bd547bSAdrian Chadd         return HAL_EIO;
321476bd547bSAdrian Chadd     }
321576bd547bSAdrian Chadd 
321676bd547bSAdrian Chadd 
321776bd547bSAdrian Chadd     return HAL_OK;
321876bd547bSAdrian Chadd #undef N
321976bd547bSAdrian Chadd }
322076bd547bSAdrian Chadd 
322176bd547bSAdrian Chadd /* ar9300_is_cal_supp
322276bd547bSAdrian Chadd  * Determine if calibration is supported by device and channel flags
322376bd547bSAdrian Chadd  */
322476bd547bSAdrian Chadd inline static HAL_BOOL
ar9300_is_cal_supp(struct ath_hal * ah,const struct ieee80211_channel * chan,HAL_CAL_TYPES cal_type)3225e113789bSAdrian Chadd ar9300_is_cal_supp(struct ath_hal *ah, const struct ieee80211_channel *chan,
322676bd547bSAdrian Chadd     HAL_CAL_TYPES cal_type)
322776bd547bSAdrian Chadd {
322876bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
322976bd547bSAdrian Chadd     HAL_BOOL retval = AH_FALSE;
323076bd547bSAdrian Chadd 
323176bd547bSAdrian Chadd     switch (cal_type & ahp->ah_supp_cals) {
323276bd547bSAdrian Chadd     case IQ_MISMATCH_CAL:
323376bd547bSAdrian Chadd         /* Run IQ Mismatch for non-CCK only */
3234e113789bSAdrian Chadd         if (!IEEE80211_IS_CHAN_B(chan)) {
323576bd547bSAdrian Chadd             retval = AH_TRUE;
323676bd547bSAdrian Chadd         }
323776bd547bSAdrian Chadd         break;
323876bd547bSAdrian Chadd     case TEMP_COMP_CAL:
323976bd547bSAdrian Chadd         retval = AH_TRUE;
324076bd547bSAdrian Chadd         break;
324176bd547bSAdrian Chadd     }
324276bd547bSAdrian Chadd 
324376bd547bSAdrian Chadd     return retval;
324476bd547bSAdrian Chadd }
324576bd547bSAdrian Chadd 
324676bd547bSAdrian Chadd 
324776bd547bSAdrian Chadd #if 0
324876bd547bSAdrian Chadd /* ar9285_pa_cal
324976bd547bSAdrian Chadd  * PA Calibration for Kite 1.1 and later versions of Kite.
325076bd547bSAdrian Chadd  * - from system's team.
325176bd547bSAdrian Chadd  */
325276bd547bSAdrian Chadd static inline void
325376bd547bSAdrian Chadd ar9285_pa_cal(struct ath_hal *ah)
325476bd547bSAdrian Chadd {
325576bd547bSAdrian Chadd     u_int32_t reg_val;
325676bd547bSAdrian Chadd     int i, lo_gn, offs_6_1, offs_0;
325776bd547bSAdrian Chadd     u_int8_t reflo;
325876bd547bSAdrian Chadd     u_int32_t phy_test2_reg_val, phy_adc_ctl_reg_val;
325976bd547bSAdrian Chadd     u_int32_t an_top2_reg_val, phy_tst_dac_reg_val;
326076bd547bSAdrian Chadd 
326176bd547bSAdrian Chadd 
326276bd547bSAdrian Chadd     /* Kite 1.1 WAR for Bug 35666
326376bd547bSAdrian Chadd      * Increase the LDO value to 1.28V before accessing analog Reg */
326476bd547bSAdrian Chadd     if (AR_SREV_KITE_11(ah)) {
326576bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14) );
326676bd547bSAdrian Chadd     }
326776bd547bSAdrian Chadd     an_top2_reg_val = OS_REG_READ(ah, AR9285_AN_TOP2);
326876bd547bSAdrian Chadd 
326976bd547bSAdrian Chadd     /* set pdv2i pdrxtxbb */
327076bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1);
327176bd547bSAdrian Chadd     reg_val |= ((0x1 << 5) | (0x1 << 7));
327276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val);
327376bd547bSAdrian Chadd 
327476bd547bSAdrian Chadd     /* clear pwddb */
327576bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G7);
327676bd547bSAdrian Chadd     reg_val &= 0xfffffffd;
327776bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G7, reg_val);
327876bd547bSAdrian Chadd 
327976bd547bSAdrian Chadd     /* clear enpacal */
328076bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);
328176bd547bSAdrian Chadd     reg_val &= 0xfffff7ff;
328276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);
328376bd547bSAdrian Chadd 
328476bd547bSAdrian Chadd     /* set offcal */
328576bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2);
328676bd547bSAdrian Chadd     reg_val |= (0x1 << 12);
328776bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val);
328876bd547bSAdrian Chadd 
328976bd547bSAdrian Chadd     /* set pdpadrv1=pdpadrv2=pdpaout=1 */
329076bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);
329176bd547bSAdrian Chadd     reg_val |= (0x7 << 23);
329276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);
329376bd547bSAdrian Chadd 
329476bd547bSAdrian Chadd     /* Read back reflo, increase it by 1 and write it. */
329576bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
329676bd547bSAdrian Chadd     reflo = ((reg_val >> 26) & 0x7);
329776bd547bSAdrian Chadd 
329876bd547bSAdrian Chadd     if (reflo < 0x7) {
329976bd547bSAdrian Chadd         reflo++;
330076bd547bSAdrian Chadd     }
330176bd547bSAdrian Chadd     reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26));
330276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
330376bd547bSAdrian Chadd 
330476bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
330576bd547bSAdrian Chadd     reflo = ((reg_val >> 26) & 0x7);
330676bd547bSAdrian Chadd 
330776bd547bSAdrian Chadd     /* use TX single carrier to transmit
330876bd547bSAdrian Chadd      * dac const
330976bd547bSAdrian Chadd      * reg. 15
331076bd547bSAdrian Chadd      */
331176bd547bSAdrian Chadd     phy_tst_dac_reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST);
331276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, ((0x7ff << 11) | 0x7ff));
331376bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST);
331476bd547bSAdrian Chadd 
331576bd547bSAdrian Chadd     /* source is dac const
331676bd547bSAdrian Chadd      * reg. 2
331776bd547bSAdrian Chadd      */
331876bd547bSAdrian Chadd     phy_test2_reg_val = OS_REG_READ(ah, AR_PHY_TEST2);
331976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_TEST2, ((0x1 << 7) | (0x1 << 1)));
332076bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR_PHY_TEST2);
332176bd547bSAdrian Chadd 
332276bd547bSAdrian Chadd     /* set dac on
332376bd547bSAdrian Chadd      * reg. 11
332476bd547bSAdrian Chadd      */
332576bd547bSAdrian Chadd     phy_adc_ctl_reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL);
332676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_ADC_CTL, 0x80008000);
332776bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL);
332876bd547bSAdrian Chadd 
332976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_TOP2, (0x1 << 27) | (0x1 << 17) | (0x1 << 16) |
333076bd547bSAdrian Chadd               (0x1 << 14) | (0x1 << 12) | (0x1 << 11) |
333176bd547bSAdrian Chadd               (0x1 << 7) | (0x1 << 5));
333276bd547bSAdrian Chadd 
333376bd547bSAdrian Chadd     OS_DELAY(10); /* 10 usec */
333476bd547bSAdrian Chadd 
333576bd547bSAdrian Chadd     /* clear off[6:0] */
333676bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);
333776bd547bSAdrian Chadd     reg_val &= 0xfc0fffff;
333876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);
333976bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
334076bd547bSAdrian Chadd     reg_val &= 0xfdffffff;
334176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
334276bd547bSAdrian Chadd 
334376bd547bSAdrian Chadd     offs_6_1 = 0;
334476bd547bSAdrian Chadd     for (i = 6; i > 0; i--) {
334576bd547bSAdrian Chadd         /* sef off[$k]==1 */
334676bd547bSAdrian Chadd         reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);
334776bd547bSAdrian Chadd         reg_val &= 0xfc0fffff;
334876bd547bSAdrian Chadd         reg_val = reg_val | (0x1 << (19 + i)) | ((offs_6_1) << 20);
334976bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);
335076bd547bSAdrian Chadd         lo_gn = (OS_REG_READ(ah, AR9285_AN_RF2G9)) & 0x1;
335176bd547bSAdrian Chadd         offs_6_1 = offs_6_1 | (lo_gn << (i - 1));
335276bd547bSAdrian Chadd     }
335376bd547bSAdrian Chadd 
335476bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);
335576bd547bSAdrian Chadd     reg_val &= 0xfc0fffff;
335676bd547bSAdrian Chadd     reg_val = reg_val | ((offs_6_1 - 1) << 20);
335776bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);
335876bd547bSAdrian Chadd 
335976bd547bSAdrian Chadd     /* set off_0=1; */
336076bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
336176bd547bSAdrian Chadd     reg_val &= 0xfdffffff;
336276bd547bSAdrian Chadd     reg_val = reg_val | (0x1 << 25);
336376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
336476bd547bSAdrian Chadd 
336576bd547bSAdrian Chadd     lo_gn = OS_REG_READ(ah, AR9285_AN_RF2G9) & 0x1;
336676bd547bSAdrian Chadd     offs_0 = lo_gn;
336776bd547bSAdrian Chadd 
336876bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
336976bd547bSAdrian Chadd     reg_val &= 0xfdffffff;
337076bd547bSAdrian Chadd     reg_val = reg_val | (offs_0 << 25);
337176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
337276bd547bSAdrian Chadd 
337376bd547bSAdrian Chadd     /* clear pdv2i */
337476bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1);
337576bd547bSAdrian Chadd     reg_val &= 0xffffff5f;
337676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val);
337776bd547bSAdrian Chadd 
337876bd547bSAdrian Chadd     /* set enpacal */
337976bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);
338076bd547bSAdrian Chadd     reg_val |= (0x1 << 11);
338176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);
338276bd547bSAdrian Chadd 
338376bd547bSAdrian Chadd     /* clear offcal */
338476bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2);
338576bd547bSAdrian Chadd     reg_val &= 0xffffefff;
338676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val);
338776bd547bSAdrian Chadd 
338876bd547bSAdrian Chadd     /* set pdpadrv1=pdpadrv2=pdpaout=0 */
338976bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);
339076bd547bSAdrian Chadd     reg_val &= 0xfc7fffff;
339176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);
339276bd547bSAdrian Chadd 
339376bd547bSAdrian Chadd     /* Read back reflo, decrease it by 1 and write it. */
339476bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
339576bd547bSAdrian Chadd     reflo = (reg_val >> 26) & 0x7;
339676bd547bSAdrian Chadd     if (reflo) {
339776bd547bSAdrian Chadd         reflo--;
339876bd547bSAdrian Chadd     }
339976bd547bSAdrian Chadd     reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26));
340076bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);
340176bd547bSAdrian Chadd     reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);
340276bd547bSAdrian Chadd     reflo = (reg_val >> 26) & 0x7;
340376bd547bSAdrian Chadd 
340476bd547bSAdrian Chadd     /* write back registers */
340576bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, phy_tst_dac_reg_val);
340676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_TEST2, phy_test2_reg_val);
340776bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_ADC_CTL, phy_adc_ctl_reg_val);
340876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR9285_AN_TOP2, an_top2_reg_val);
340976bd547bSAdrian Chadd 
341076bd547bSAdrian Chadd     /* Kite 1.1 WAR for Bug 35666
341176bd547bSAdrian Chadd      * Decrease the LDO value back to 1.20V */
341276bd547bSAdrian Chadd     if (AR_SREV_KITE_11(ah)) {
341376bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
341476bd547bSAdrian Chadd     }
341576bd547bSAdrian Chadd }
341676bd547bSAdrian Chadd #endif
341776bd547bSAdrian Chadd 
341876bd547bSAdrian Chadd /* ar9300_run_init_cals
341976bd547bSAdrian Chadd  * Runs non-periodic calibrations
342076bd547bSAdrian Chadd  */
342176bd547bSAdrian Chadd inline static HAL_BOOL
ar9300_run_init_cals(struct ath_hal * ah,int init_cal_count)342276bd547bSAdrian Chadd ar9300_run_init_cals(struct ath_hal *ah, int init_cal_count)
342376bd547bSAdrian Chadd {
342476bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
342576bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL ichan; /* bogus */
342676bd547bSAdrian Chadd     HAL_BOOL is_cal_done;
342776bd547bSAdrian Chadd     HAL_CAL_LIST *curr_cal;
3428e113789bSAdrian Chadd     const HAL_PERCAL_DATA *cal_data;
342976bd547bSAdrian Chadd     int i;
343076bd547bSAdrian Chadd 
343176bd547bSAdrian Chadd     curr_cal = ahp->ah_cal_list_curr;
343276bd547bSAdrian Chadd     if (curr_cal == AH_NULL) {
343376bd547bSAdrian Chadd         return AH_FALSE;
343476bd547bSAdrian Chadd     }
3435e113789bSAdrian Chadd     cal_data = curr_cal->cal_data;
3436e113789bSAdrian Chadd     ichan.calValid = 0;
343776bd547bSAdrian Chadd 
343876bd547bSAdrian Chadd     for (i = 0; i < init_cal_count; i++) {
343976bd547bSAdrian Chadd         /* Reset this Cal */
344076bd547bSAdrian Chadd         ar9300_reset_calibration(ah, curr_cal);
344176bd547bSAdrian Chadd         /* Poll for offset calibration complete */
344276bd547bSAdrian Chadd         if (!ath_hal_wait(
3443e113789bSAdrian Chadd                 ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL, 0))
344476bd547bSAdrian Chadd         {
344576bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
344676bd547bSAdrian Chadd                 "%s: Cal %d failed to complete in 100ms.\n",
344776bd547bSAdrian Chadd                 __func__, curr_cal->cal_data->cal_type);
344876bd547bSAdrian Chadd             /* Re-initialize list pointers for periodic cals */
344976bd547bSAdrian Chadd             ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr
345076bd547bSAdrian Chadd                 = AH_NULL;
345176bd547bSAdrian Chadd             return AH_FALSE;
345276bd547bSAdrian Chadd         }
345376bd547bSAdrian Chadd         /* Run this cal */
345476bd547bSAdrian Chadd         ar9300_per_calibration(
345576bd547bSAdrian Chadd             ah, &ichan, ahp->ah_rx_chainmask, curr_cal, &is_cal_done);
345676bd547bSAdrian Chadd         if (is_cal_done == AH_FALSE) {
345776bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
345876bd547bSAdrian Chadd                 "%s: Not able to run Init Cal %d.\n", __func__,
345976bd547bSAdrian Chadd                 curr_cal->cal_data->cal_type);
346076bd547bSAdrian Chadd         }
346176bd547bSAdrian Chadd         if (curr_cal->cal_next) {
346276bd547bSAdrian Chadd             curr_cal = curr_cal->cal_next;
346376bd547bSAdrian Chadd         }
346476bd547bSAdrian Chadd     }
346576bd547bSAdrian Chadd 
346676bd547bSAdrian Chadd     /* Re-initialize list pointers for periodic cals */
346776bd547bSAdrian Chadd     ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL;
346876bd547bSAdrian Chadd     return AH_TRUE;
346976bd547bSAdrian Chadd }
347076bd547bSAdrian Chadd 
347176bd547bSAdrian Chadd #if 0
347276bd547bSAdrian Chadd static void
347376bd547bSAdrian Chadd ar9300_tx_carrier_leak_war(struct ath_hal *ah)
347476bd547bSAdrian Chadd {
347576bd547bSAdrian Chadd     unsigned long tx_gain_table_max;
347676bd547bSAdrian Chadd     unsigned long reg_bb_cl_map_0_b0 = 0xffffffff;
347776bd547bSAdrian Chadd     unsigned long reg_bb_cl_map_1_b0 = 0xffffffff;
347876bd547bSAdrian Chadd     unsigned long reg_bb_cl_map_2_b0 = 0xffffffff;
347976bd547bSAdrian Chadd     unsigned long reg_bb_cl_map_3_b0 = 0xffffffff;
348076bd547bSAdrian Chadd     unsigned long tx_gain, cal_run = 0;
348176bd547bSAdrian Chadd     unsigned long cal_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];
348276bd547bSAdrian Chadd     unsigned long cal_gain_index[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];
348376bd547bSAdrian Chadd     unsigned long new_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];
348476bd547bSAdrian Chadd     int i, j;
348576bd547bSAdrian Chadd 
348676bd547bSAdrian Chadd     OS_MEMSET(new_gain, 0, sizeof(new_gain));
348776bd547bSAdrian Chadd     /*printf("     Running TxCarrierLeakWAR\n");*/
348876bd547bSAdrian Chadd 
348976bd547bSAdrian Chadd     /* process tx gain table, we use cl_map_hw_gen=0. */
349076bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_MAP_HW_GEN, 0);
349176bd547bSAdrian Chadd 
349276bd547bSAdrian Chadd 	//the table we used is txbb_gc[2:0], 1dB[2:1].
349376bd547bSAdrian Chadd     tx_gain_table_max = OS_REG_READ_FIELD(ah,
349476bd547bSAdrian Chadd         AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX);
349576bd547bSAdrian Chadd 
349676bd547bSAdrian Chadd     for (i = 0; i <= tx_gain_table_max; i++) {
349776bd547bSAdrian Chadd         tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4);
349876bd547bSAdrian Chadd         cal_gain[i] = (((tx_gain >> 5)& 0x7) << 2) |
349976bd547bSAdrian Chadd             (((tx_gain >> 1) & 0x3) << 0);
350076bd547bSAdrian Chadd         if (i == 0) {
350176bd547bSAdrian Chadd             cal_gain_index[i] = cal_run;
350276bd547bSAdrian Chadd             new_gain[i] = 1;
350376bd547bSAdrian Chadd             cal_run++;
350476bd547bSAdrian Chadd         } else {
350576bd547bSAdrian Chadd             new_gain[i] = 1;
350676bd547bSAdrian Chadd             for (j = 0; j < i; j++) {
350776bd547bSAdrian Chadd                 /*
350876bd547bSAdrian Chadd                 printf("i=%d, j=%d cal_gain[$i]=0x%04x\n", i, j, cal_gain[i]);
350976bd547bSAdrian Chadd                  */
351076bd547bSAdrian Chadd                 if (new_gain[i]) {
351176bd547bSAdrian Chadd                     if ((cal_gain[i] != cal_gain[j])) {
351276bd547bSAdrian Chadd                         new_gain[i] = 1;
351376bd547bSAdrian Chadd                     } else {
351476bd547bSAdrian Chadd                         /* if old gain found, use old cal_run value. */
351576bd547bSAdrian Chadd                         new_gain[i] = 0;
351676bd547bSAdrian Chadd                         cal_gain_index[i] = cal_gain_index[j];
351776bd547bSAdrian Chadd                     }
351876bd547bSAdrian Chadd                 }
351976bd547bSAdrian Chadd             }
352076bd547bSAdrian Chadd             /* if new gain found, increase cal_run */
352176bd547bSAdrian Chadd             if (new_gain[i] == 1) {
352276bd547bSAdrian Chadd                 cal_gain_index[i] = cal_run;
352376bd547bSAdrian Chadd                 cal_run++;
352476bd547bSAdrian Chadd             }
352576bd547bSAdrian Chadd         }
352676bd547bSAdrian Chadd 
352776bd547bSAdrian Chadd         reg_bb_cl_map_0_b0 = (reg_bb_cl_map_0_b0 & ~(0x1 << i)) |
352876bd547bSAdrian Chadd             ((cal_gain_index[i] >> 0 & 0x1) << i);
352976bd547bSAdrian Chadd         reg_bb_cl_map_1_b0 = (reg_bb_cl_map_1_b0 & ~(0x1 << i)) |
353076bd547bSAdrian Chadd             ((cal_gain_index[i] >> 1 & 0x1) << i);
353176bd547bSAdrian Chadd         reg_bb_cl_map_2_b0 = (reg_bb_cl_map_2_b0 & ~(0x1 << i)) |
353276bd547bSAdrian Chadd             ((cal_gain_index[i] >> 2 & 0x1) << i);
353376bd547bSAdrian Chadd         reg_bb_cl_map_3_b0 = (reg_bb_cl_map_3_b0 & ~(0x1 << i)) |
353476bd547bSAdrian Chadd             ((cal_gain_index[i] >> 3 & 0x1) << i);
353576bd547bSAdrian Chadd 
353676bd547bSAdrian Chadd         /*
353776bd547bSAdrian Chadd         printf("i=%2d, cal_gain[$i]= 0x%04x, cal_run= %d, "
353876bd547bSAdrian Chadd             "cal_gain_index[i]=%d, new_gain[i] = %d\n",
353976bd547bSAdrian Chadd             i, cal_gain[i], cal_run, cal_gain_index[i], new_gain[i]);
354076bd547bSAdrian Chadd          */
354176bd547bSAdrian Chadd     }
354276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B0, reg_bb_cl_map_0_b0);
354376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B0, reg_bb_cl_map_1_b0);
354476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B0, reg_bb_cl_map_2_b0);
354576bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B0, reg_bb_cl_map_3_b0);
354676bd547bSAdrian Chadd     if (AR_SREV_WASP(ah)) {
354776bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B1, reg_bb_cl_map_0_b0);
354876bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B1, reg_bb_cl_map_1_b0);
354976bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B1, reg_bb_cl_map_2_b0);
355076bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B1, reg_bb_cl_map_3_b0);
355176bd547bSAdrian Chadd     }
355276bd547bSAdrian Chadd }
355376bd547bSAdrian Chadd #endif
355476bd547bSAdrian Chadd 
355576bd547bSAdrian Chadd 
355676bd547bSAdrian Chadd static inline void
ar9300_invalidate_saved_cals(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * ichan)355776bd547bSAdrian Chadd ar9300_invalidate_saved_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
355876bd547bSAdrian Chadd {
355976bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
356076bd547bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse &
356176bd547bSAdrian Chadd         ATH_CAL_REUSE_REDO_IN_FULL_RESET)
356276bd547bSAdrian Chadd     {
356376bd547bSAdrian Chadd         ichan->one_time_txiqcal_done = AH_FALSE;
356476bd547bSAdrian Chadd         ichan->one_time_txclcal_done = AH_FALSE;
356576bd547bSAdrian Chadd     }
356676bd547bSAdrian Chadd #endif
356776bd547bSAdrian Chadd }
356876bd547bSAdrian Chadd 
356976bd547bSAdrian Chadd static inline HAL_BOOL
ar9300_restore_rtt_cals(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * ichan)357076bd547bSAdrian Chadd ar9300_restore_rtt_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
357176bd547bSAdrian Chadd {
357276bd547bSAdrian Chadd     HAL_BOOL restore_status = AH_FALSE;
357376bd547bSAdrian Chadd 
357476bd547bSAdrian Chadd     return restore_status;
357576bd547bSAdrian Chadd }
357676bd547bSAdrian Chadd 
357776bd547bSAdrian Chadd /* ar9300_init_cal
357876bd547bSAdrian Chadd  * Initialize Calibration infrastructure
357976bd547bSAdrian Chadd  */
358076bd547bSAdrian Chadd static inline HAL_BOOL
ar9300_init_cal_internal(struct ath_hal * ah,struct ieee80211_channel * chan,HAL_CHANNEL_INTERNAL * ichan,HAL_BOOL enable_rtt,HAL_BOOL do_rtt_cal,HAL_BOOL skip_if_none,HAL_BOOL apply_last_iqcorr)3581e113789bSAdrian Chadd ar9300_init_cal_internal(struct ath_hal *ah, struct ieee80211_channel *chan,
3582e113789bSAdrian Chadd                          HAL_CHANNEL_INTERNAL *ichan,
3583e113789bSAdrian Chadd                          HAL_BOOL enable_rtt, HAL_BOOL do_rtt_cal, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr)
358476bd547bSAdrian Chadd {
358576bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
358676bd547bSAdrian Chadd     HAL_BOOL txiqcal_success_flag = AH_FALSE;
358776bd547bSAdrian Chadd     HAL_BOOL cal_done = AH_FALSE;
358876bd547bSAdrian Chadd     int iqcal_idx = 0;
358976bd547bSAdrian Chadd     HAL_BOOL do_sep_iq_cal = AH_FALSE;
359076bd547bSAdrian Chadd     HAL_BOOL do_agc_cal = do_rtt_cal;
359176bd547bSAdrian Chadd     HAL_BOOL is_cal_reusable = AH_TRUE;
359276bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
359376bd547bSAdrian Chadd     HAL_BOOL      cal_reuse_enable = AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse &
359476bd547bSAdrian Chadd                                  ATH_CAL_REUSE_ENABLE;
359576bd547bSAdrian Chadd     HAL_BOOL      clc_success = AH_FALSE;
359676bd547bSAdrian Chadd     int32_t   ch_idx, j, cl_tab_reg;
359776bd547bSAdrian Chadd     u_int32_t BB_cl_tab_entry = MAX_BB_CL_TABLE_ENTRY;
359876bd547bSAdrian Chadd     u_int32_t BB_cl_tab_b[AR9300_MAX_CHAINS] = {
359976bd547bSAdrian Chadd                     AR_PHY_CL_TAB_0,
360076bd547bSAdrian Chadd                     AR_PHY_CL_TAB_1,
360176bd547bSAdrian Chadd                     AR_PHY_CL_TAB_2
360276bd547bSAdrian Chadd                 };
360376bd547bSAdrian Chadd #endif
360476bd547bSAdrian Chadd 
360576bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
360676bd547bSAdrian Chadd         /* Hornet: 1 x 1 */
360776bd547bSAdrian Chadd         ahp->ah_rx_cal_chainmask = 0x1;
360876bd547bSAdrian Chadd         ahp->ah_tx_cal_chainmask = 0x1;
360927e2ad46SAdrian Chadd     } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(ah)) {
361076bd547bSAdrian Chadd         /* Wasp/Jupiter: 2 x 2 */
361176bd547bSAdrian Chadd         ahp->ah_rx_cal_chainmask = 0x3;
361276bd547bSAdrian Chadd         ahp->ah_tx_cal_chainmask = 0x3;
361376bd547bSAdrian Chadd     } else {
361476bd547bSAdrian Chadd         /*
361576bd547bSAdrian Chadd          * Osprey needs to be configured for the correct chain mode
361676bd547bSAdrian Chadd          * before running AGC/TxIQ cals.
361776bd547bSAdrian Chadd          */
361876bd547bSAdrian Chadd         if (ahp->ah_enterprise_mode & AR_ENT_OTP_CHAIN2_DISABLE) {
361976bd547bSAdrian Chadd             /* chain 2 disabled - 2 chain mode */
362076bd547bSAdrian Chadd             ahp->ah_rx_cal_chainmask = 0x3;
362176bd547bSAdrian Chadd             ahp->ah_tx_cal_chainmask = 0x3;
362276bd547bSAdrian Chadd         } else {
362376bd547bSAdrian Chadd             ahp->ah_rx_cal_chainmask = 0x7;
362476bd547bSAdrian Chadd             ahp->ah_tx_cal_chainmask = 0x7;
362576bd547bSAdrian Chadd         }
362676bd547bSAdrian Chadd     }
362776bd547bSAdrian Chadd         ar9300_init_chain_masks(ah, ahp->ah_rx_cal_chainmask, ahp->ah_tx_cal_chainmask);
362876bd547bSAdrian Chadd 
362976bd547bSAdrian Chadd 
363076bd547bSAdrian Chadd     if (ahp->tx_cl_cal_enable) {
363176bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
363276bd547bSAdrian Chadd         /* disable Carrie Leak or set do_agc_cal accordingly */
363376bd547bSAdrian Chadd         if (cal_reuse_enable && ichan->one_time_txclcal_done)
363476bd547bSAdrian Chadd         {
363576bd547bSAdrian Chadd             OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
363676bd547bSAdrian Chadd         } else
363776bd547bSAdrian Chadd #endif /* ATH_SUPPORT_CAL_REUSE */
363876bd547bSAdrian Chadd         {
363976bd547bSAdrian Chadd             OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
364076bd547bSAdrian Chadd             do_agc_cal = AH_TRUE;
364176bd547bSAdrian Chadd         }
364276bd547bSAdrian Chadd     }
364376bd547bSAdrian Chadd 
364476bd547bSAdrian Chadd     /* Do Tx IQ Calibration here for osprey hornet and wasp */
364576bd547bSAdrian Chadd     /* XXX: For initial wasp bringup - check and enable this */
364676bd547bSAdrian Chadd     /* EV 74233: Tx IQ fails to complete for half/quarter rates */
3647e113789bSAdrian Chadd     if (!(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) {
364876bd547bSAdrian Chadd         if (ahp->tx_iq_cal_enable) {
364976bd547bSAdrian Chadd             /* this should be eventually moved to INI file */
365076bd547bSAdrian Chadd             OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah),
365176bd547bSAdrian Chadd                 AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT);
365276bd547bSAdrian Chadd 
365376bd547bSAdrian Chadd             /*
365476bd547bSAdrian Chadd              * For poseidon and later chips,
365576bd547bSAdrian Chadd              * Tx IQ cal HW run will be a part of AGC calibration
365676bd547bSAdrian Chadd              */
365776bd547bSAdrian Chadd             if (ahp->tx_iq_cal_during_agc_cal) {
365876bd547bSAdrian Chadd                 /*
365976bd547bSAdrian Chadd                  * txiqcal_success_flag always set to 1 to run
366076bd547bSAdrian Chadd                  *     ar9300_tx_iq_cal_post_proc
366176bd547bSAdrian Chadd                  * if following AGC cal passes
366276bd547bSAdrian Chadd                 */
366376bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
366476bd547bSAdrian Chadd                 if (!cal_reuse_enable || !ichan->one_time_txiqcal_done)
366576bd547bSAdrian Chadd                 {
366676bd547bSAdrian Chadd                     txiqcal_success_flag = AH_TRUE;
366776bd547bSAdrian Chadd                     OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),
366876bd547bSAdrian Chadd                         OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) |
366976bd547bSAdrian Chadd                         AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
367076bd547bSAdrian Chadd                 } else {
367176bd547bSAdrian Chadd                     OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),
367276bd547bSAdrian Chadd                         OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) &
367376bd547bSAdrian Chadd                         (~AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL));
367476bd547bSAdrian Chadd                 }
367576bd547bSAdrian Chadd #else
367676bd547bSAdrian Chadd 		if (OS_REG_READ_FIELD(ah,
367776bd547bSAdrian Chadd 					AR_PHY_TX_IQCAL_CONTROL_0(ah),
367876bd547bSAdrian Chadd 					AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)){
367976bd547bSAdrian Chadd 			if (apply_last_iqcorr == AH_TRUE) {
368076bd547bSAdrian Chadd 				OS_REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),
368176bd547bSAdrian Chadd 						AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
368276bd547bSAdrian Chadd 				txiqcal_success_flag = AH_FALSE;
368376bd547bSAdrian Chadd 			} else {
368476bd547bSAdrian Chadd 				txiqcal_success_flag = AH_TRUE;
368576bd547bSAdrian Chadd 			}
368676bd547bSAdrian Chadd 		}else{
368776bd547bSAdrian Chadd 			txiqcal_success_flag = AH_FALSE;
368876bd547bSAdrian Chadd 		}
368976bd547bSAdrian Chadd #endif
369076bd547bSAdrian Chadd                 if (txiqcal_success_flag) {
369176bd547bSAdrian Chadd                     do_agc_cal = AH_TRUE;
369276bd547bSAdrian Chadd                 }
369376bd547bSAdrian Chadd             } else
369476bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
369576bd547bSAdrian Chadd             if (!cal_reuse_enable || !ichan->one_time_txiqcal_done)
369676bd547bSAdrian Chadd #endif
369776bd547bSAdrian Chadd             {
369876bd547bSAdrian Chadd                 do_sep_iq_cal = AH_TRUE;
369976bd547bSAdrian Chadd                 do_agc_cal = AH_TRUE;
370076bd547bSAdrian Chadd             }
370176bd547bSAdrian Chadd         }
370276bd547bSAdrian Chadd     }
370376bd547bSAdrian Chadd 
370476bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
3705e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&
370676bd547bSAdrian Chadd         IS_CHAN_2GHZ(ichan) &&
370776bd547bSAdrian Chadd         (ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&
370876bd547bSAdrian Chadd         do_agc_cal &&
3709e113789bSAdrian Chadd         !(ah->ah_config.ath_hal_mci_config &
371076bd547bSAdrian Chadd         ATH_MCI_CONFIG_DISABLE_MCI_CAL))
371176bd547bSAdrian Chadd     {
371276bd547bSAdrian Chadd         u_int32_t payload[4] = {0, 0, 0, 0};
371376bd547bSAdrian Chadd 
371476bd547bSAdrian Chadd         /* Send CAL_REQ only when BT is AWAKE. */
371576bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_REQ 0x%X\n",
371676bd547bSAdrian Chadd             __func__, ahp->ah_mci_wlan_cal_seq);
371776bd547bSAdrian Chadd         MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_REQ);
371876bd547bSAdrian Chadd         payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_seq++;
371976bd547bSAdrian Chadd         ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);
372076bd547bSAdrian Chadd 
372176bd547bSAdrian Chadd         /* Wait BT_CAL_GRANT for 50ms */
372276bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_BT_COEX,
372376bd547bSAdrian Chadd             "(MCI) %s: Wait for BT_CAL_GRANT\n", __func__);
372476bd547bSAdrian Chadd         if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000))
372576bd547bSAdrian Chadd         {
372676bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_BT_COEX,
372776bd547bSAdrian Chadd                 "(MCI) %s: Got BT_CAL_GRANT.\n", __func__);
372876bd547bSAdrian Chadd         }
372976bd547bSAdrian Chadd         else {
373076bd547bSAdrian Chadd             is_cal_reusable = AH_FALSE;
373176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_BT_COEX,
373276bd547bSAdrian Chadd                 "(MCI) %s: BT is not responding.\n", __func__);
373376bd547bSAdrian Chadd         }
373476bd547bSAdrian Chadd     }
373576bd547bSAdrian Chadd #endif /* ATH_SUPPORT_MCI */
373676bd547bSAdrian Chadd 
373776bd547bSAdrian Chadd     if (do_sep_iq_cal)
373876bd547bSAdrian Chadd     {
373976bd547bSAdrian Chadd         /* enable Tx IQ Calibration HW for osprey/hornet/wasp */
374076bd547bSAdrian Chadd         txiqcal_success_flag = ar9300_tx_iq_cal_hw_run(ah);
374176bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
374276bd547bSAdrian Chadd         OS_DELAY(5);
374376bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
374476bd547bSAdrian Chadd     }
374576bd547bSAdrian Chadd #if 0
374676bd547bSAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {
374776bd547bSAdrian Chadd         ar9300_tx_carrier_leak_war(ah);
374876bd547bSAdrian Chadd     }
374976bd547bSAdrian Chadd #endif
375076bd547bSAdrian Chadd     /*
375176bd547bSAdrian Chadd      * Calibrate the AGC
375276bd547bSAdrian Chadd      *
375376bd547bSAdrian Chadd      * Tx IQ cal is a part of AGC cal for Jupiter/Poseidon, etc.
375476bd547bSAdrian Chadd      * please enable the bit of txiqcal_control_0[31] in INI file
375576bd547bSAdrian Chadd      * for Jupiter/Poseidon/etc.
375676bd547bSAdrian Chadd      */
375776bd547bSAdrian Chadd     if(!AR_SREV_SCORPION(ah)) {
375876bd547bSAdrian Chadd         if (do_agc_cal || !skip_if_none) {
375976bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
376076bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
376176bd547bSAdrian Chadd 
376276bd547bSAdrian Chadd             /* Poll for offset calibration complete */
376376bd547bSAdrian Chadd             cal_done = ath_hal_wait(ah,
3764e113789bSAdrian Chadd                     AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0);
376576bd547bSAdrian Chadd             if (!cal_done) {
376676bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
376776bd547bSAdrian Chadd                     "(FCS) CAL NOT DONE!!! - %d\n", ichan->channel);
376876bd547bSAdrian Chadd             }
376976bd547bSAdrian Chadd         } else {
377076bd547bSAdrian Chadd             cal_done = AH_TRUE;
377176bd547bSAdrian Chadd         }
377276bd547bSAdrian Chadd             /*
377376bd547bSAdrian Chadd              * Tx IQ cal post-processing in SW
377476bd547bSAdrian Chadd              * This part of code should be common to all chips,
377576bd547bSAdrian Chadd              * no chip specific code for Jupiter/Posdeion except for register names.
377676bd547bSAdrian Chadd              */
377776bd547bSAdrian Chadd             if (txiqcal_success_flag) {
37786ba04f0dSAdrian Chadd                 ar9300_tx_iq_cal_post_proc(ah,ichan, 1, 1,is_cal_reusable, AH_FALSE);
377976bd547bSAdrian Chadd             }
378076bd547bSAdrian Chadd     } else {
378176bd547bSAdrian Chadd         if (!txiqcal_success_flag) {
378276bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
378376bd547bSAdrian Chadd                 OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
378476bd547bSAdrian Chadd             if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
3785e113789bSAdrian Chadd                     0)) {
378676bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
378776bd547bSAdrian Chadd                     "%s: offset calibration failed to complete in 1ms; "
378876bd547bSAdrian Chadd                     "noisy environment?\n", __func__);
378976bd547bSAdrian Chadd                 return AH_FALSE;
379076bd547bSAdrian Chadd             }
379176bd547bSAdrian Chadd             if (apply_last_iqcorr == AH_TRUE) {
379276bd547bSAdrian Chadd                 ar9300_tx_iq_cal_post_proc(ah, ichan, 0, 0, is_cal_reusable, AH_TRUE);
379376bd547bSAdrian Chadd             }
379476bd547bSAdrian Chadd         } else {
379576bd547bSAdrian Chadd             for (iqcal_idx=0;iqcal_idx<MAXIQCAL;iqcal_idx++) {
379676bd547bSAdrian Chadd                 OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
379776bd547bSAdrian Chadd                     OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
379876bd547bSAdrian Chadd 
379976bd547bSAdrian Chadd                 /* Poll for offset calibration complete */
380076bd547bSAdrian Chadd                 if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL,
3801e113789bSAdrian Chadd                         AR_PHY_AGC_CONTROL_CAL, 0)) {
380276bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
380376bd547bSAdrian Chadd                         "%s: offset calibration failed to complete in 1ms; "
380476bd547bSAdrian Chadd                         "noisy environment?\n", __func__);
380576bd547bSAdrian Chadd                     return AH_FALSE;
380676bd547bSAdrian Chadd                 }
380776bd547bSAdrian Chadd                 /*
380876bd547bSAdrian Chadd                  * Tx IQ cal post-processing in SW
380976bd547bSAdrian Chadd                  * This part of code should be common to all chips,
381076bd547bSAdrian Chadd                  * no chip specific code for Jupiter/Posdeion except for register names.
381176bd547bSAdrian Chadd                  */
381276bd547bSAdrian Chadd                 ar9300_tx_iq_cal_post_proc(ah, ichan, iqcal_idx+1, MAXIQCAL, is_cal_reusable, AH_FALSE);
381376bd547bSAdrian Chadd             }
381476bd547bSAdrian Chadd        }
381576bd547bSAdrian Chadd     }
381676bd547bSAdrian Chadd 
381776bd547bSAdrian Chadd 
381876bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
3819e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&
382076bd547bSAdrian Chadd         IS_CHAN_2GHZ(ichan) &&
382176bd547bSAdrian Chadd         (ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&
382276bd547bSAdrian Chadd         do_agc_cal &&
3823e113789bSAdrian Chadd         !(ah->ah_config.ath_hal_mci_config &
382476bd547bSAdrian Chadd         ATH_MCI_CONFIG_DISABLE_MCI_CAL))
382576bd547bSAdrian Chadd     {
382676bd547bSAdrian Chadd         u_int32_t payload[4] = {0, 0, 0, 0};
382776bd547bSAdrian Chadd 
382876bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_DONE 0x%X\n",
382976bd547bSAdrian Chadd             __func__, ahp->ah_mci_wlan_cal_done);
383076bd547bSAdrian Chadd         MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
383176bd547bSAdrian Chadd         payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_done++;
383276bd547bSAdrian Chadd         ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);
383376bd547bSAdrian Chadd     }
383476bd547bSAdrian Chadd #endif /* ATH_SUPPORT_MCI */
383576bd547bSAdrian Chadd 
383676bd547bSAdrian Chadd 
383776bd547bSAdrian Chadd     if (!cal_done && !AR_SREV_SCORPION(ah) )
383876bd547bSAdrian Chadd     {
383976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
384076bd547bSAdrian Chadd             "%s: offset calibration failed to complete in 1ms; "
384176bd547bSAdrian Chadd             "noisy environment?\n", __func__);
384276bd547bSAdrian Chadd         return AH_FALSE;
384376bd547bSAdrian Chadd     }
384476bd547bSAdrian Chadd 
384576bd547bSAdrian Chadd #if 0
384676bd547bSAdrian Chadd      /* Beacon stuck fix, refer to EV 120056 */
384776bd547bSAdrian Chadd     if(IS_CHAN_2GHZ(chan) && AR_SREV_SCORPION(ah))
384876bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_TIMING5, OS_REG_READ(ah,AR_PHY_TIMING5) & ~AR_PHY_TIMING5_CYCPWR_THR1_ENABLE);
384976bd547bSAdrian Chadd #endif
385076bd547bSAdrian Chadd 
385176bd547bSAdrian Chadd #if 0
385276bd547bSAdrian Chadd     /* Do PA Calibration */
385376bd547bSAdrian Chadd     if (AR_SREV_KITE(ah) && AR_SREV_KITE_11_OR_LATER(ah)) {
385476bd547bSAdrian Chadd         ar9285_pa_cal(ah);
385576bd547bSAdrian Chadd     }
385676bd547bSAdrian Chadd #endif
385776bd547bSAdrian Chadd 
385876bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
385976bd547bSAdrian Chadd      if (ichan->one_time_txiqcal_done) {
386076bd547bSAdrian Chadd         ar9300_tx_iq_cal_apply(ah, ichan);
386176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
386276bd547bSAdrian Chadd             "(FCS) TXIQCAL applied - %d\n", ichan->channel);
386376bd547bSAdrian Chadd     }
386476bd547bSAdrian Chadd #endif /* ATH_SUPPORT_CAL_REUSE */
386576bd547bSAdrian Chadd 
386676bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
386776bd547bSAdrian Chadd     if (cal_reuse_enable && ahp->tx_cl_cal_enable)
386876bd547bSAdrian Chadd     {
386976bd547bSAdrian Chadd         clc_success = (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) &
387076bd547bSAdrian Chadd                   AR_PHY_AGC_CONTROL_CLC_SUCCESS) ? 1 : 0;
387176bd547bSAdrian Chadd 
387276bd547bSAdrian Chadd         if (ichan->one_time_txclcal_done)
387376bd547bSAdrian Chadd         {
387476bd547bSAdrian Chadd             /* reapply CL cal results */
387576bd547bSAdrian Chadd             for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {
387676bd547bSAdrian Chadd                 if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {
387776bd547bSAdrian Chadd                     continue;
387876bd547bSAdrian Chadd                 }
387976bd547bSAdrian Chadd                 cl_tab_reg = BB_cl_tab_b[ch_idx];
388076bd547bSAdrian Chadd                 for (j = 0; j < BB_cl_tab_entry; j++) {
388176bd547bSAdrian Chadd                     OS_REG_WRITE(ah, cl_tab_reg, ichan->tx_clcal[ch_idx][j]);
388211224884SEd Maste                     cl_tab_reg += 4;
388376bd547bSAdrian Chadd                 }
388476bd547bSAdrian Chadd             }
388576bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
388676bd547bSAdrian Chadd                 "(FCS) TX CL CAL applied - %d\n", ichan->channel);
388776bd547bSAdrian Chadd         }
388876bd547bSAdrian Chadd         else if (is_cal_reusable && clc_success) {
388976bd547bSAdrian Chadd             /* save CL cal results */
389076bd547bSAdrian Chadd             for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {
389176bd547bSAdrian Chadd                 if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {
389276bd547bSAdrian Chadd                     continue;
389376bd547bSAdrian Chadd                 }
389476bd547bSAdrian Chadd                 cl_tab_reg = BB_cl_tab_b[ch_idx];
389576bd547bSAdrian Chadd                 for (j = 0; j < BB_cl_tab_entry; j++) {
389676bd547bSAdrian Chadd                     ichan->tx_clcal[ch_idx][j] = OS_REG_READ(ah, cl_tab_reg);
389776bd547bSAdrian Chadd                     cl_tab_reg += 4;
389876bd547bSAdrian Chadd                 }
389976bd547bSAdrian Chadd             }
390076bd547bSAdrian Chadd             ichan->one_time_txclcal_done = AH_TRUE;
390176bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
390276bd547bSAdrian Chadd                 "(FCS) TX CL CAL saved - %d\n", ichan->channel);
390376bd547bSAdrian Chadd         }
390476bd547bSAdrian Chadd     }
390576bd547bSAdrian Chadd #endif /* ATH_SUPPORT_CAL_REUSE */
390676bd547bSAdrian Chadd 
390776bd547bSAdrian Chadd     /* Revert chainmasks to their original values before NF cal */
390876bd547bSAdrian Chadd     ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask);
390976bd547bSAdrian Chadd 
391076bd547bSAdrian Chadd #if !FIX_NOISE_FLOOR
391176bd547bSAdrian Chadd     /*
391276bd547bSAdrian Chadd      * Do NF calibration after DC offset and other CALs.
391376bd547bSAdrian Chadd      * Per system engineers, noise floor value can sometimes be 20 dB
391476bd547bSAdrian Chadd      * higher than normal value if DC offset and noise floor cal are
391576bd547bSAdrian Chadd      * triggered at the same time.
391676bd547bSAdrian Chadd      */
391776bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
391876bd547bSAdrian Chadd         OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
391976bd547bSAdrian Chadd #endif
392076bd547bSAdrian Chadd 
392176bd547bSAdrian Chadd     /* Initialize list pointers */
392276bd547bSAdrian Chadd     ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL;
392376bd547bSAdrian Chadd 
392476bd547bSAdrian Chadd     /*
392576bd547bSAdrian Chadd      * Enable IQ, ADC Gain, ADC DC Offset Cals
392676bd547bSAdrian Chadd      */
392776bd547bSAdrian Chadd     /* Setup all non-periodic, init time only calibrations */
392876bd547bSAdrian Chadd     /* XXX: Init DC Offset not working yet */
392976bd547bSAdrian Chadd #ifdef not_yet
393076bd547bSAdrian Chadd     if (AH_TRUE == ar9300_is_cal_supp(ah, chan, ADC_DC_INIT_CAL)) {
393176bd547bSAdrian Chadd         INIT_CAL(&ahp->ah_adc_dc_cal_init_data);
393276bd547bSAdrian Chadd         INSERT_CAL(ahp, &ahp->ah_adc_dc_cal_init_data);
393376bd547bSAdrian Chadd     }
393476bd547bSAdrian Chadd 
393576bd547bSAdrian Chadd     /* Initialize current pointer to first element in list */
393676bd547bSAdrian Chadd     ahp->ah_cal_list_curr = ahp->ah_cal_list;
393776bd547bSAdrian Chadd 
393876bd547bSAdrian Chadd     if (ahp->ah_cal_list_curr) {
393976bd547bSAdrian Chadd         if (ar9300_run_init_cals(ah, 0) == AH_FALSE) {
394076bd547bSAdrian Chadd             return AH_FALSE;
394176bd547bSAdrian Chadd         }
394276bd547bSAdrian Chadd     }
394376bd547bSAdrian Chadd #endif
394476bd547bSAdrian Chadd     /* end - Init time calibrations */
394576bd547bSAdrian Chadd 
3946899d1cacSAdrian Chadd     /* Do not do RX cal in case of offchan, or cal data already exists on same channel*/
3947899d1cacSAdrian Chadd     if (ahp->ah_skip_rx_iq_cal) {
3948899d1cacSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
3949899d1cacSAdrian Chadd                 "Skip RX IQ Cal\n");
3950899d1cacSAdrian Chadd         return AH_TRUE;
3951899d1cacSAdrian Chadd     }
3952899d1cacSAdrian Chadd 
395376bd547bSAdrian Chadd     /* If Cals are supported, add them to list via INIT/INSERT_CAL */
395476bd547bSAdrian Chadd     if (AH_TRUE == ar9300_is_cal_supp(ah, chan, IQ_MISMATCH_CAL)) {
395576bd547bSAdrian Chadd         INIT_CAL(&ahp->ah_iq_cal_data);
395676bd547bSAdrian Chadd         INSERT_CAL(ahp, &ahp->ah_iq_cal_data);
395776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
395876bd547bSAdrian Chadd             "%s: enabling IQ Calibration.\n", __func__);
395976bd547bSAdrian Chadd     }
396076bd547bSAdrian Chadd     if (AH_TRUE == ar9300_is_cal_supp(ah, chan, TEMP_COMP_CAL)) {
396176bd547bSAdrian Chadd         INIT_CAL(&ahp->ah_temp_comp_cal_data);
396276bd547bSAdrian Chadd         INSERT_CAL(ahp, &ahp->ah_temp_comp_cal_data);
396376bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
396476bd547bSAdrian Chadd             "%s: enabling Temperature Compensation Calibration.\n", __func__);
396576bd547bSAdrian Chadd     }
396676bd547bSAdrian Chadd 
396776bd547bSAdrian Chadd     /* Initialize current pointer to first element in list */
396876bd547bSAdrian Chadd     ahp->ah_cal_list_curr = ahp->ah_cal_list;
396976bd547bSAdrian Chadd 
397076bd547bSAdrian Chadd     /* Reset state within current cal */
397176bd547bSAdrian Chadd     if (ahp->ah_cal_list_curr) {
397276bd547bSAdrian Chadd         ar9300_reset_calibration(ah, ahp->ah_cal_list_curr);
397376bd547bSAdrian Chadd     }
397476bd547bSAdrian Chadd 
397576bd547bSAdrian Chadd     /* Mark all calibrations on this channel as being invalid */
3976e113789bSAdrian Chadd     ichan->calValid = 0;
397776bd547bSAdrian Chadd 
397876bd547bSAdrian Chadd     return AH_TRUE;
397976bd547bSAdrian Chadd }
398076bd547bSAdrian Chadd 
398176bd547bSAdrian Chadd static inline HAL_BOOL
ar9300_init_cal(struct ath_hal * ah,struct ieee80211_channel * chan,HAL_BOOL skip_if_none,HAL_BOOL apply_last_iqcorr)3982e113789bSAdrian Chadd ar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr)
398376bd547bSAdrian Chadd {
398476bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
398576bd547bSAdrian Chadd     HAL_BOOL do_rtt_cal = AH_TRUE;
398676bd547bSAdrian Chadd     HAL_BOOL enable_rtt = AH_FALSE;
398776bd547bSAdrian Chadd 
398876bd547bSAdrian Chadd     HALASSERT(ichan);
398976bd547bSAdrian Chadd 
399076bd547bSAdrian Chadd     return ar9300_init_cal_internal(ah, chan, ichan, enable_rtt, do_rtt_cal, skip_if_none, apply_last_iqcorr);
399176bd547bSAdrian Chadd }
399276bd547bSAdrian Chadd 
399376bd547bSAdrian Chadd /* ar9300_reset_cal_valid
399476bd547bSAdrian Chadd  * Entry point for upper layers to restart current cal.
399576bd547bSAdrian Chadd  * Reset the calibration valid bit in channel.
399676bd547bSAdrian Chadd  */
399776bd547bSAdrian Chadd void
ar9300_reset_cal_valid(struct ath_hal * ah,const struct ieee80211_channel * chan,HAL_BOOL * is_cal_done,u_int32_t cal_type)3998e113789bSAdrian Chadd ar9300_reset_cal_valid(struct ath_hal *ah, const struct ieee80211_channel *chan,
399976bd547bSAdrian Chadd     HAL_BOOL *is_cal_done, u_int32_t cal_type)
400076bd547bSAdrian Chadd {
400176bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
400276bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
400376bd547bSAdrian Chadd     HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr;
400476bd547bSAdrian Chadd 
400576bd547bSAdrian Chadd     *is_cal_done = AH_TRUE;
400676bd547bSAdrian Chadd 
400776bd547bSAdrian Chadd     if (curr_cal == AH_NULL) {
400876bd547bSAdrian Chadd         return;
400976bd547bSAdrian Chadd     }
401076bd547bSAdrian Chadd     if (ichan == AH_NULL) {
401176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
401276bd547bSAdrian Chadd             "%s: invalid channel %u/0x%x; no mapping\n",
4013e113789bSAdrian Chadd             __func__, chan->ic_freq, chan->ic_flags);
401476bd547bSAdrian Chadd         return;
401576bd547bSAdrian Chadd     }
401676bd547bSAdrian Chadd 
401776bd547bSAdrian Chadd     if (!(cal_type & IQ_MISMATCH_CAL)) {
401876bd547bSAdrian Chadd         *is_cal_done = AH_FALSE;
401976bd547bSAdrian Chadd         return;
402076bd547bSAdrian Chadd     }
402176bd547bSAdrian Chadd 
402276bd547bSAdrian Chadd     /* Expected that this calibration has run before, post-reset.
402376bd547bSAdrian Chadd      * Current state should be done
402476bd547bSAdrian Chadd      */
402576bd547bSAdrian Chadd     if (curr_cal->cal_state != CAL_DONE) {
402676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
402776bd547bSAdrian Chadd             "%s: Calibration state incorrect, %d\n",
402876bd547bSAdrian Chadd             __func__, curr_cal->cal_state);
402976bd547bSAdrian Chadd         return;
403076bd547bSAdrian Chadd     }
403176bd547bSAdrian Chadd 
403276bd547bSAdrian Chadd     /* Verify Cal is supported on this channel */
403376bd547bSAdrian Chadd     if (ar9300_is_cal_supp(ah, chan, curr_cal->cal_data->cal_type) == AH_FALSE) {
403476bd547bSAdrian Chadd         return;
403576bd547bSAdrian Chadd     }
403676bd547bSAdrian Chadd 
403776bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
403876bd547bSAdrian Chadd         "%s: Resetting Cal %d state for channel %u/0x%x\n", __func__,
4039e113789bSAdrian Chadd         curr_cal->cal_data->cal_type, chan->ic_freq, chan->ic_flags);
404076bd547bSAdrian Chadd 
404176bd547bSAdrian Chadd     /* Disable cal validity in channel */
4042e113789bSAdrian Chadd     ichan->calValid &= ~curr_cal->cal_data->cal_type;
404376bd547bSAdrian Chadd     curr_cal->cal_state = CAL_WAITING;
404476bd547bSAdrian Chadd     /* Indicate to upper layers that we need polling */
404576bd547bSAdrian Chadd     *is_cal_done = AH_FALSE;
404676bd547bSAdrian Chadd }
404776bd547bSAdrian Chadd 
404876bd547bSAdrian Chadd static inline void
ar9300_set_dma(struct ath_hal * ah)404976bd547bSAdrian Chadd ar9300_set_dma(struct ath_hal *ah)
405076bd547bSAdrian Chadd {
405176bd547bSAdrian Chadd     u_int32_t   regval;
405276bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
4053899d1cacSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
4054899d1cacSAdrian Chadd     HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
405576bd547bSAdrian Chadd 
405676bd547bSAdrian Chadd #if 0
405776bd547bSAdrian Chadd     /*
405876bd547bSAdrian Chadd      * set AHB_MODE not to do cacheline prefetches
405976bd547bSAdrian Chadd      */
406076bd547bSAdrian Chadd     regval = OS_REG_READ(ah, AR_AHB_MODE);
406176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
406276bd547bSAdrian Chadd #endif
406376bd547bSAdrian Chadd 
406476bd547bSAdrian Chadd     /*
406576bd547bSAdrian Chadd      * let mac dma reads be in 128 byte chunks
406676bd547bSAdrian Chadd      */
406776bd547bSAdrian Chadd     regval = OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
406876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
406976bd547bSAdrian Chadd 
407076bd547bSAdrian Chadd     /*
407176bd547bSAdrian Chadd      * Restore TX Trigger Level to its pre-reset value.
407276bd547bSAdrian Chadd      * The initial value depends on whether aggregation is enabled, and is
407376bd547bSAdrian Chadd      * adjusted whenever underruns are detected.
407476bd547bSAdrian Chadd      */
407576bd547bSAdrian Chadd     /*
407676bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, AH_PRIVATE(ah)->ah_tx_trig_level);
407776bd547bSAdrian Chadd      */
407876bd547bSAdrian Chadd     /*
407976bd547bSAdrian Chadd      * Osprey 1.0 bug (EV 61936). Don't change trigger level from .ini default.
408076bd547bSAdrian Chadd      * Osprey 2.0 - hardware recommends using the default INI settings.
408176bd547bSAdrian Chadd      */
408276bd547bSAdrian Chadd #if 0
408376bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, 0x3f);
408476bd547bSAdrian Chadd #endif
408576bd547bSAdrian Chadd     /*
408676bd547bSAdrian Chadd      * let mac dma writes be in 128 byte chunks
408776bd547bSAdrian Chadd      */
408876bd547bSAdrian Chadd     regval = OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
408976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
409076bd547bSAdrian Chadd 
409176bd547bSAdrian Chadd     /*
409276bd547bSAdrian Chadd      * Setup receive FIFO threshold to hold off TX activities
409376bd547bSAdrian Chadd      */
409476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
409576bd547bSAdrian Chadd 
409676bd547bSAdrian Chadd     /*
409776bd547bSAdrian Chadd      * reduce the number of usable entries in PCU TXBUF to avoid
409876bd547bSAdrian Chadd      * wrap around bugs. (bug 20428)
409976bd547bSAdrian Chadd      */
410076bd547bSAdrian Chadd 
410176bd547bSAdrian Chadd     if (AR_SREV_WASP(ah) &&
410276bd547bSAdrian Chadd         (AH_PRIVATE((ah))->ah_macRev > AR_SREV_REVISION_WASP_12)) {
410376bd547bSAdrian Chadd         /* Wasp 1.3 fix for EV#85395 requires usable entries
410476bd547bSAdrian Chadd          * to be set to 0x500
410576bd547bSAdrian Chadd          */
410676bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, 0x500);
410776bd547bSAdrian Chadd     } else {
410876bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE);
410976bd547bSAdrian Chadd     }
411076bd547bSAdrian Chadd 
411176bd547bSAdrian Chadd     /*
411276bd547bSAdrian Chadd      * Enable HPQ for UAPSD
411376bd547bSAdrian Chadd      */
4114899d1cacSAdrian Chadd     if (pCap->halHwUapsdTrig == AH_TRUE) {
4115899d1cacSAdrian Chadd     /* Only enable this if HAL capabilities says it is OK */
411676bd547bSAdrian Chadd         if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
411776bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_HP_Q_CONTROL,
411876bd547bSAdrian Chadd                     AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN);
411976bd547bSAdrian Chadd         }
4120899d1cacSAdrian Chadd     } else {
4121899d1cacSAdrian Chadd         /* use default value from ini file - which disable HPQ queue usage */
4122899d1cacSAdrian Chadd     }
412376bd547bSAdrian Chadd 
412476bd547bSAdrian Chadd     /*
412576bd547bSAdrian Chadd      * set the transmit status ring
412676bd547bSAdrian Chadd      */
412776bd547bSAdrian Chadd     ar9300_reset_tx_status_ring(ah);
412876bd547bSAdrian Chadd 
412976bd547bSAdrian Chadd     /*
413076bd547bSAdrian Chadd      * set rxbp threshold.  Must be non-zero for RX_EOL to occur.
413176bd547bSAdrian Chadd      * For Osprey 2.0+, keep the original thresholds
413276bd547bSAdrian Chadd      * otherwise performance is lost due to excessive RX EOL interrupts.
413376bd547bSAdrian Chadd      */
413476bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1);
413576bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1);
413676bd547bSAdrian Chadd 
413776bd547bSAdrian Chadd     /*
413876bd547bSAdrian Chadd      * set receive buffer size.
413976bd547bSAdrian Chadd      */
414076bd547bSAdrian Chadd     if (ahp->rx_buf_size) {
414176bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_DATABUF, ahp->rx_buf_size);
414276bd547bSAdrian Chadd     }
414376bd547bSAdrian Chadd }
414476bd547bSAdrian Chadd 
414576bd547bSAdrian Chadd static inline void
ar9300_init_bb(struct ath_hal * ah,struct ieee80211_channel * chan)4146e113789bSAdrian Chadd ar9300_init_bb(struct ath_hal *ah, struct ieee80211_channel *chan)
414776bd547bSAdrian Chadd {
414876bd547bSAdrian Chadd     u_int32_t synth_delay;
414976bd547bSAdrian Chadd 
415076bd547bSAdrian Chadd     /*
415176bd547bSAdrian Chadd      * Wait for the frequency synth to settle (synth goes on
415276bd547bSAdrian Chadd      * via AR_PHY_ACTIVE_EN).  Read the phy active delay register.
415376bd547bSAdrian Chadd      * Value is in 100ns increments.
415476bd547bSAdrian Chadd      */
415576bd547bSAdrian Chadd     synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
4156e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_CCK(chan)) {
415776bd547bSAdrian Chadd         synth_delay = (4 * synth_delay) / 22;
415876bd547bSAdrian Chadd     } else {
415976bd547bSAdrian Chadd         synth_delay /= 10;
416076bd547bSAdrian Chadd     }
416176bd547bSAdrian Chadd 
416276bd547bSAdrian Chadd     /* Activate the PHY (includes baseband activate + synthesizer on) */
416376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
416476bd547bSAdrian Chadd 
416576bd547bSAdrian Chadd     /*
416676bd547bSAdrian Chadd      * There is an issue if the AP starts the calibration before
416776bd547bSAdrian Chadd      * the base band timeout completes.  This could result in the
416827e2ad46SAdrian Chadd      * rx_clear false triggering.  As a workaround we add delay an
416976bd547bSAdrian Chadd      * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
417076bd547bSAdrian Chadd      * does not happen.
417176bd547bSAdrian Chadd      */
417276bd547bSAdrian Chadd     OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY);
417376bd547bSAdrian Chadd }
417476bd547bSAdrian Chadd 
417576bd547bSAdrian Chadd static inline void
ar9300_init_interrupt_masks(struct ath_hal * ah,HAL_OPMODE opmode)417676bd547bSAdrian Chadd ar9300_init_interrupt_masks(struct ath_hal *ah, HAL_OPMODE opmode)
417776bd547bSAdrian Chadd {
417876bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
417976bd547bSAdrian Chadd     u_int32_t msi_cfg = 0;
418076bd547bSAdrian Chadd     u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT;
418176bd547bSAdrian Chadd 
418276bd547bSAdrian Chadd     /*
418376bd547bSAdrian Chadd      * Setup interrupt handling.  Note that ar9300_reset_tx_queue
418476bd547bSAdrian Chadd      * manipulates the secondary IMR's as queues are enabled
418576bd547bSAdrian Chadd      * and disabled.  This is done with RMW ops to insure the
418676bd547bSAdrian Chadd      * settings we make here are preserved.
418776bd547bSAdrian Chadd      */
418876bd547bSAdrian Chadd     ahp->ah_mask_reg =
418976bd547bSAdrian Chadd         AR_IMR_TXERR | AR_IMR_TXURN |
419076bd547bSAdrian Chadd         AR_IMR_RXERR | AR_IMR_RXORN |
419176bd547bSAdrian Chadd         AR_IMR_BCNMISC;
419276bd547bSAdrian Chadd 
419376bd547bSAdrian Chadd     if (ahp->ah_intr_mitigation_rx) {
419476bd547bSAdrian Chadd         /* enable interrupt mitigation for rx */
419576bd547bSAdrian Chadd         ahp->ah_mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR | AR_IMR_RXOK_HP;
419676bd547bSAdrian Chadd         msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR;
419776bd547bSAdrian Chadd     } else {
419876bd547bSAdrian Chadd         ahp->ah_mask_reg |= AR_IMR_RXOK_LP | AR_IMR_RXOK_HP;
419976bd547bSAdrian Chadd         msi_cfg |= AR_INTCFG_MSI_RXOK;
420076bd547bSAdrian Chadd     }
420176bd547bSAdrian Chadd     if (ahp->ah_intr_mitigation_tx) {
420276bd547bSAdrian Chadd         /* enable interrupt mitigation for tx */
420376bd547bSAdrian Chadd         ahp->ah_mask_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR;
420476bd547bSAdrian Chadd         msi_cfg |= AR_INTCFG_MSI_TXINTM | AR_INTCFG_MSI_TXMINTR;
420576bd547bSAdrian Chadd     } else {
420676bd547bSAdrian Chadd         ahp->ah_mask_reg |= AR_IMR_TXOK;
420776bd547bSAdrian Chadd         msi_cfg |= AR_INTCFG_MSI_TXOK;
420876bd547bSAdrian Chadd     }
420976bd547bSAdrian Chadd     if (opmode == HAL_M_HOSTAP) {
421076bd547bSAdrian Chadd         ahp->ah_mask_reg |= AR_IMR_MIB;
421176bd547bSAdrian Chadd     }
421276bd547bSAdrian Chadd 
421376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_IMR, ahp->ah_mask_reg);
421476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
421576bd547bSAdrian Chadd     ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2);
421676bd547bSAdrian Chadd 
4217e113789bSAdrian Chadd     if (ah->ah_config.ath_hal_enable_msi) {
421876bd547bSAdrian Chadd         /* Cache MSI register value */
421976bd547bSAdrian Chadd         ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI));
422076bd547bSAdrian Chadd         ahp->ah_msi_reg |= AR_PCIE_MSI_HW_DBI_WR_EN;
422176bd547bSAdrian Chadd         if (AR_SREV_POSEIDON(ah)) {
422276bd547bSAdrian Chadd             ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64;
422376bd547bSAdrian Chadd         } else {
422476bd547bSAdrian Chadd             ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR;
422576bd547bSAdrian Chadd         }
422676bd547bSAdrian Chadd         /* Program MSI configuration */
422776bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_INTCFG, msi_cfg);
422876bd547bSAdrian Chadd     }
422976bd547bSAdrian Chadd 
423076bd547bSAdrian Chadd     /*
423176bd547bSAdrian Chadd      * debug - enable to see all synchronous interrupts status
423276bd547bSAdrian Chadd      */
423376bd547bSAdrian Chadd     /* Clear any pending sync cause interrupts */
423476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE), 0xFFFFFFFF);
423576bd547bSAdrian Chadd 
423676bd547bSAdrian Chadd     /* Allow host interface sync interrupt sources to set cause bit */
423776bd547bSAdrian Chadd     if (AR_SREV_POSEIDON(ah)) {
423876bd547bSAdrian Chadd         sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR;
423976bd547bSAdrian Chadd     }
424076bd547bSAdrian Chadd     else if (AR_SREV_WASP(ah)) {
424176bd547bSAdrian Chadd         sync_en_def = AR9340_INTR_SYNC_DEFAULT;
424276bd547bSAdrian Chadd     }
424376bd547bSAdrian Chadd     OS_REG_WRITE(ah,
424476bd547bSAdrian Chadd         AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), sync_en_def);
424576bd547bSAdrian Chadd 
424676bd547bSAdrian Chadd     /* _Disable_ host interface sync interrupt when cause bits set */
424776bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 0);
424876bd547bSAdrian Chadd 
424976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0);
425076bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 0);
425176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE), 0);
425276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK), 0);
425376bd547bSAdrian Chadd }
425476bd547bSAdrian Chadd 
425576bd547bSAdrian Chadd static inline void
ar9300_init_qos(struct ath_hal * ah)425676bd547bSAdrian Chadd ar9300_init_qos(struct ath_hal *ah)
425776bd547bSAdrian Chadd {
425876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);  /* XXX magic */
425976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);    /* XXX magic */
426076bd547bSAdrian Chadd 
426176bd547bSAdrian Chadd     /* Turn on NOACK Support for QoS packets */
426276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_QOS_NO_ACK,
426376bd547bSAdrian Chadd         SM(2, AR_QOS_NO_ACK_TWO_BIT) |
426476bd547bSAdrian Chadd         SM(5, AR_QOS_NO_ACK_BIT_OFF) |
426576bd547bSAdrian Chadd         SM(0, AR_QOS_NO_ACK_BYTE_OFF));
426676bd547bSAdrian Chadd 
426776bd547bSAdrian Chadd     /*
426876bd547bSAdrian Chadd      * initialize TXOP for all TIDs
426976bd547bSAdrian Chadd      */
427076bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
427176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
427276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
427376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
427476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
427576bd547bSAdrian Chadd }
427676bd547bSAdrian Chadd 
427776bd547bSAdrian Chadd static inline void
ar9300_init_user_settings(struct ath_hal * ah)427876bd547bSAdrian Chadd ar9300_init_user_settings(struct ath_hal *ah)
427976bd547bSAdrian Chadd {
428076bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
428176bd547bSAdrian Chadd 
428276bd547bSAdrian Chadd     /* Restore user-specified settings */
428376bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_RESET,
428476bd547bSAdrian Chadd         "--AP %s ahp->ah_misc_mode 0x%x\n", __func__, ahp->ah_misc_mode);
428576bd547bSAdrian Chadd     if (ahp->ah_misc_mode != 0) {
428676bd547bSAdrian Chadd         OS_REG_WRITE(ah,
428776bd547bSAdrian Chadd             AR_PCU_MISC, OS_REG_READ(ah, AR_PCU_MISC) | ahp->ah_misc_mode);
428876bd547bSAdrian Chadd     }
428976bd547bSAdrian Chadd     if (ahp->ah_get_plcp_hdr) {
429076bd547bSAdrian Chadd         OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM);
429176bd547bSAdrian Chadd     }
429276bd547bSAdrian Chadd     if (ahp->ah_slot_time != (u_int) -1) {
429376bd547bSAdrian Chadd         ar9300_set_slot_time(ah, ahp->ah_slot_time);
429476bd547bSAdrian Chadd     }
429576bd547bSAdrian Chadd     if (ahp->ah_ack_timeout != (u_int) -1) {
429676bd547bSAdrian Chadd         ar9300_set_ack_timeout(ah, ahp->ah_ack_timeout);
429776bd547bSAdrian Chadd     }
429876bd547bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_diagreg != 0) {
429976bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
430076bd547bSAdrian Chadd     }
430176bd547bSAdrian Chadd     if (ahp->ah_beacon_rssi_threshold != 0) {
430276bd547bSAdrian Chadd         ar9300_set_hw_beacon_rssi_threshold(ah, ahp->ah_beacon_rssi_threshold);
430376bd547bSAdrian Chadd     }
4304ea319c83SAdrian Chadd //#ifdef ATH_SUPPORT_DFS
430576bd547bSAdrian Chadd     if (ahp->ah_cac_quiet_enabled) {
430676bd547bSAdrian Chadd         ar9300_cac_tx_quiet(ah, 1);
430776bd547bSAdrian Chadd     }
4308ea319c83SAdrian Chadd //#endif /* ATH_SUPPORT_DFS */
430976bd547bSAdrian Chadd }
431076bd547bSAdrian Chadd 
431176bd547bSAdrian Chadd int
ar9300_get_spur_info(struct ath_hal * ah,int * enable,int len,u_int16_t * freq)431276bd547bSAdrian Chadd ar9300_get_spur_info(struct ath_hal * ah, int *enable, int len, u_int16_t *freq)
431376bd547bSAdrian Chadd {
4314e113789bSAdrian Chadd //    struct ath_hal_private *ap = AH_PRIVATE(ah);
431576bd547bSAdrian Chadd     int i, j;
431676bd547bSAdrian Chadd 
431776bd547bSAdrian Chadd     for (i = 0; i < len; i++) {
431876bd547bSAdrian Chadd         freq[i] =  0;
431976bd547bSAdrian Chadd     }
432076bd547bSAdrian Chadd 
4321e113789bSAdrian Chadd     *enable = ah->ah_config.ath_hal_spur_mode;
432276bd547bSAdrian Chadd     for (i = 0, j = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
4323e113789bSAdrian Chadd         if (AH9300(ah)->ath_hal_spur_chans[i][0] != AR_NO_SPUR) {
4324e113789bSAdrian Chadd             freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][0];
432576bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_ANI,
4326e113789bSAdrian Chadd                 "1. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][0]);
432776bd547bSAdrian Chadd         }
4328e113789bSAdrian Chadd         if (AH9300(ah)->ath_hal_spur_chans[i][1] != AR_NO_SPUR) {
4329e113789bSAdrian Chadd             freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][1];
433076bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_ANI,
4331e113789bSAdrian Chadd                 "2. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][1]);
433276bd547bSAdrian Chadd         }
433376bd547bSAdrian Chadd     }
433476bd547bSAdrian Chadd 
433576bd547bSAdrian Chadd     return 0;
433676bd547bSAdrian Chadd }
433776bd547bSAdrian Chadd 
433876bd547bSAdrian Chadd #define ATH_HAL_2GHZ_FREQ_MIN   20000
433976bd547bSAdrian Chadd #define ATH_HAL_2GHZ_FREQ_MAX   29999
434076bd547bSAdrian Chadd #define ATH_HAL_5GHZ_FREQ_MIN   50000
434176bd547bSAdrian Chadd #define ATH_HAL_5GHZ_FREQ_MAX   59999
434276bd547bSAdrian Chadd 
4343e113789bSAdrian Chadd #if 0
434476bd547bSAdrian Chadd int
434576bd547bSAdrian Chadd ar9300_set_spur_info(struct ath_hal * ah, int enable, int len, u_int16_t *freq)
434676bd547bSAdrian Chadd {
434776bd547bSAdrian Chadd     struct ath_hal_private *ap = AH_PRIVATE(ah);
434876bd547bSAdrian Chadd     int i, j, k;
434976bd547bSAdrian Chadd 
435076bd547bSAdrian Chadd     ap->ah_config.ath_hal_spur_mode = enable;
435176bd547bSAdrian Chadd 
435276bd547bSAdrian Chadd     if (ap->ah_config.ath_hal_spur_mode == SPUR_ENABLE_IOCTL) {
435376bd547bSAdrian Chadd         for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
4354e113789bSAdrian Chadd             AH9300(ah)->ath_hal_spur_chans[i][0] = AR_NO_SPUR;
4355e113789bSAdrian Chadd             AH9300(ah)->ath_hal_spur_chans[i][1] = AR_NO_SPUR;
435676bd547bSAdrian Chadd         }
435776bd547bSAdrian Chadd         for (i = 0, j = 0, k = 0; i < len; i++) {
435876bd547bSAdrian Chadd             if (freq[i] > ATH_HAL_2GHZ_FREQ_MIN &&
435976bd547bSAdrian Chadd                 freq[i] < ATH_HAL_2GHZ_FREQ_MAX)
436076bd547bSAdrian Chadd             {
436176bd547bSAdrian Chadd                 /* 2GHz Spur */
436276bd547bSAdrian Chadd                 if (j < AR_EEPROM_MODAL_SPURS) {
4363e113789bSAdrian Chadd                     AH9300(ah)->ath_hal_spur_chans[j++][1] =  freq[i];
436476bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_ANI, "1 set spur %d\n", freq[i]);
436576bd547bSAdrian Chadd                 }
436676bd547bSAdrian Chadd             } else if (freq[i] > ATH_HAL_5GHZ_FREQ_MIN &&
436776bd547bSAdrian Chadd                        freq[i] < ATH_HAL_5GHZ_FREQ_MAX)
436876bd547bSAdrian Chadd             {
436976bd547bSAdrian Chadd                 /* 5Ghz Spur */
437076bd547bSAdrian Chadd                 if (k < AR_EEPROM_MODAL_SPURS) {
4371e113789bSAdrian Chadd                     AH9300(ah)->ath_hal_spur_chans[k++][0] =  freq[i];
437276bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_ANI, "2 set spur %d\n", freq[i]);
437376bd547bSAdrian Chadd                 }
437476bd547bSAdrian Chadd             }
437576bd547bSAdrian Chadd         }
437676bd547bSAdrian Chadd     }
437776bd547bSAdrian Chadd 
437876bd547bSAdrian Chadd     return 0;
437976bd547bSAdrian Chadd }
4380e113789bSAdrian Chadd #endif
438176bd547bSAdrian Chadd 
438276bd547bSAdrian Chadd #define ar9300_check_op_mode(_opmode) \
438376bd547bSAdrian Chadd     ((_opmode == HAL_M_STA) || (_opmode == HAL_M_IBSS) ||\
438476bd547bSAdrian Chadd      (_opmode == HAL_M_HOSTAP) || (_opmode == HAL_M_MONITOR))
438576bd547bSAdrian Chadd 
438676bd547bSAdrian Chadd 
438776bd547bSAdrian Chadd 
438876bd547bSAdrian Chadd 
438976bd547bSAdrian Chadd #ifndef ATH_NF_PER_CHAN
439076bd547bSAdrian Chadd /*
439176bd547bSAdrian Chadd * To fixed first reset noise floor value not correct issue
439276bd547bSAdrian Chadd * For ART need it to fixed low rate sens too low issue
439376bd547bSAdrian Chadd */
439476bd547bSAdrian Chadd static int
First_NFCal(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * ichan,int is_scan,struct ieee80211_channel * chan)439576bd547bSAdrian Chadd First_NFCal(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan,
4396e113789bSAdrian Chadd     int is_scan, struct ieee80211_channel *chan)
439776bd547bSAdrian Chadd {
439876bd547bSAdrian Chadd     HAL_NFCAL_HIST_FULL *nfh;
439976bd547bSAdrian Chadd     int i, j, k;
4400e113789bSAdrian Chadd     int16_t nfarray[HAL_NUM_NF_READINGS] = {0};
440176bd547bSAdrian Chadd     int is_2g = 0;
440276bd547bSAdrian Chadd     int nf_hist_len;
440376bd547bSAdrian Chadd     int stats = 0;
440476bd547bSAdrian Chadd 
4405e113789bSAdrian Chadd     int16_t nf_buf[HAL_NUM_NF_READINGS];
440676bd547bSAdrian Chadd #define IS(_c, _f)       (((_c)->channel_flags & _f) || 0)
440776bd547bSAdrian Chadd 
440876bd547bSAdrian Chadd 
440976bd547bSAdrian Chadd     if ((!is_scan) &&
4410e113789bSAdrian Chadd         chan->ic_freq == AH_PRIVATE(ah)->ah_curchan->ic_freq)
441176bd547bSAdrian Chadd     {
441276bd547bSAdrian Chadd         nfh = &AH_PRIVATE(ah)->nf_cal_hist;
441376bd547bSAdrian Chadd     } else {
441476bd547bSAdrian Chadd         nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;
441576bd547bSAdrian Chadd     }
441676bd547bSAdrian Chadd 
441776bd547bSAdrian Chadd     ar9300_start_nf_cal(ah);
441876bd547bSAdrian Chadd     for (j = 0; j < 10000; j++) {
441976bd547bSAdrian Chadd         if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){
442076bd547bSAdrian Chadd             break;
442176bd547bSAdrian Chadd 		}
442276bd547bSAdrian Chadd         OS_DELAY(10);
442376bd547bSAdrian Chadd     }
442476bd547bSAdrian Chadd 	if (j < 10000) {
4425e113789bSAdrian Chadd         is_2g = IEEE80211_IS_CHAN_2GHZ(chan);
442676bd547bSAdrian Chadd         ar9300_upload_noise_floor(ah, is_2g, nfarray);
442776bd547bSAdrian Chadd 
442876bd547bSAdrian Chadd 	    if (is_scan) {
442976bd547bSAdrian Chadd 			/*
443076bd547bSAdrian Chadd 			 * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct
443176bd547bSAdrian Chadd 			 * rather than a HAL_NFCAL_HIST_FULL struct.
443276bd547bSAdrian Chadd 			 * As long as we only use the first history element of nf_cal_buffer
4433e113789bSAdrian Chadd 			 * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use
443476bd547bSAdrian Chadd 			 * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably.
443576bd547bSAdrian Chadd 			 */
443676bd547bSAdrian Chadd             nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;
443776bd547bSAdrian Chadd             nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL;
443876bd547bSAdrian Chadd 		} else {
443976bd547bSAdrian Chadd             nfh = &AH_PRIVATE(ah)->nf_cal_hist;
444076bd547bSAdrian Chadd             nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;
444176bd547bSAdrian Chadd 		}
444276bd547bSAdrian Chadd 
4443e113789bSAdrian Chadd   	    for (i = 0; i < HAL_NUM_NF_READINGS; i ++) {
444476bd547bSAdrian Chadd     		for (k = 0; k < HAL_NF_CAL_HIST_LEN_FULL; k++) {
444576bd547bSAdrian Chadd                 nfh->nf_cal_buffer[k][i] = nfarray[i];
444676bd547bSAdrian Chadd             }
444776bd547bSAdrian Chadd             nfh->base.priv_nf[i] = ar9300_limit_nf_range(ah,
444876bd547bSAdrian Chadd 							ar9300_get_nf_hist_mid(ah, nfh, i, nf_hist_len));
444976bd547bSAdrian Chadd   		}
445076bd547bSAdrian Chadd 
445176bd547bSAdrian Chadd 
445276bd547bSAdrian Chadd 		//ar9300StoreNewNf(ah, ichan, is_scan);
445376bd547bSAdrian Chadd 
445476bd547bSAdrian Chadd 		/*
445576bd547bSAdrian Chadd 		 * See if the NF value from the old channel should be
445676bd547bSAdrian Chadd 		 * retained when switching to a new channel.
445776bd547bSAdrian Chadd 		 * TBD: this may need to be changed, as it wipes out the
445876bd547bSAdrian Chadd 		 * purpose of saving NF values for each channel.
445976bd547bSAdrian Chadd 		 */
4460e113789bSAdrian Chadd 		for (i = 0; i < HAL_NUM_NF_READINGS; i++)
446176bd547bSAdrian Chadd 		{
4462e113789bSAdrian Chadd     		if (IEEE80211_IS_CHAN_2GHZ(chan))
446376bd547bSAdrian Chadd     		{
446476bd547bSAdrian Chadd     			if (nfh->nf_cal_buffer[0][i] <
446576bd547bSAdrian Chadd 					AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ)
446676bd547bSAdrian Chadd                 {
446776bd547bSAdrian Chadd                     ichan->nf_cal_hist.nf_cal_buffer[0][i] =
446876bd547bSAdrian Chadd 							AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];
446976bd547bSAdrian Chadd 				}
447076bd547bSAdrian Chadd     		} else {
447176bd547bSAdrian Chadd                 if (AR_SREV_AR9580(ah)) {
447276bd547bSAdrian Chadd                     if (nfh->nf_cal_buffer[0][i] <
447376bd547bSAdrian Chadd                         AR_PHY_CCA_NOM_VAL_PEACOCK_5GHZ)
447476bd547bSAdrian Chadd                     {
447576bd547bSAdrian Chadd                        ichan->nf_cal_hist.nf_cal_buffer[0][i] =
447676bd547bSAdrian Chadd                        AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];
447776bd547bSAdrian Chadd                     }
447876bd547bSAdrian Chadd                 } else {
447976bd547bSAdrian Chadd                    if (nfh->nf_cal_buffer[0][i] <
448076bd547bSAdrian Chadd                        AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ)
448176bd547bSAdrian Chadd                     {
448276bd547bSAdrian Chadd                         ichan->nf_cal_hist.nf_cal_buffer[0][i] =
448376bd547bSAdrian Chadd                             AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];
448476bd547bSAdrian Chadd                      }
448576bd547bSAdrian Chadd                 }
448676bd547bSAdrian Chadd             }
448776bd547bSAdrian Chadd         }
448876bd547bSAdrian Chadd 		/*
448976bd547bSAdrian Chadd 		 * Copy the channel's NF buffer, which may have been modified
449076bd547bSAdrian Chadd 		 * just above here, to the full NF history buffer.
449176bd547bSAdrian Chadd 		 */
449276bd547bSAdrian Chadd         ar9300_reset_nf_hist_buff(ah, ichan);
4493e113789bSAdrian Chadd         ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);
449476bd547bSAdrian Chadd         ar9300_load_nf(ah, nf_buf);
44958a97beffSAdrian Chadd         /* XXX TODO: handle failure from load_nf */
449676bd547bSAdrian Chadd         stats = 0;
449776bd547bSAdrian Chadd 	} else {
449876bd547bSAdrian Chadd         stats = 1;
449976bd547bSAdrian Chadd 	}
450076bd547bSAdrian Chadd #undef IS
450176bd547bSAdrian Chadd     return stats;
450276bd547bSAdrian Chadd }
450376bd547bSAdrian Chadd #endif
450476bd547bSAdrian Chadd 
450576bd547bSAdrian Chadd 
450676bd547bSAdrian Chadd /*
450776bd547bSAdrian Chadd  * Places the device in and out of reset and then places sane
450876bd547bSAdrian Chadd  * values in the registers based on EEPROM config, initialization
450976bd547bSAdrian Chadd  * vectors (as determined by the mode), and station configuration
451076bd547bSAdrian Chadd  *
451176bd547bSAdrian Chadd  * b_channel_change is used to preserve DMA/PCU registers across
451276bd547bSAdrian Chadd  * a HW Reset during channel change.
451376bd547bSAdrian Chadd  */
451476bd547bSAdrian Chadd HAL_BOOL
ar9300_reset(struct ath_hal * ah,HAL_OPMODE opmode,struct ieee80211_channel * chan,HAL_HT_MACMODE macmode,u_int8_t txchainmask,u_int8_t rxchainmask,HAL_HT_EXTPROTSPACING extprotspacing,HAL_BOOL b_channel_change,HAL_STATUS * status,HAL_RESET_TYPE reset_type,int is_scan)4515e113789bSAdrian Chadd ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan,
451676bd547bSAdrian Chadd     HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask,
451776bd547bSAdrian Chadd     HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change,
45188c01c3dcSAdrian Chadd     HAL_STATUS *status, HAL_RESET_TYPE reset_type, int is_scan)
451976bd547bSAdrian Chadd {
452076bd547bSAdrian Chadd #define FAIL(_code)     do { ecode = _code; goto bad; } while (0)
452176bd547bSAdrian Chadd     u_int32_t               save_led_state;
452276bd547bSAdrian Chadd     struct ath_hal_9300     *ahp = AH9300(ah);
452376bd547bSAdrian Chadd     struct ath_hal_private  *ap  = AH_PRIVATE(ah);
452476bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL    *ichan;
4525e113789bSAdrian Chadd     //const struct ieee80211_channel *curchan = ap->ah_curchan;
452676bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
452776bd547bSAdrian Chadd     HAL_BOOL                    save_full_sleep = ahp->ah_chip_full_sleep;
452876bd547bSAdrian Chadd #endif
452976bd547bSAdrian Chadd     u_int32_t               save_def_antenna;
453076bd547bSAdrian Chadd     u_int32_t               mac_sta_id1;
453176bd547bSAdrian Chadd     HAL_STATUS              ecode;
453276bd547bSAdrian Chadd     int                     i, rx_chainmask;
453376bd547bSAdrian Chadd     int                     nf_hist_buff_reset = 0;
4534e113789bSAdrian Chadd     int16_t                 nf_buf[HAL_NUM_NF_READINGS];
453576bd547bSAdrian Chadd #ifdef ATH_FORCE_PPM
453676bd547bSAdrian Chadd     u_int32_t               save_force_val, tmp_reg;
453776bd547bSAdrian Chadd #endif
453827e2ad46SAdrian Chadd     u_int8_t                clk_25mhz = AH9300(ah)->clk_25mhz;
453976bd547bSAdrian Chadd     HAL_BOOL                    stopped, cal_ret;
454076bd547bSAdrian Chadd     HAL_BOOL                    apply_last_iqcorr = AH_FALSE;
4541*dead34f8SAdrian Chadd     uint64_t tsf;
4542899d1cacSAdrian Chadd 
454376bd547bSAdrian Chadd     if (OS_REG_READ(ah, AR_IER) == AR_IER_ENABLE) {
454476bd547bSAdrian Chadd         HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "** Reset called with WLAN "
454576bd547bSAdrian Chadd                 "interrupt enabled %08x **\n", ar9300_get_interrupts(ah));
454676bd547bSAdrian Chadd     }
454776bd547bSAdrian Chadd 
454876bd547bSAdrian Chadd     /*
454976bd547bSAdrian Chadd      * Set the status to "ok" by default to cover the cases
455027e2ad46SAdrian Chadd      * where we return false without going to "bad"
455176bd547bSAdrian Chadd      */
455276bd547bSAdrian Chadd     HALASSERT(status);
455376bd547bSAdrian Chadd     *status = HAL_OK;
4554e113789bSAdrian Chadd     if ((ah->ah_config.ath_hal_sta_update_tx_pwr_enable)) {
4555e113789bSAdrian Chadd         AH9300(ah)->green_tx_status = HAL_RSSI_TX_POWER_NONE;
455676bd547bSAdrian Chadd     }
455776bd547bSAdrian Chadd 
455876bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
4559e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&
4560615a867fSAdrian Chadd         (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)))
456176bd547bSAdrian Chadd     {
4562e113789bSAdrian Chadd         ar9300_mci_2g5g_changed(ah, IEEE80211_IS_CHAN_2GHZ(chan));
456376bd547bSAdrian Chadd     }
456476bd547bSAdrian Chadd #endif
456576bd547bSAdrian Chadd 
456676bd547bSAdrian Chadd     ahp->ah_ext_prot_spacing = extprotspacing;
4567e113789bSAdrian Chadd     ahp->ah_tx_chainmask = txchainmask & ap->ah_caps.halTxChainMask;
4568e113789bSAdrian Chadd     ahp->ah_rx_chainmask = rxchainmask & ap->ah_caps.halRxChainMask;
4569e113789bSAdrian Chadd     ahp->ah_tx_cal_chainmask = ap->ah_caps.halTxChainMask;
4570e113789bSAdrian Chadd     ahp->ah_rx_cal_chainmask = ap->ah_caps.halRxChainMask;
4571899d1cacSAdrian Chadd 
4572899d1cacSAdrian Chadd     /*
4573899d1cacSAdrian Chadd      * Keep the previous optinal txchainmask value
4574899d1cacSAdrian Chadd      */
4575899d1cacSAdrian Chadd 
457676bd547bSAdrian Chadd     HALASSERT(ar9300_check_op_mode(opmode));
457776bd547bSAdrian Chadd 
457876bd547bSAdrian Chadd     OS_MARK(ah, AH_MARK_RESET, b_channel_change);
457976bd547bSAdrian Chadd 
458076bd547bSAdrian Chadd     /*
458176bd547bSAdrian Chadd      * Map public channel to private.
458276bd547bSAdrian Chadd      */
458376bd547bSAdrian Chadd     ichan = ar9300_check_chan(ah, chan);
458476bd547bSAdrian Chadd     if (ichan == AH_NULL) {
458576bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CHANNEL,
458676bd547bSAdrian Chadd             "%s: invalid channel %u/0x%x; no mapping\n",
4587e113789bSAdrian Chadd             __func__, chan->ic_freq, chan->ic_flags);
458876bd547bSAdrian Chadd         FAIL(HAL_EINVAL);
458976bd547bSAdrian Chadd     }
459076bd547bSAdrian Chadd 
459176bd547bSAdrian Chadd     ichan->paprd_table_write_done = 0;  /* Clear PAPRD table write flag */
4592e113789bSAdrian Chadd #if 0
459376bd547bSAdrian Chadd     chan->paprd_table_write_done = 0;  /* Clear PAPRD table write flag */
4594e113789bSAdrian Chadd #endif
459576bd547bSAdrian Chadd 
459676bd547bSAdrian Chadd     if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) {
459776bd547bSAdrian Chadd         /* Need to stop RX DMA before reset otherwise chip might hang */
459876bd547bSAdrian Chadd         stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */
459976bd547bSAdrian Chadd         ar9300_set_rx_filter(ah, 0);
460076bd547bSAdrian Chadd         stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */
460176bd547bSAdrian Chadd         if (!stopped) {
460276bd547bSAdrian Chadd             /*
460376bd547bSAdrian Chadd              * During the transition from full sleep to reset,
460476bd547bSAdrian Chadd              * recv DMA regs are not available to be read
460576bd547bSAdrian Chadd              */
460676bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
460776bd547bSAdrian Chadd                 "%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__);
460876bd547bSAdrian Chadd             b_channel_change = AH_FALSE;
460976bd547bSAdrian Chadd         }
461076bd547bSAdrian Chadd     } else {
461176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
461276bd547bSAdrian Chadd             "%s[%d]: Chip is already in full sleep\n", __func__, __LINE__);
461376bd547bSAdrian Chadd     }
461476bd547bSAdrian Chadd 
461576bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
4616e113789bSAdrian Chadd     if ((AH_PRIVATE(ah)->ah_caps.halMciSupport) &&
461776bd547bSAdrian Chadd         (ahp->ah_mci_bt_state == MCI_BT_CAL_START))
461876bd547bSAdrian Chadd     {
461976bd547bSAdrian Chadd         u_int32_t payload[4] = {0, 0, 0, 0};
462076bd547bSAdrian Chadd 
462176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_BT_COEX,
462276bd547bSAdrian Chadd             "(MCI) %s: Stop rx for BT cal.\n", __func__);
462376bd547bSAdrian Chadd         ahp->ah_mci_bt_state = MCI_BT_CAL;
462476bd547bSAdrian Chadd 
462576bd547bSAdrian Chadd         /*
462676bd547bSAdrian Chadd          * MCIFIX: disable mci interrupt here. This is to avoid SW_MSG_DONE or
462776bd547bSAdrian Chadd          * RX_MSG bits to trigger MCI_INT and lead to mci_intr reentry.
462876bd547bSAdrian Chadd          */
462976bd547bSAdrian Chadd         ar9300_mci_disable_interrupt(ah);
463076bd547bSAdrian Chadd 
463176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_BT_COEX,
463276bd547bSAdrian Chadd             "(MCI) %s: Send WLAN_CAL_GRANT\n", __func__);
463376bd547bSAdrian Chadd         MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
463476bd547bSAdrian Chadd         ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);
463576bd547bSAdrian Chadd 
463676bd547bSAdrian Chadd         /* Wait BT calibration to be completed for 25ms */
463776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_BT_COEX,
463876bd547bSAdrian Chadd             "(MCI) %s: BT is calibrating.\n", __func__);
463976bd547bSAdrian Chadd         if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) {
464076bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_BT_COEX,
464176bd547bSAdrian Chadd                 "(MCI) %s: Got BT_CAL_DONE.\n", __func__);
464276bd547bSAdrian Chadd         }
464376bd547bSAdrian Chadd         else {
464476bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_BT_COEX,
464576bd547bSAdrian Chadd                 "(MCI) %s: ### BT cal takes too long. Force bt_state to be bt_awake.\n",
464676bd547bSAdrian Chadd                 __func__);
464776bd547bSAdrian Chadd         }
464876bd547bSAdrian Chadd         ahp->ah_mci_bt_state = MCI_BT_AWAKE;
464976bd547bSAdrian Chadd         /* MCIFIX: enable mci interrupt here */
465076bd547bSAdrian Chadd         ar9300_mci_enable_interrupt(ah);
465176bd547bSAdrian Chadd 
465276bd547bSAdrian Chadd         return AH_TRUE;
465376bd547bSAdrian Chadd     }
465476bd547bSAdrian Chadd #endif
465576bd547bSAdrian Chadd 
465676bd547bSAdrian Chadd     /* Bring out of sleep mode */
465776bd547bSAdrian Chadd     if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {
465876bd547bSAdrian Chadd         *status = HAL_INV_PMODE;
465976bd547bSAdrian Chadd         return AH_FALSE;
466076bd547bSAdrian Chadd     }
466176bd547bSAdrian Chadd 
466276bd547bSAdrian Chadd     /* Check the Rx mitigation config again, it might have changed
466376bd547bSAdrian Chadd      * during attach in ath_vap_attach.
466476bd547bSAdrian Chadd      */
4665e113789bSAdrian Chadd     if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) {
466676bd547bSAdrian Chadd         ahp->ah_intr_mitigation_rx = AH_TRUE;
466776bd547bSAdrian Chadd     } else {
466876bd547bSAdrian Chadd         ahp->ah_intr_mitigation_rx = AH_FALSE;
466976bd547bSAdrian Chadd     }
467076bd547bSAdrian Chadd 
4671e113789bSAdrian Chadd     /*
4672e113789bSAdrian Chadd      * XXX TODO FreeBSD:
4673e113789bSAdrian Chadd      *
4674e113789bSAdrian Chadd      * This is painful because we don't have a non-const channel pointer
4675e113789bSAdrian Chadd      * at this stage.
4676e113789bSAdrian Chadd      *
4677e113789bSAdrian Chadd      * Make sure this gets fixed!
4678e113789bSAdrian Chadd      */
4679e113789bSAdrian Chadd #if 0
468076bd547bSAdrian Chadd     /* Get the value from the previous NF cal and update history buffer */
468176bd547bSAdrian Chadd     if (curchan && (ahp->ah_chip_full_sleep != AH_TRUE)) {
4682899d1cacSAdrian Chadd 
4683899d1cacSAdrian Chadd         if(ahp->ah_chip_reset_done){
4684899d1cacSAdrian Chadd             ahp->ah_chip_reset_done = 0;
4685899d1cacSAdrian Chadd         } else {
4686899d1cacSAdrian Chadd         	/*
4687899d1cacSAdrian Chadd          	 * is_scan controls updating NF for home channel or off channel.
4688899d1cacSAdrian Chadd          	 * Home -> Off, update home channel
4689899d1cacSAdrian Chadd          	 * Off -> Home, update off channel
4690899d1cacSAdrian Chadd          	 * Home -> Home, uppdate home channel
4691899d1cacSAdrian Chadd          	 */
4692899d1cacSAdrian Chadd         	if (ap->ah_curchan->channel != chan->channel)
4693899d1cacSAdrian Chadd             	ar9300_store_new_nf(ah, curchan, !is_scan);
4694899d1cacSAdrian Chadd         	else
469576bd547bSAdrian Chadd             	ar9300_store_new_nf(ah, curchan, is_scan);
469676bd547bSAdrian Chadd         }
4697899d1cacSAdrian Chadd     }
4698e113789bSAdrian Chadd #endif
469976bd547bSAdrian Chadd 
470076bd547bSAdrian Chadd     /*
470176bd547bSAdrian Chadd      * Account for the effect of being in either the 2 GHz or 5 GHz band
470276bd547bSAdrian Chadd      * on the nominal, max allowable, and min allowable noise floor values.
470376bd547bSAdrian Chadd      */
4704e113789bSAdrian Chadd     AH9300(ah)->nfp = IS_CHAN_2GHZ(ichan) ? &ahp->nf_2GHz : &ahp->nf_5GHz;
470576bd547bSAdrian Chadd 
4706e113789bSAdrian Chadd     /*
4707899d1cacSAdrian Chadd      * XXX FreeBSD For now, don't apply the last IQ correction.
4708e113789bSAdrian Chadd      *
4709e113789bSAdrian Chadd      * This should be done when scorpion is enabled on FreeBSD; just be
4710e113789bSAdrian Chadd      * sure to fix this channel match code so it uses net80211 flags
4711e113789bSAdrian Chadd      * instead.
4712e113789bSAdrian Chadd      */
4713e113789bSAdrian Chadd #if 0
471476bd547bSAdrian Chadd     if (AR_SREV_SCORPION(ah) && curchan && (chan->channel == curchan->channel) &&
471576bd547bSAdrian Chadd         ((chan->channel_flags & (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)) ==
471676bd547bSAdrian Chadd          (curchan->channel_flags &
471776bd547bSAdrian Chadd           (CHANNEL_ALL | CHANNEL_HALF | CHANNEL_QUARTER)))) {
471876bd547bSAdrian Chadd             apply_last_iqcorr = AH_TRUE;
471976bd547bSAdrian Chadd     }
4720e113789bSAdrian Chadd #endif
4721e113789bSAdrian Chadd     apply_last_iqcorr = AH_FALSE;
4722e113789bSAdrian Chadd 
472376bd547bSAdrian Chadd 
472476bd547bSAdrian Chadd #ifndef ATH_NF_PER_CHAN
472576bd547bSAdrian Chadd     /*
472676bd547bSAdrian Chadd      * If there's only one full-size home-channel NF history buffer
472776bd547bSAdrian Chadd      * rather than a full-size NF history buffer per channel, decide
472876bd547bSAdrian Chadd      * whether to (re)initialize the home-channel NF buffer.
472976bd547bSAdrian Chadd      * If this is just a channel change for a scan, or if the channel
473076bd547bSAdrian Chadd      * is not being changed, don't mess up the home channel NF history
473176bd547bSAdrian Chadd      * buffer with NF values from this scanned channel.  If we're
473276bd547bSAdrian Chadd      * changing the home channel to a new channel, reset the home-channel
473376bd547bSAdrian Chadd      * NF history buffer with the most accurate NF known for the new channel.
473476bd547bSAdrian Chadd      */
473576bd547bSAdrian Chadd     if (!is_scan && (!ap->ah_curchan ||
4736e113789bSAdrian Chadd         ap->ah_curchan->ic_freq != chan->ic_freq)) // ||
4737e113789bSAdrian Chadd //        ap->ah_curchan->channel_flags != chan->channel_flags))
473876bd547bSAdrian Chadd     {
473976bd547bSAdrian Chadd         nf_hist_buff_reset = 1;
474076bd547bSAdrian Chadd         ar9300_reset_nf_hist_buff(ah, ichan);
474176bd547bSAdrian Chadd     }
474276bd547bSAdrian Chadd #endif
474376bd547bSAdrian Chadd     /*
4744899d1cacSAdrian Chadd      * In case of
4745899d1cacSAdrian Chadd      * - offchan scan, or
4746899d1cacSAdrian Chadd      * - same channel and RX IQ Cal already available
4747899d1cacSAdrian Chadd      * disable RX IQ Cal.
4748899d1cacSAdrian Chadd      */
4749899d1cacSAdrian Chadd     if (is_scan) {
4750899d1cacSAdrian Chadd         ahp->ah_skip_rx_iq_cal = AH_TRUE;
4751899d1cacSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
4752899d1cacSAdrian Chadd                 "Skip RX IQ Cal due to scanning\n");
4753899d1cacSAdrian Chadd     } else {
4754899d1cacSAdrian Chadd #if 0
4755899d1cacSAdrian Chadd         /* XXX FreeBSD: always just do the RX IQ cal */
4756899d1cacSAdrian Chadd 	/* XXX I think it's just going to speed things up; I don't think it's to avoid chan bugs */
4757899d1cacSAdrian Chadd         if (ahp->ah_rx_cal_complete &&
4758899d1cacSAdrian Chadd             ahp->ah_rx_cal_chan == ichan->channel &&
4759899d1cacSAdrian Chadd             ahp->ah_rx_cal_chan_flag == chan->channel_flags) {
4760899d1cacSAdrian Chadd             ahp->ah_skip_rx_iq_cal = AH_TRUE;
4761899d1cacSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
4762899d1cacSAdrian Chadd                     "Skip RX IQ Cal due to same channel with completed RX IQ Cal\n");
4763899d1cacSAdrian Chadd         } else
4764899d1cacSAdrian Chadd #endif
4765899d1cacSAdrian Chadd             ahp->ah_skip_rx_iq_cal = AH_FALSE;
4766899d1cacSAdrian Chadd     }
4767899d1cacSAdrian Chadd 
47689778bf37SAdrian Chadd     /* FreeBSD: clear the channel survey data */
47699778bf37SAdrian Chadd     ath_hal_survey_clear(ah);
47709778bf37SAdrian Chadd 
4771899d1cacSAdrian Chadd     /*
477276bd547bSAdrian Chadd      * Fast channel change (Change synthesizer based on channel freq
477376bd547bSAdrian Chadd      * without resetting chip)
477476bd547bSAdrian Chadd      * Don't do it when
477576bd547bSAdrian Chadd      *   - Flag is not set
477676bd547bSAdrian Chadd      *   - Chip is just coming out of full sleep
477776bd547bSAdrian Chadd      *   - Channel to be set is same as current channel
477876bd547bSAdrian Chadd      *   - Channel flags are different, like when moving from 2GHz to 5GHz
477976bd547bSAdrian Chadd      *     channels
478076bd547bSAdrian Chadd      *   - Merlin: Switching in/out of fast clock enabled channels
478176bd547bSAdrian Chadd      *             (not currently coded, since fast clock is enabled
478276bd547bSAdrian Chadd      *             across the 5GHz band
478376bd547bSAdrian Chadd      *             and we already do a full reset when switching in/out
478476bd547bSAdrian Chadd      *             of 5GHz channels)
478576bd547bSAdrian Chadd      */
4786e113789bSAdrian Chadd #if 0
478776bd547bSAdrian Chadd     if (b_channel_change &&
478876bd547bSAdrian Chadd         (ahp->ah_chip_full_sleep != AH_TRUE) &&
478976bd547bSAdrian Chadd         (AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&
479076bd547bSAdrian Chadd         ((chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) &&
479176bd547bSAdrian Chadd         (((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & chan->channel_flags) ==
479276bd547bSAdrian Chadd         ((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & AH_PRIVATE(ah)->ah_curchan->channel_flags))))
479376bd547bSAdrian Chadd     {
479476bd547bSAdrian Chadd         if (ar9300_channel_change(ah, chan, ichan, macmode)) {
479576bd547bSAdrian Chadd             chan->channel_flags = ichan->channel_flags;
479676bd547bSAdrian Chadd             chan->priv_flags = ichan->priv_flags;
479776bd547bSAdrian Chadd             AH_PRIVATE(ah)->ah_curchan->ah_channel_time = 0;
479876bd547bSAdrian Chadd             AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar9300_get_tsf64(ah);
479976bd547bSAdrian Chadd 
480076bd547bSAdrian Chadd             /*
480176bd547bSAdrian Chadd              * Load the NF from history buffer of the current channel.
480276bd547bSAdrian Chadd              * NF is slow time-variant, so it is OK to use a historical value.
480376bd547bSAdrian Chadd              */
480476bd547bSAdrian Chadd             ar9300_get_nf_hist_base(ah,
480576bd547bSAdrian Chadd                 AH_PRIVATE(ah)->ah_curchan, is_scan, nf_buf);
480676bd547bSAdrian Chadd             ar9300_load_nf(ah, nf_buf);
480776bd547bSAdrian Chadd 
480876bd547bSAdrian Chadd             /* start NF calibration, without updating BB NF register*/
480976bd547bSAdrian Chadd             ar9300_start_nf_cal(ah);
481076bd547bSAdrian Chadd 
481176bd547bSAdrian Chadd             /*
481276bd547bSAdrian Chadd              * If channel_change completed and DMA was stopped
481376bd547bSAdrian Chadd              * successfully - skip the rest of reset
481476bd547bSAdrian Chadd              */
481576bd547bSAdrian Chadd             if (AH9300(ah)->ah_dma_stuck != AH_TRUE) {
4816f0949f0cSAdrian Chadd                 ar9300_disable_pll_lock_detect(ah);
481776bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
4818e113789bSAdrian Chadd                 if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready)
481976bd547bSAdrian Chadd                 {
482076bd547bSAdrian Chadd                     ar9300_mci_2g5g_switch(ah, AH_TRUE);
482176bd547bSAdrian Chadd                 }
482276bd547bSAdrian Chadd #endif
4823e113789bSAdrian Chadd                 return HAL_OK;
482476bd547bSAdrian Chadd             }
482576bd547bSAdrian Chadd          }
482676bd547bSAdrian Chadd     }
4827e113789bSAdrian Chadd #endif /* #if 0 */
482876bd547bSAdrian Chadd 
482976bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
4830e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {
483176bd547bSAdrian Chadd         ar9300_mci_disable_interrupt(ah);
483276bd547bSAdrian Chadd         if (ahp->ah_mci_ready && !save_full_sleep) {
483376bd547bSAdrian Chadd             ar9300_mci_mute_bt(ah);
483476bd547bSAdrian Chadd             OS_DELAY(20);
483576bd547bSAdrian Chadd             OS_REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
483676bd547bSAdrian Chadd         }
483776bd547bSAdrian Chadd 
483876bd547bSAdrian Chadd         ahp->ah_mci_bt_state = MCI_BT_SLEEP;
483976bd547bSAdrian Chadd         ahp->ah_mci_ready = AH_FALSE;
484076bd547bSAdrian Chadd     }
484176bd547bSAdrian Chadd #endif
484276bd547bSAdrian Chadd 
484376bd547bSAdrian Chadd     AH9300(ah)->ah_dma_stuck = AH_FALSE;
484476bd547bSAdrian Chadd #ifdef ATH_FORCE_PPM
484576bd547bSAdrian Chadd     /* Preserve force ppm state */
484676bd547bSAdrian Chadd     save_force_val =
484776bd547bSAdrian Chadd         OS_REG_READ(ah, AR_PHY_TIMING2) &
484876bd547bSAdrian Chadd         (AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL);
484976bd547bSAdrian Chadd #endif
485076bd547bSAdrian Chadd     /*
485176bd547bSAdrian Chadd      * Preserve the antenna on a channel change
485276bd547bSAdrian Chadd      */
485376bd547bSAdrian Chadd     save_def_antenna = OS_REG_READ(ah, AR_DEF_ANTENNA);
485476bd547bSAdrian Chadd     if (0 == ahp->ah_smartantenna_enable )
485576bd547bSAdrian Chadd     {
485676bd547bSAdrian Chadd         if (save_def_antenna == 0) {
485776bd547bSAdrian Chadd             save_def_antenna = 1;
485876bd547bSAdrian Chadd         }
485976bd547bSAdrian Chadd     }
486076bd547bSAdrian Chadd 
486176bd547bSAdrian Chadd     /* Save hardware flag before chip reset clears the register */
486276bd547bSAdrian Chadd     mac_sta_id1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
486376bd547bSAdrian Chadd 
486476bd547bSAdrian Chadd     /* Save led state from pci config register */
486576bd547bSAdrian Chadd     save_led_state = OS_REG_READ(ah, AR_CFG_LED) &
486676bd547bSAdrian Chadd         (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
486776bd547bSAdrian Chadd         AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW);
486876bd547bSAdrian Chadd 
486976bd547bSAdrian Chadd     /* Mark PHY inactive prior to reset, to be undone in ar9300_init_bb () */
487076bd547bSAdrian Chadd     ar9300_mark_phy_inactive(ah);
487176bd547bSAdrian Chadd 
4872*dead34f8SAdrian Chadd     /* Save/restore TSF across a potentially full reset */
4873*dead34f8SAdrian Chadd     /* XXX TODO: only do this if we do a cold reset */
4874*dead34f8SAdrian Chadd     tsf = ar9300_get_tsf64(ah);
48758c01c3dcSAdrian Chadd     if (!ar9300_chip_reset(ah, chan, reset_type)) {
487676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET, "%s: chip reset failed\n", __func__);
487776bd547bSAdrian Chadd         FAIL(HAL_EIO);
487876bd547bSAdrian Chadd     }
4879*dead34f8SAdrian Chadd     if (tsf != 0)
4880*dead34f8SAdrian Chadd         ar9300_set_tsf64(ah, tsf);
488176bd547bSAdrian Chadd 
488276bd547bSAdrian Chadd     OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
488376bd547bSAdrian Chadd 
488476bd547bSAdrian Chadd 
488576bd547bSAdrian Chadd     /* Disable JTAG */
488676bd547bSAdrian Chadd     OS_REG_SET_BIT(ah,
488776bd547bSAdrian Chadd         AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE);
488876bd547bSAdrian Chadd 
488976bd547bSAdrian Chadd     /*
489076bd547bSAdrian Chadd      * Note that ar9300_init_chain_masks() is called from within
489176bd547bSAdrian Chadd      * ar9300_process_ini() to ensure the swap bit is set before
489276bd547bSAdrian Chadd      * the pdadc table is written.
489376bd547bSAdrian Chadd      */
489476bd547bSAdrian Chadd     ecode = ar9300_process_ini(ah, chan, ichan, macmode);
489576bd547bSAdrian Chadd     if (ecode != HAL_OK) {
489676bd547bSAdrian Chadd         goto bad;
489776bd547bSAdrian Chadd     }
489876bd547bSAdrian Chadd 
489927e2ad46SAdrian Chadd     /*
490027e2ad46SAdrian Chadd      * Configuring WMAC PLL values for 25/40 MHz
490127e2ad46SAdrian Chadd      */
490227e2ad46SAdrian Chadd     if(AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah) || AR_SREV_SCORPION(ah) ) {
490327e2ad46SAdrian Chadd         if(clk_25mhz) {
490427e2ad46SAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); // 32KHz sleep clk
490527e2ad46SAdrian Chadd         } else {
490627e2ad46SAdrian Chadd             OS_REG_WRITE(ah, AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); // 32KHz sleep clk
490727e2ad46SAdrian Chadd         }
490827e2ad46SAdrian Chadd         OS_DELAY(100);
490927e2ad46SAdrian Chadd     }
491027e2ad46SAdrian Chadd 
491176bd547bSAdrian Chadd     ahp->ah_immunity_on = AH_FALSE;
491276bd547bSAdrian Chadd 
491376bd547bSAdrian Chadd     if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
491476bd547bSAdrian Chadd         ahp->tx_iq_cal_enable = OS_REG_READ_FIELD(ah,
491576bd547bSAdrian Chadd                                 AR_PHY_TX_IQCAL_CONTROL_0(ah),
491676bd547bSAdrian Chadd                                 AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL) ?
491776bd547bSAdrian Chadd                                 1 : 0;
491876bd547bSAdrian Chadd     }
491976bd547bSAdrian Chadd     ahp->tx_cl_cal_enable = (OS_REG_READ(ah, AR_PHY_CL_CAL_CTL) &
492076bd547bSAdrian Chadd                                 AR_PHY_CL_CAL_ENABLE) ? 1 : 0;
492176bd547bSAdrian Chadd 
492276bd547bSAdrian Chadd     /* For devices with full HW RIFS Rx support (Sowl/Howl/Merlin, etc),
492376bd547bSAdrian Chadd      * restore register settings from prior to reset.
492476bd547bSAdrian Chadd      */
492576bd547bSAdrian Chadd     if ((AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&
492676bd547bSAdrian Chadd         (ar9300_get_capability(ah, HAL_CAP_LDPCWAR, 0, AH_NULL) == HAL_OK))
492776bd547bSAdrian Chadd     {
492876bd547bSAdrian Chadd         /* Re-program RIFS Rx policy after reset */
492976bd547bSAdrian Chadd         ar9300_set_rifs_delay(ah, ahp->ah_rifs_enabled);
493076bd547bSAdrian Chadd     }
493176bd547bSAdrian Chadd 
493276bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
4933e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {
4934e113789bSAdrian Chadd         ar9300_mci_reset(ah, AH_FALSE, IS_CHAN_2GHZ(ichan), save_full_sleep);
493576bd547bSAdrian Chadd     }
493676bd547bSAdrian Chadd #endif
493776bd547bSAdrian Chadd 
493876bd547bSAdrian Chadd     /* Initialize Management Frame Protection */
493976bd547bSAdrian Chadd     ar9300_init_mfp(ah);
494076bd547bSAdrian Chadd 
494176bd547bSAdrian Chadd     ahp->ah_immunity_vals[0] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,
494276bd547bSAdrian Chadd         AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
494376bd547bSAdrian Chadd     ahp->ah_immunity_vals[1] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,
494476bd547bSAdrian Chadd         AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
494576bd547bSAdrian Chadd     ahp->ah_immunity_vals[2] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,
494676bd547bSAdrian Chadd         AR_PHY_SFCORR_M1_THRESH);
494776bd547bSAdrian Chadd     ahp->ah_immunity_vals[3] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,
494876bd547bSAdrian Chadd         AR_PHY_SFCORR_M2_THRESH);
494976bd547bSAdrian Chadd     ahp->ah_immunity_vals[4] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,
495076bd547bSAdrian Chadd         AR_PHY_SFCORR_M2COUNT_THR);
495176bd547bSAdrian Chadd     ahp->ah_immunity_vals[5] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,
495276bd547bSAdrian Chadd         AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
495376bd547bSAdrian Chadd 
495476bd547bSAdrian Chadd     /* Write delta slope for OFDM enabled modes (A, G, Turbo) */
4955e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) {
4956e113789bSAdrian Chadd         ar9300_set_delta_slope(ah, chan);
495776bd547bSAdrian Chadd     }
495876bd547bSAdrian Chadd 
495976bd547bSAdrian Chadd     ar9300_spur_mitigate(ah, chan);
4960e113789bSAdrian Chadd     if (!ar9300_eeprom_set_board_values(ah, chan)) {
496176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_EEPROM,
496276bd547bSAdrian Chadd             "%s: error setting board options\n", __func__);
496376bd547bSAdrian Chadd         FAIL(HAL_EIO);
496476bd547bSAdrian Chadd     }
496576bd547bSAdrian Chadd 
496676bd547bSAdrian Chadd #ifdef ATH_HAL_WAR_REG16284_APH128
496776bd547bSAdrian Chadd     /* temp work around, will be removed. */
496876bd547bSAdrian Chadd     if (AR_SREV_WASP(ah)) {
496976bd547bSAdrian Chadd         OS_REG_WRITE(ah, 0x16284, 0x1553e000);
497076bd547bSAdrian Chadd     }
497176bd547bSAdrian Chadd #endif
497276bd547bSAdrian Chadd 
497376bd547bSAdrian Chadd     OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
497476bd547bSAdrian Chadd 
497576bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));
497676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)
497776bd547bSAdrian Chadd             | mac_sta_id1
497876bd547bSAdrian Chadd             | AR_STA_ID1_RTS_USE_DEF
4979e113789bSAdrian Chadd             | (ah->ah_config.ath_hal_6mb_ack ? AR_STA_ID1_ACKCTS_6MB : 0)
498076bd547bSAdrian Chadd             | ahp->ah_sta_id1_defaults
498176bd547bSAdrian Chadd     );
498276bd547bSAdrian Chadd     ar9300_set_operating_mode(ah, opmode);
498376bd547bSAdrian Chadd 
498476bd547bSAdrian Chadd     /* Set Venice BSSID mask according to current state */
498576bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssid_mask));
498676bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssid_mask + 4));
498776bd547bSAdrian Chadd 
498876bd547bSAdrian Chadd     /* Restore previous antenna */
498976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_DEF_ANTENNA, save_def_antenna);
499076bd547bSAdrian Chadd #ifdef ATH_FORCE_PPM
499176bd547bSAdrian Chadd     /* Restore force ppm state */
499276bd547bSAdrian Chadd     tmp_reg = OS_REG_READ(ah, AR_PHY_TIMING2) &
499376bd547bSAdrian Chadd         ~(AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL);
499476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_TIMING2, tmp_reg | save_force_val);
499576bd547bSAdrian Chadd #endif
499676bd547bSAdrian Chadd 
499776bd547bSAdrian Chadd     /* then our BSSID and assocID */
499876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
499976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_BSS_ID1,
500076bd547bSAdrian Chadd         LE_READ_2(ahp->ah_bssid + 4) |
500176bd547bSAdrian Chadd         ((ahp->ah_assoc_id & 0x3fff) << AR_BSS_ID1_AID_S));
500276bd547bSAdrian Chadd 
500376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */
500476bd547bSAdrian Chadd 
500576bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR);
500676bd547bSAdrian Chadd 
500776bd547bSAdrian Chadd     /* HW beacon processing */
5008e113789bSAdrian Chadd     /*
5009e113789bSAdrian Chadd      * XXX what happens if I just leave filter_interval=0?
5010e113789bSAdrian Chadd      * it stays disabled?
5011e113789bSAdrian Chadd      */
501276bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_BCN_WEIGHT,
501376bd547bSAdrian Chadd             INIT_RSSI_BEACON_WEIGHT);
501476bd547bSAdrian Chadd     OS_REG_SET_BIT(ah, AR_HWBCNPROC1, AR_HWBCNPROC1_CRC_ENABLE |
501576bd547bSAdrian Chadd             AR_HWBCNPROC1_EXCLUDE_TIM_ELM);
5016e113789bSAdrian Chadd     if (ah->ah_config.ath_hal_beacon_filter_interval) {
501776bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_HWBCNPROC2, AR_HWBCNPROC2_FILTER_INTERVAL,
5018e113789bSAdrian Chadd                 ah->ah_config.ath_hal_beacon_filter_interval);
501976bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_HWBCNPROC2,
502076bd547bSAdrian Chadd                 AR_HWBCNPROC2_FILTER_INTERVAL_ENABLE);
502176bd547bSAdrian Chadd     }
502276bd547bSAdrian Chadd 
502376bd547bSAdrian Chadd 
502476bd547bSAdrian Chadd     /*
502576bd547bSAdrian Chadd      * Set Channel now modifies bank 6 parameters for FOWL workaround
502676bd547bSAdrian Chadd      * to force rf_pwd_icsyndiv bias current as function of synth
502776bd547bSAdrian Chadd      * frequency.Thus must be called after ar9300_process_ini() to ensure
502876bd547bSAdrian Chadd      * analog register cache is valid.
502976bd547bSAdrian Chadd      */
5030e113789bSAdrian Chadd     if (!ahp->ah_rf_hal.set_channel(ah, chan)) {
503176bd547bSAdrian Chadd         FAIL(HAL_EIO);
503276bd547bSAdrian Chadd     }
503376bd547bSAdrian Chadd 
503476bd547bSAdrian Chadd 
503576bd547bSAdrian Chadd     OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
503676bd547bSAdrian Chadd 
503776bd547bSAdrian Chadd     /* Set 1:1 QCU to DCU mapping for all queues */
503876bd547bSAdrian Chadd     for (i = 0; i < AR_NUM_DCU; i++) {
503976bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
504076bd547bSAdrian Chadd     }
504176bd547bSAdrian Chadd 
504276bd547bSAdrian Chadd     ahp->ah_intr_txqs = 0;
5043e113789bSAdrian Chadd     for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) {
504476bd547bSAdrian Chadd         ar9300_reset_tx_queue(ah, i);
504576bd547bSAdrian Chadd     }
504676bd547bSAdrian Chadd 
504776bd547bSAdrian Chadd     ar9300_init_interrupt_masks(ah, opmode);
504876bd547bSAdrian Chadd 
504976bd547bSAdrian Chadd     /* Reset ier reference count to disabled */
5050e113789bSAdrian Chadd //    OS_ATOMIC_SET(&ahp->ah_ier_ref_count, 1);
505176bd547bSAdrian Chadd     if (ath_hal_isrfkillenabled(ah)) {
505276bd547bSAdrian Chadd         ar9300_enable_rf_kill(ah);
505376bd547bSAdrian Chadd     }
505476bd547bSAdrian Chadd 
505576bd547bSAdrian Chadd     /* must be called AFTER ini is processed */
505676bd547bSAdrian Chadd     ar9300_ani_init_defaults(ah, macmode);
505776bd547bSAdrian Chadd 
505876bd547bSAdrian Chadd     ar9300_init_qos(ah);
505976bd547bSAdrian Chadd 
506076bd547bSAdrian Chadd     ar9300_init_user_settings(ah);
506176bd547bSAdrian Chadd 
506276bd547bSAdrian Chadd 
506376bd547bSAdrian Chadd     AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */
506476bd547bSAdrian Chadd 
506576bd547bSAdrian Chadd     OS_MARK(ah, AH_MARK_RESET_DONE, 0);
506676bd547bSAdrian Chadd 
506776bd547bSAdrian Chadd     /*
506876bd547bSAdrian Chadd      * disable seq number generation in hw
506976bd547bSAdrian Chadd      */
507076bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_STA_ID1,
507176bd547bSAdrian Chadd         OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
507276bd547bSAdrian Chadd 
507376bd547bSAdrian Chadd     ar9300_set_dma(ah);
507476bd547bSAdrian Chadd 
507576bd547bSAdrian Chadd     /*
507676bd547bSAdrian Chadd      * program OBS bus to see MAC interrupts
507776bd547bSAdrian Chadd      */
507876bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
5079e113789bSAdrian Chadd     if (!AH_PRIVATE(ah)->ah_caps.halMciSupport) {
508076bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8);
508176bd547bSAdrian Chadd     }
508276bd547bSAdrian Chadd #else
508376bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8);
508476bd547bSAdrian Chadd #endif
508576bd547bSAdrian Chadd 
508676bd547bSAdrian Chadd 
508776bd547bSAdrian Chadd     /* enabling AR_GTTM_IGNORE_IDLE in GTTM register so that
508876bd547bSAdrian Chadd        GTT timer will not increment if the channel idle indicates
508976bd547bSAdrian Chadd        the air is busy or NAV is still counting down */
509076bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_GTTM, AR_GTTM_IGNORE_IDLE);
509176bd547bSAdrian Chadd 
509276bd547bSAdrian Chadd     /*
509376bd547bSAdrian Chadd      * GTT debug mode setting
509476bd547bSAdrian Chadd      */
509576bd547bSAdrian Chadd     /*
509676bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0x64, 0x00320000);
509776bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0x68, 7);
509876bd547bSAdrian Chadd     OS_REG_WRITE(ah, 0x4080, 0xC);
509976bd547bSAdrian Chadd      */
510076bd547bSAdrian Chadd     /*
510176bd547bSAdrian Chadd      * Disable general interrupt mitigation by setting MIRT = 0x0
510276bd547bSAdrian Chadd      * Rx and tx interrupt mitigation are conditionally enabled below.
510376bd547bSAdrian Chadd      */
510476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_MIRT, 0);
510576bd547bSAdrian Chadd     if (ahp->ah_intr_mitigation_rx) {
510676bd547bSAdrian Chadd         /*
510776bd547bSAdrian Chadd          * Enable Interrupt Mitigation for Rx.
510876bd547bSAdrian Chadd          * If no build-specific limits for the rx interrupt mitigation
510976bd547bSAdrian Chadd          * timer have been specified, use conservative defaults.
511076bd547bSAdrian Chadd          */
511176bd547bSAdrian Chadd         #ifndef AH_RIMT_VAL_LAST
511276bd547bSAdrian Chadd             #define AH_RIMT_LAST_MICROSEC 500
511376bd547bSAdrian Chadd         #endif
511476bd547bSAdrian Chadd         #ifndef AH_RIMT_VAL_FIRST
511576bd547bSAdrian Chadd             #define AH_RIMT_FIRST_MICROSEC 2000
511676bd547bSAdrian Chadd         #endif
511776bd547bSAdrian Chadd #ifndef HOST_OFFLOAD
511876bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, AH_RIMT_LAST_MICROSEC);
511976bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, AH_RIMT_FIRST_MICROSEC);
512076bd547bSAdrian Chadd #else
512176bd547bSAdrian Chadd         /* lower mitigation level to reduce latency for offload arch. */
512276bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST,
512376bd547bSAdrian Chadd             (AH_RIMT_LAST_MICROSEC >> 2));
512476bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST,
512576bd547bSAdrian Chadd             (AH_RIMT_FIRST_MICROSEC >> 2));
512676bd547bSAdrian Chadd #endif
512776bd547bSAdrian Chadd     }
512876bd547bSAdrian Chadd 
512976bd547bSAdrian Chadd     if (ahp->ah_intr_mitigation_tx) {
513076bd547bSAdrian Chadd         /*
513176bd547bSAdrian Chadd          * Enable Interrupt Mitigation for Tx.
513276bd547bSAdrian Chadd          * If no build-specific limits for the tx interrupt mitigation
513376bd547bSAdrian Chadd          * timer have been specified, use the values preferred for
513476bd547bSAdrian Chadd          * the carrier group's products.
513576bd547bSAdrian Chadd          */
513676bd547bSAdrian Chadd         #ifndef AH_TIMT_LAST
513776bd547bSAdrian Chadd             #define AH_TIMT_LAST_MICROSEC 300
513876bd547bSAdrian Chadd         #endif
513976bd547bSAdrian Chadd         #ifndef AH_TIMT_FIRST
514076bd547bSAdrian Chadd             #define AH_TIMT_FIRST_MICROSEC 750
514176bd547bSAdrian Chadd         #endif
514276bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, AH_TIMT_LAST_MICROSEC);
514376bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, AH_TIMT_FIRST_MICROSEC);
514476bd547bSAdrian Chadd     }
514576bd547bSAdrian Chadd 
514676bd547bSAdrian Chadd     rx_chainmask = ahp->ah_rx_chainmask;
514776bd547bSAdrian Chadd 
514876bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
514976bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
515076bd547bSAdrian Chadd 
515176bd547bSAdrian Chadd     ar9300_init_bb(ah, chan);
515276bd547bSAdrian Chadd 
515376bd547bSAdrian Chadd     /* BB Step 7: Calibration */
5154899d1cacSAdrian Chadd     /*
5155899d1cacSAdrian Chadd      * Only kick off calibration not on offchan.
5156899d1cacSAdrian Chadd      * If coming back from offchan, restore prevous Cal results
5157899d1cacSAdrian Chadd      * since chip reset will clear existings.
5158899d1cacSAdrian Chadd      */
5159899d1cacSAdrian Chadd     if (!ahp->ah_skip_rx_iq_cal) {
5160899d1cacSAdrian Chadd         int i;
5161899d1cacSAdrian Chadd         /* clear existing RX cal data */
5162899d1cacSAdrian Chadd         for (i=0; i<AR9300_MAX_CHAINS; i++)
5163899d1cacSAdrian Chadd             ahp->ah_rx_cal_corr[i] = 0;
5164899d1cacSAdrian Chadd 
5165899d1cacSAdrian Chadd         ahp->ah_rx_cal_complete = AH_FALSE;
5166899d1cacSAdrian Chadd //        ahp->ah_rx_cal_chan = chan->channel;
5167899d1cacSAdrian Chadd //        ahp->ah_rx_cal_chan_flag = ichan->channel_flags;
5168899d1cacSAdrian Chadd         ahp->ah_rx_cal_chan = 0;
5169899d1cacSAdrian Chadd         ahp->ah_rx_cal_chan_flag = 0; /* XXX FreeBSD */
5170899d1cacSAdrian Chadd     }
517176bd547bSAdrian Chadd     ar9300_invalidate_saved_cals(ah, ichan);
517276bd547bSAdrian Chadd     cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr);
517376bd547bSAdrian Chadd 
517476bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
5175e113789bSAdrian Chadd     if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) {
5176e113789bSAdrian Chadd         if (IS_CHAN_2GHZ(ichan) &&
517776bd547bSAdrian Chadd             (ahp->ah_mci_bt_state == MCI_BT_SLEEP))
517876bd547bSAdrian Chadd         {
517976bd547bSAdrian Chadd             if (ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
518076bd547bSAdrian Chadd                 ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))
518176bd547bSAdrian Chadd             {
518276bd547bSAdrian Chadd                 /*
518376bd547bSAdrian Chadd                  * BT is sleeping. Check if BT wakes up duing WLAN
518476bd547bSAdrian Chadd                  * calibration. If BT wakes up during WLAN calibration, need
518576bd547bSAdrian Chadd                  * to go through all message exchanges again and recal.
518676bd547bSAdrian Chadd                  */
518776bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_BT_COEX,
518876bd547bSAdrian Chadd                     "(MCI) ### %s: BT wakes up during WLAN calibration.\n",
518976bd547bSAdrian Chadd                     __func__);
519076bd547bSAdrian Chadd                 OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
519176bd547bSAdrian Chadd                         AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
519276bd547bSAdrian Chadd                         AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
519376bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) send REMOTE_RESET\n");
519476bd547bSAdrian Chadd                 ar9300_mci_remote_reset(ah, AH_TRUE);
519576bd547bSAdrian Chadd                 ar9300_mci_send_sys_waking(ah, AH_TRUE);
519676bd547bSAdrian Chadd                 OS_DELAY(1);
5197e113789bSAdrian Chadd                 if (IS_CHAN_2GHZ(ichan)) {
519876bd547bSAdrian Chadd                     ar9300_mci_send_lna_transfer(ah, AH_TRUE);
519976bd547bSAdrian Chadd                 }
520076bd547bSAdrian Chadd                 ahp->ah_mci_bt_state = MCI_BT_AWAKE;
520176bd547bSAdrian Chadd 
520276bd547bSAdrian Chadd                 /* Redo calibration */
520376bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Re-calibrate.\n",
520476bd547bSAdrian Chadd                     __func__);
520576bd547bSAdrian Chadd                 ar9300_invalidate_saved_cals(ah, ichan);
5206e113789bSAdrian Chadd                 cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr);
520776bd547bSAdrian Chadd             }
520876bd547bSAdrian Chadd         }
520976bd547bSAdrian Chadd         ar9300_mci_enable_interrupt(ah);
521076bd547bSAdrian Chadd     }
521176bd547bSAdrian Chadd #endif
521276bd547bSAdrian Chadd 
521376bd547bSAdrian Chadd     if (!cal_ret) {
521476bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Init Cal Failed\n", __func__);
521576bd547bSAdrian Chadd         FAIL(HAL_ESELFTEST);
521676bd547bSAdrian Chadd     }
521776bd547bSAdrian Chadd 
521876bd547bSAdrian Chadd     ar9300_init_txbf(ah);
521976bd547bSAdrian Chadd #if 0
522076bd547bSAdrian Chadd     /*
522176bd547bSAdrian Chadd      * WAR for owl 1.0 - restore chain mask for 2-chain cfgs after cal
522276bd547bSAdrian Chadd      */
522376bd547bSAdrian Chadd     rx_chainmask = ahp->ah_rx_chainmask;
522476bd547bSAdrian Chadd     if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
522576bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
522676bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
522776bd547bSAdrian Chadd     }
522876bd547bSAdrian Chadd #endif
522976bd547bSAdrian Chadd 
523076bd547bSAdrian Chadd     /* Restore previous led state */
523176bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_CFG_LED, save_led_state | AR_CFG_SCLK_32KHZ);
523276bd547bSAdrian Chadd 
5233e113789bSAdrian Chadd #if ATH_BT_COEX
523476bd547bSAdrian Chadd     if (ahp->ah_bt_coex_config_type != HAL_BT_COEX_CFG_NONE) {
523576bd547bSAdrian Chadd         ar9300_init_bt_coex(ah);
523676bd547bSAdrian Chadd 
523776bd547bSAdrian Chadd #if ATH_SUPPORT_MCI
5238e113789bSAdrian Chadd         if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) {
523976bd547bSAdrian Chadd             /* Check BT state again to make sure it's not changed. */
524076bd547bSAdrian Chadd             ar9300_mci_sync_bt_state(ah);
524176bd547bSAdrian Chadd             ar9300_mci_2g5g_switch(ah, AH_TRUE);
524276bd547bSAdrian Chadd 
524376bd547bSAdrian Chadd             if ((ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&
524476bd547bSAdrian Chadd                 (ahp->ah_mci_query_bt == AH_TRUE))
524576bd547bSAdrian Chadd             {
524676bd547bSAdrian Chadd                 ahp->ah_mci_need_flush_btinfo = AH_TRUE;
524776bd547bSAdrian Chadd             }
524876bd547bSAdrian Chadd         }
524976bd547bSAdrian Chadd #endif
525076bd547bSAdrian Chadd     }
525176bd547bSAdrian Chadd #endif
525276bd547bSAdrian Chadd 
525376bd547bSAdrian Chadd     /* Start TSF2 for generic timer 8-15. */
525476bd547bSAdrian Chadd     ar9300_start_tsf2(ah);
525576bd547bSAdrian Chadd 
525676bd547bSAdrian Chadd     /* MIMO Power save setting */
525776bd547bSAdrian Chadd     if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) == HAL_OK) {
525876bd547bSAdrian Chadd         ar9300_set_sm_power_mode(ah, ahp->ah_sm_power_mode);
525976bd547bSAdrian Chadd     }
526076bd547bSAdrian Chadd 
526176bd547bSAdrian Chadd     /*
526276bd547bSAdrian Chadd      * For big endian systems turn on swapping for descriptors
526376bd547bSAdrian Chadd      */
526476bd547bSAdrian Chadd #if AH_BYTE_ORDER == AH_BIG_ENDIAN
526527e2ad46SAdrian Chadd     if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
526676bd547bSAdrian Chadd         OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB, 0);
526776bd547bSAdrian Chadd     } else {
526876bd547bSAdrian Chadd         ar9300_init_cfg_reg(ah);
526976bd547bSAdrian Chadd     }
527076bd547bSAdrian Chadd #endif
527176bd547bSAdrian Chadd 
527227e2ad46SAdrian Chadd     if ( AR_SREV_OSPREY(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah) ) {
527376bd547bSAdrian Chadd         OS_REG_RMW(ah, AR_CFG_LED, AR_CFG_LED_ASSOC_CTL, AR_CFG_LED_ASSOC_CTL);
527476bd547bSAdrian Chadd     }
527576bd547bSAdrian Chadd 
527676bd547bSAdrian Chadd #if !(defined(ART_BUILD)) && defined(ATH_SUPPORT_LED)
527776bd547bSAdrian Chadd #define REG_WRITE(_reg, _val)   *((volatile u_int32_t *)(_reg)) = (_val);
527876bd547bSAdrian Chadd #define REG_READ(_reg)          *((volatile u_int32_t *)(_reg))
527976bd547bSAdrian Chadd #define ATH_GPIO_OUT_FUNCTION3  0xB8040038
528076bd547bSAdrian Chadd #define ATH_GPIO_OE             0xB8040000
528176bd547bSAdrian Chadd     if ( AR_SREV_WASP(ah)) {
528276bd547bSAdrian Chadd         if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {
528376bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x33 << 8) );
528476bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )));
528576bd547bSAdrian Chadd         }
528676bd547bSAdrian Chadd         else {
528776bd547bSAdrian Chadd 
528876bd547bSAdrian Chadd             /* Disable 2G WLAN LED. During ath_open, reset function is called even before channel is set.
528976bd547bSAdrian Chadd             So 2GHz is taken as default and it also blinks. Hence
529076bd547bSAdrian Chadd             to avoid both from blinking, disable 2G led while in 5G mode */
529176bd547bSAdrian Chadd 
529276bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) | (1 << 13) ));
529376bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x33) );
529476bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )));
529576bd547bSAdrian Chadd         }
529676bd547bSAdrian Chadd 
529776bd547bSAdrian Chadd     }
529876bd547bSAdrian Chadd     else if (AR_SREV_SCORPION(ah)) {
529976bd547bSAdrian Chadd         if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {
530076bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x2F << 8) );
530176bd547bSAdrian Chadd     	    REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )) | (0x1 << 12)));
530276bd547bSAdrian Chadd         } else if (IS_CHAN_5GHZ((AH_PRIVATE(ah)->ah_curchan))) {
530376bd547bSAdrian Chadd             REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x2F) );
530476bd547bSAdrian Chadd     	    REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )) | (0x1 << 13)));
530576bd547bSAdrian Chadd         }
530676bd547bSAdrian Chadd     }
530727e2ad46SAdrian Chadd     else if (AR_SREV_HONEYBEE(ah)) {
530827e2ad46SAdrian Chadd             REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x32) );
530927e2ad46SAdrian Chadd             REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) ))));
531027e2ad46SAdrian Chadd     }
531176bd547bSAdrian Chadd #undef REG_READ
531276bd547bSAdrian Chadd #undef REG_WRITE
531376bd547bSAdrian Chadd #endif
531476bd547bSAdrian Chadd 
5315e113789bSAdrian Chadd     /* XXX FreeBSD What's this? -adrian */
5316e113789bSAdrian Chadd #if 0
531776bd547bSAdrian Chadd     chan->channel_flags = ichan->channel_flags;
531876bd547bSAdrian Chadd     chan->priv_flags = ichan->priv_flags;
5319e113789bSAdrian Chadd #endif
532076bd547bSAdrian Chadd 
532176bd547bSAdrian Chadd #if FIX_NOISE_FLOOR
5322e113789bSAdrian Chadd     /* XXX FreeBSD is ichan appropariate? It was curchan.. */
5323e113789bSAdrian Chadd     ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);
532476bd547bSAdrian Chadd     ar9300_load_nf(ah, nf_buf);
53258a97beffSAdrian Chadd     /* XXX TODO: handle NF load failure */
532676bd547bSAdrian Chadd     if (nf_hist_buff_reset == 1)
532776bd547bSAdrian Chadd     {
532876bd547bSAdrian Chadd         nf_hist_buff_reset = 0;
532976bd547bSAdrian Chadd     #ifndef ATH_NF_PER_CHAN
533076bd547bSAdrian Chadd 	    if (First_NFCal(ah, ichan, is_scan, chan)){
5331899d1cacSAdrian Chadd             if (ahp->ah_skip_rx_iq_cal && !is_scan) {
5332899d1cacSAdrian Chadd                 /* restore RX Cal result if existing */
5333899d1cacSAdrian Chadd                 ar9300_rx_iq_cal_restore(ah);
5334899d1cacSAdrian Chadd                 ahp->ah_skip_rx_iq_cal = AH_FALSE;
5335899d1cacSAdrian Chadd             }
533676bd547bSAdrian Chadd         }
533776bd547bSAdrian Chadd     #endif /* ATH_NF_PER_CHAN */
533876bd547bSAdrian Chadd     }
533976bd547bSAdrian Chadd     else{
534076bd547bSAdrian Chadd         ar9300_start_nf_cal(ah);
534176bd547bSAdrian Chadd     }
534276bd547bSAdrian Chadd #endif
534376bd547bSAdrian Chadd 
534476bd547bSAdrian Chadd #ifdef AH_SUPPORT_AR9300
534576bd547bSAdrian Chadd     /* BB Panic Watchdog */
534676bd547bSAdrian Chadd     if (ar9300_get_capability(ah, HAL_CAP_BB_PANIC_WATCHDOG, 0, AH_NULL) ==
534776bd547bSAdrian Chadd         HAL_OK)
534876bd547bSAdrian Chadd     {
534976bd547bSAdrian Chadd         ar9300_config_bb_panic_watchdog(ah);
535076bd547bSAdrian Chadd     }
535176bd547bSAdrian Chadd #endif
535276bd547bSAdrian Chadd 
535376bd547bSAdrian Chadd     /* While receiving unsupported rate frame receive state machine
535476bd547bSAdrian Chadd      * gets into a state 0xb and if phy_restart happens when rx
535576bd547bSAdrian Chadd      * state machine is in 0xb state, BB would go hang, if we
535676bd547bSAdrian Chadd      * see 0xb state after first bb panic, make sure that we
535776bd547bSAdrian Chadd      * disable the phy_restart.
535876bd547bSAdrian Chadd      *
535976bd547bSAdrian Chadd      * There may be multiple panics, make sure that we always do
536076bd547bSAdrian Chadd      * this if we see this panic at least once. This is required
536176bd547bSAdrian Chadd      * because reset seems to be writing from INI file.
536276bd547bSAdrian Chadd      */
536376bd547bSAdrian Chadd     if ((ar9300_get_capability(ah, HAL_CAP_PHYRESTART_CLR_WAR, 0, AH_NULL)
5364e113789bSAdrian Chadd          == HAL_OK) && (((MS((AH9300(ah)->ah_bb_panic_last_status),
536576bd547bSAdrian Chadd                 AR_PHY_BB_WD_RX_OFDM_SM)) == 0xb) ||
5366e113789bSAdrian Chadd             AH9300(ah)->ah_phyrestart_disabled) )
536776bd547bSAdrian Chadd     {
536876bd547bSAdrian Chadd         ar9300_disable_phy_restart(ah, 1);
536976bd547bSAdrian Chadd     }
537076bd547bSAdrian Chadd 
537176bd547bSAdrian Chadd 
537276bd547bSAdrian Chadd 
537376bd547bSAdrian Chadd     ahp->ah_radar1 = MS(OS_REG_READ(ah, AR_PHY_RADAR_1),
537476bd547bSAdrian Chadd                         AR_PHY_RADAR_1_CF_BIN_THRESH);
537576bd547bSAdrian Chadd     ahp->ah_dc_offset = MS(OS_REG_READ(ah, AR_PHY_TIMING2),
537676bd547bSAdrian Chadd                         AR_PHY_TIMING2_DC_OFFSET);
537776bd547bSAdrian Chadd     ahp->ah_disable_cck = MS(OS_REG_READ(ah, AR_PHY_MODE),
537876bd547bSAdrian Chadd                         AR_PHY_MODE_DISABLE_CCK);
537976bd547bSAdrian Chadd 
5380e113789bSAdrian Chadd     if (AH9300(ah)->ah_enable_keysearch_always) {
538176bd547bSAdrian Chadd         ar9300_enable_keysearch_always(ah, 1);
538276bd547bSAdrian Chadd     }
538376bd547bSAdrian Chadd 
538476bd547bSAdrian Chadd #if ATH_LOW_POWER_ENABLE
538576bd547bSAdrian Chadd #define REG_WRITE(_reg, _val)   *((volatile u_int32_t *)(_reg)) = (_val)
538676bd547bSAdrian Chadd #define REG_READ(_reg)      *((volatile u_int32_t *)(_reg))
538776bd547bSAdrian Chadd     if (AR_SREV_OSPREY(ah)) {
538876bd547bSAdrian Chadd         REG_WRITE(0xb4000080, REG_READ(0xb4000080) | 3);
538976bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_RTC_RESET, 1);
539076bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL),
539176bd547bSAdrian Chadd                         AR_PCIE_PM_CTRL_ENA);
539276bd547bSAdrian Chadd         OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_SPARE), 0xffffffff);
539376bd547bSAdrian Chadd     }
539476bd547bSAdrian Chadd #undef REG_READ
539576bd547bSAdrian Chadd #undef REG_WRITE
539676bd547bSAdrian Chadd #endif  /* ATH_LOW_POWER_ENABLE */
539776bd547bSAdrian Chadd 
5398f0949f0cSAdrian Chadd     ar9300_disable_pll_lock_detect(ah);
539976bd547bSAdrian Chadd 
540076bd547bSAdrian Chadd     /* H/W Green TX */
540176bd547bSAdrian Chadd     ar9300_control_signals_for_green_tx_mode(ah);
540276bd547bSAdrian Chadd     /* Smart Antenna, only for 5GHz on Scropion */
5403e113789bSAdrian Chadd     if (IEEE80211_IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan)) && AR_SREV_SCORPION(ah)) {
540476bd547bSAdrian Chadd         ahp->ah_smartantenna_enable = 0;
540576bd547bSAdrian Chadd     }
540676bd547bSAdrian Chadd 
540776bd547bSAdrian Chadd     ar9300_set_smart_antenna(ah, ahp->ah_smartantenna_enable);
540876bd547bSAdrian Chadd 
54093091d364SAdrian Chadd     if (AR_SREV_APHRODITE(ah) && ahp->ah_lna_div_use_bt_ant_enable)
54103091d364SAdrian Chadd         OS_REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
54113091d364SAdrian Chadd 
5412899d1cacSAdrian Chadd     if (ahp->ah_skip_rx_iq_cal && !is_scan) {
5413899d1cacSAdrian Chadd         /* restore RX Cal result if existing */
5414899d1cacSAdrian Chadd         ar9300_rx_iq_cal_restore(ah);
5415899d1cacSAdrian Chadd         ahp->ah_skip_rx_iq_cal = AH_FALSE;
5416899d1cacSAdrian Chadd     }
5417899d1cacSAdrian Chadd 
541876bd547bSAdrian Chadd 
541976bd547bSAdrian Chadd     return AH_TRUE;
542076bd547bSAdrian Chadd bad:
542176bd547bSAdrian Chadd     OS_MARK(ah, AH_MARK_RESET_DONE, ecode);
542276bd547bSAdrian Chadd     *status = ecode;
542376bd547bSAdrian Chadd 
5424899d1cacSAdrian Chadd     if (ahp->ah_skip_rx_iq_cal && !is_scan) {
5425899d1cacSAdrian Chadd         /* restore RX Cal result if existing */
5426899d1cacSAdrian Chadd         ar9300_rx_iq_cal_restore(ah);
5427899d1cacSAdrian Chadd         ahp->ah_skip_rx_iq_cal = AH_FALSE;
5428899d1cacSAdrian Chadd     }
5429899d1cacSAdrian Chadd 
543076bd547bSAdrian Chadd     return AH_FALSE;
543176bd547bSAdrian Chadd #undef FAIL
543276bd547bSAdrian Chadd }
543376bd547bSAdrian Chadd 
543476bd547bSAdrian Chadd void
ar9300_green_ap_ps_on_off(struct ath_hal * ah,u_int16_t on_off)543576bd547bSAdrian Chadd ar9300_green_ap_ps_on_off( struct ath_hal *ah, u_int16_t on_off)
543676bd547bSAdrian Chadd {
543776bd547bSAdrian Chadd     /* Set/reset the ps flag */
5438e113789bSAdrian Chadd     AH9300(ah)->green_ap_ps_on = !!on_off;
543976bd547bSAdrian Chadd }
544076bd547bSAdrian Chadd 
544176bd547bSAdrian Chadd /*
544276bd547bSAdrian Chadd  * This function returns 1, where it is possible to do
544376bd547bSAdrian Chadd  * single-chain power save.
544476bd547bSAdrian Chadd  */
544576bd547bSAdrian Chadd u_int16_t
ar9300_is_single_ant_power_save_possible(struct ath_hal * ah)544676bd547bSAdrian Chadd ar9300_is_single_ant_power_save_possible(struct ath_hal *ah)
544776bd547bSAdrian Chadd {
544876bd547bSAdrian Chadd     return AH_TRUE;
544976bd547bSAdrian Chadd }
545076bd547bSAdrian Chadd 
545176bd547bSAdrian Chadd /* To avoid compilation warnings. Functions not used when EMULATION. */
545276bd547bSAdrian Chadd /*
545376bd547bSAdrian Chadd  * ar9300_find_mag_approx()
545476bd547bSAdrian Chadd  */
545576bd547bSAdrian Chadd static int32_t
ar9300_find_mag_approx(struct ath_hal * ah,int32_t in_re,int32_t in_im)545676bd547bSAdrian Chadd ar9300_find_mag_approx(struct ath_hal *ah, int32_t in_re, int32_t in_im)
545776bd547bSAdrian Chadd {
545876bd547bSAdrian Chadd     int32_t abs_i = abs(in_re);
545976bd547bSAdrian Chadd     int32_t abs_q = abs(in_im);
546076bd547bSAdrian Chadd     int32_t max_abs, min_abs;
546176bd547bSAdrian Chadd 
546276bd547bSAdrian Chadd     if (abs_i > abs_q) {
546376bd547bSAdrian Chadd         max_abs = abs_i;
546476bd547bSAdrian Chadd         min_abs = abs_q;
546576bd547bSAdrian Chadd     } else {
546676bd547bSAdrian Chadd         max_abs = abs_q;
546776bd547bSAdrian Chadd         min_abs = abs_i;
546876bd547bSAdrian Chadd     }
546976bd547bSAdrian Chadd 
547076bd547bSAdrian Chadd     return (max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4));
547176bd547bSAdrian Chadd }
547276bd547bSAdrian Chadd 
547376bd547bSAdrian Chadd /*
547476bd547bSAdrian Chadd  * ar9300_solve_iq_cal()
547576bd547bSAdrian Chadd  * solve 4x4 linear equation used in loopback iq cal.
547676bd547bSAdrian Chadd  */
547776bd547bSAdrian Chadd static HAL_BOOL
ar9300_solve_iq_cal(struct ath_hal * ah,int32_t sin_2phi_1,int32_t cos_2phi_1,int32_t sin_2phi_2,int32_t cos_2phi_2,int32_t mag_a0_d0,int32_t phs_a0_d0,int32_t mag_a1_d0,int32_t phs_a1_d0,int32_t solved_eq[])547876bd547bSAdrian Chadd ar9300_solve_iq_cal(
547976bd547bSAdrian Chadd     struct ath_hal *ah,
548076bd547bSAdrian Chadd     int32_t sin_2phi_1,
548176bd547bSAdrian Chadd     int32_t cos_2phi_1,
548276bd547bSAdrian Chadd     int32_t sin_2phi_2,
548376bd547bSAdrian Chadd     int32_t cos_2phi_2,
548476bd547bSAdrian Chadd     int32_t mag_a0_d0,
548576bd547bSAdrian Chadd     int32_t phs_a0_d0,
548676bd547bSAdrian Chadd     int32_t mag_a1_d0,
548776bd547bSAdrian Chadd     int32_t phs_a1_d0,
548876bd547bSAdrian Chadd     int32_t solved_eq[])
548976bd547bSAdrian Chadd {
549076bd547bSAdrian Chadd     int32_t f1 = cos_2phi_1 - cos_2phi_2;
549176bd547bSAdrian Chadd     int32_t f3 = sin_2phi_1 - sin_2phi_2;
549276bd547bSAdrian Chadd     int32_t f2;
549376bd547bSAdrian Chadd     int32_t mag_tx, phs_tx, mag_rx, phs_rx;
549476bd547bSAdrian Chadd     const int32_t result_shift = 1 << 15;
549576bd547bSAdrian Chadd 
549676bd547bSAdrian Chadd     f2 = (((int64_t)f1 * (int64_t)f1) / result_shift) + (((int64_t)f3 * (int64_t)f3) / result_shift);
549776bd547bSAdrian Chadd 
549876bd547bSAdrian Chadd     if (0 == f2) {
549976bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d).\n",
550076bd547bSAdrian Chadd             __func__, __LINE__);
550176bd547bSAdrian Chadd         return AH_FALSE;
550276bd547bSAdrian Chadd     }
550376bd547bSAdrian Chadd 
550476bd547bSAdrian Chadd     /* magnitude mismatch, tx */
550576bd547bSAdrian Chadd     mag_tx = f1 * (mag_a0_d0  - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
550676bd547bSAdrian Chadd     /* phase mismatch, tx */
550776bd547bSAdrian Chadd     phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
550876bd547bSAdrian Chadd 
550976bd547bSAdrian Chadd     mag_tx = (mag_tx / f2);
551076bd547bSAdrian Chadd     phs_tx = (phs_tx / f2);
551176bd547bSAdrian Chadd 
551276bd547bSAdrian Chadd     /* magnitude mismatch, rx */
551376bd547bSAdrian Chadd     mag_rx =
551476bd547bSAdrian Chadd         mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / result_shift;
551576bd547bSAdrian Chadd     /* phase mismatch, rx */
551676bd547bSAdrian Chadd     phs_rx =
551776bd547bSAdrian Chadd         phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / result_shift;
551876bd547bSAdrian Chadd 
551976bd547bSAdrian Chadd     solved_eq[0] = mag_tx;
552076bd547bSAdrian Chadd     solved_eq[1] = phs_tx;
552176bd547bSAdrian Chadd     solved_eq[2] = mag_rx;
552276bd547bSAdrian Chadd     solved_eq[3] = phs_rx;
552376bd547bSAdrian Chadd 
552476bd547bSAdrian Chadd     return AH_TRUE;
552576bd547bSAdrian Chadd }
552676bd547bSAdrian Chadd 
552776bd547bSAdrian Chadd /*
552876bd547bSAdrian Chadd  * ar9300_calc_iq_corr()
552976bd547bSAdrian Chadd  */
553076bd547bSAdrian Chadd static HAL_BOOL
ar9300_calc_iq_corr(struct ath_hal * ah,int32_t chain_idx,const int32_t iq_res[],int32_t iqc_coeff[])553176bd547bSAdrian Chadd ar9300_calc_iq_corr(struct ath_hal *ah, int32_t chain_idx,
553276bd547bSAdrian Chadd     const int32_t iq_res[], int32_t iqc_coeff[])
553376bd547bSAdrian Chadd {
553476bd547bSAdrian Chadd     int32_t i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0;
553576bd547bSAdrian Chadd     int32_t i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1;
553676bd547bSAdrian Chadd     int32_t i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0;
553776bd547bSAdrian Chadd     int32_t i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
553876bd547bSAdrian Chadd     int32_t mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1;
553976bd547bSAdrian Chadd     int32_t phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1;
554076bd547bSAdrian Chadd     int32_t sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2;
554176bd547bSAdrian Chadd     int32_t mag_tx, phs_tx, mag_rx, phs_rx;
554276bd547bSAdrian Chadd     int32_t solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx;
554376bd547bSAdrian Chadd     int32_t q_q_coff, q_i_coff;
554476bd547bSAdrian Chadd     const int32_t res_scale = 1 << 15;
554576bd547bSAdrian Chadd     const int32_t delpt_shift = 1 << 8;
554676bd547bSAdrian Chadd     int32_t mag1, mag2;
554776bd547bSAdrian Chadd 
554876bd547bSAdrian Chadd     i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
554976bd547bSAdrian Chadd     i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
555076bd547bSAdrian Chadd     iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
555176bd547bSAdrian Chadd 
555276bd547bSAdrian Chadd     if (i2_m_q2_a0_d0 > 0x800)  {
555376bd547bSAdrian Chadd         i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
555476bd547bSAdrian Chadd     }
555576bd547bSAdrian Chadd     if (iq_corr_a0_d0 > 0x800)  {
555676bd547bSAdrian Chadd         iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
555776bd547bSAdrian Chadd     }
555876bd547bSAdrian Chadd 
555976bd547bSAdrian Chadd     i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
556076bd547bSAdrian Chadd     i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
556176bd547bSAdrian Chadd     iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
556276bd547bSAdrian Chadd 
556376bd547bSAdrian Chadd     if (i2_m_q2_a0_d1 > 0x800)  {
556476bd547bSAdrian Chadd         i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
556576bd547bSAdrian Chadd     }
556676bd547bSAdrian Chadd     if (iq_corr_a0_d1 > 0x800)  {
556776bd547bSAdrian Chadd         iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
556876bd547bSAdrian Chadd     }
556976bd547bSAdrian Chadd 
557076bd547bSAdrian Chadd     i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
557176bd547bSAdrian Chadd     i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
557276bd547bSAdrian Chadd     iq_corr_a1_d0 = iq_res[4] & 0xfff;
557376bd547bSAdrian Chadd 
557476bd547bSAdrian Chadd     if (i2_m_q2_a1_d0 > 0x800)  {
557576bd547bSAdrian Chadd         i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
557676bd547bSAdrian Chadd     }
557776bd547bSAdrian Chadd     if (iq_corr_a1_d0 > 0x800)  {
557876bd547bSAdrian Chadd         iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
557976bd547bSAdrian Chadd     }
558076bd547bSAdrian Chadd 
558176bd547bSAdrian Chadd     i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
558276bd547bSAdrian Chadd     i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
558376bd547bSAdrian Chadd     iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
558476bd547bSAdrian Chadd 
558576bd547bSAdrian Chadd     if (i2_m_q2_a1_d1 > 0x800)  {
558676bd547bSAdrian Chadd         i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
558776bd547bSAdrian Chadd     }
558876bd547bSAdrian Chadd     if (iq_corr_a1_d1 > 0x800)  {
558976bd547bSAdrian Chadd         iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
559076bd547bSAdrian Chadd     }
559176bd547bSAdrian Chadd 
559276bd547bSAdrian Chadd     if ((i2_p_q2_a0_d0 == 0) ||
559376bd547bSAdrian Chadd         (i2_p_q2_a0_d1 == 0) ||
559476bd547bSAdrian Chadd         (i2_p_q2_a1_d0 == 0) ||
559576bd547bSAdrian Chadd         (i2_p_q2_a1_d1 == 0)) {
559676bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
559776bd547bSAdrian Chadd             "%s: Divide by 0(%d):\na0_d0=%d\na0_d1=%d\na2_d0=%d\na1_d1=%d\n",
559876bd547bSAdrian Chadd             __func__, __LINE__,
559976bd547bSAdrian Chadd             i2_p_q2_a0_d0, i2_p_q2_a0_d1, i2_p_q2_a1_d0, i2_p_q2_a1_d1);
560076bd547bSAdrian Chadd         return AH_FALSE;
560176bd547bSAdrian Chadd     }
560276bd547bSAdrian Chadd 
560376bd547bSAdrian Chadd     if ((i2_p_q2_a0_d0 <= 1024) || (i2_p_q2_a0_d0 > 2047) ||
560476bd547bSAdrian Chadd             (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||
560576bd547bSAdrian Chadd             (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||
560676bd547bSAdrian Chadd             (i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||
560776bd547bSAdrian Chadd             (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||
560876bd547bSAdrian Chadd             (i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||
560976bd547bSAdrian Chadd             (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||
561076bd547bSAdrian Chadd             (i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||
561176bd547bSAdrian Chadd             (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||
561276bd547bSAdrian Chadd             (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {
561376bd547bSAdrian Chadd         return AH_FALSE;
561476bd547bSAdrian Chadd     }
561576bd547bSAdrian Chadd 
561676bd547bSAdrian Chadd     mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
561776bd547bSAdrian Chadd     phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
561876bd547bSAdrian Chadd 
561976bd547bSAdrian Chadd     mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
562076bd547bSAdrian Chadd     phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
562176bd547bSAdrian Chadd 
562276bd547bSAdrian Chadd     mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
562376bd547bSAdrian Chadd     phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
562476bd547bSAdrian Chadd 
562576bd547bSAdrian Chadd     mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
562676bd547bSAdrian Chadd     phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
562776bd547bSAdrian Chadd 
562876bd547bSAdrian Chadd     /* without analog phase shift */
562976bd547bSAdrian Chadd     sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);
563076bd547bSAdrian Chadd     /* without analog phase shift */
563176bd547bSAdrian Chadd     cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);
563276bd547bSAdrian Chadd     /* with  analog phase shift */
563376bd547bSAdrian Chadd     sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);
563476bd547bSAdrian Chadd     /* with analog phase shift */
563576bd547bSAdrian Chadd     cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);
563676bd547bSAdrian Chadd 
563776bd547bSAdrian Chadd     /* force sin^2 + cos^2 = 1; */
563876bd547bSAdrian Chadd     /* find magnitude by approximation */
563976bd547bSAdrian Chadd     mag1 = ar9300_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
564076bd547bSAdrian Chadd     mag2 = ar9300_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
564176bd547bSAdrian Chadd 
564276bd547bSAdrian Chadd     if ((mag1 == 0) || (mag2 == 0)) {
564376bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
564476bd547bSAdrian Chadd             "%s: Divide by 0(%d): mag1=%d, mag2=%d\n",
564576bd547bSAdrian Chadd             __func__, __LINE__, mag1, mag2);
564676bd547bSAdrian Chadd         return AH_FALSE;
564776bd547bSAdrian Chadd     }
564876bd547bSAdrian Chadd 
564976bd547bSAdrian Chadd     /* normalization sin and cos by mag */
565076bd547bSAdrian Chadd     sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
565176bd547bSAdrian Chadd     cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
565276bd547bSAdrian Chadd     sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
565376bd547bSAdrian Chadd     cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
565476bd547bSAdrian Chadd 
565576bd547bSAdrian Chadd     /* calculate IQ mismatch */
565676bd547bSAdrian Chadd     if (AH_FALSE == ar9300_solve_iq_cal(ah,
565776bd547bSAdrian Chadd             sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2, mag_a0_d0,
565876bd547bSAdrian Chadd             phs_a0_d0, mag_a1_d0, phs_a1_d0, solved_eq))
565976bd547bSAdrian Chadd     {
566076bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
566176bd547bSAdrian Chadd             "%s: Call to ar9300_solve_iq_cal failed.\n", __func__);
566276bd547bSAdrian Chadd         return AH_FALSE;
566376bd547bSAdrian Chadd     }
566476bd547bSAdrian Chadd 
566576bd547bSAdrian Chadd     mag_tx = solved_eq[0];
566676bd547bSAdrian Chadd     phs_tx = solved_eq[1];
566776bd547bSAdrian Chadd     mag_rx = solved_eq[2];
566876bd547bSAdrian Chadd     phs_rx = solved_eq[3];
566976bd547bSAdrian Chadd 
567076bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
567176bd547bSAdrian Chadd         "%s: chain %d: mag mismatch=%d phase mismatch=%d\n",
567276bd547bSAdrian Chadd         __func__, chain_idx, mag_tx / res_scale, phs_tx / res_scale);
567376bd547bSAdrian Chadd 
567476bd547bSAdrian Chadd     if (res_scale == mag_tx) {
567576bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
567676bd547bSAdrian Chadd             "%s: Divide by 0(%d): mag_tx=%d, res_scale=%d\n",
567776bd547bSAdrian Chadd             __func__, __LINE__, mag_tx, res_scale);
567876bd547bSAdrian Chadd         return AH_FALSE;
567976bd547bSAdrian Chadd     }
568076bd547bSAdrian Chadd 
568176bd547bSAdrian Chadd     /* calculate and quantize Tx IQ correction factor */
568276bd547bSAdrian Chadd     mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
568376bd547bSAdrian Chadd     phs_corr_tx = -phs_tx;
568476bd547bSAdrian Chadd 
568576bd547bSAdrian Chadd     q_q_coff = (mag_corr_tx * 128 / res_scale);
568676bd547bSAdrian Chadd     q_i_coff = (phs_corr_tx * 256 / res_scale);
568776bd547bSAdrian Chadd 
568876bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
568976bd547bSAdrian Chadd         "%s: tx chain %d: mag corr=%d  phase corr=%d\n",
569076bd547bSAdrian Chadd         __func__, chain_idx, q_q_coff, q_i_coff);
569176bd547bSAdrian Chadd 
569276bd547bSAdrian Chadd     if (q_i_coff < -63) {
569376bd547bSAdrian Chadd         q_i_coff = -63;
569476bd547bSAdrian Chadd     }
569576bd547bSAdrian Chadd     if (q_i_coff > 63) {
569676bd547bSAdrian Chadd         q_i_coff = 63;
569776bd547bSAdrian Chadd     }
569876bd547bSAdrian Chadd     if (q_q_coff < -63) {
569976bd547bSAdrian Chadd         q_q_coff = -63;
570076bd547bSAdrian Chadd     }
570176bd547bSAdrian Chadd     if (q_q_coff > 63) {
570276bd547bSAdrian Chadd         q_q_coff = 63;
570376bd547bSAdrian Chadd     }
570476bd547bSAdrian Chadd 
570576bd547bSAdrian Chadd     iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
570676bd547bSAdrian Chadd 
570776bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: tx chain %d: iq corr coeff=%x\n",
570876bd547bSAdrian Chadd         __func__, chain_idx, iqc_coeff[0]);
570976bd547bSAdrian Chadd 
571076bd547bSAdrian Chadd     if (-mag_rx == res_scale) {
571176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
571276bd547bSAdrian Chadd             "%s: Divide by 0(%d): mag_rx=%d, res_scale=%d\n",
571376bd547bSAdrian Chadd             __func__, __LINE__, mag_rx, res_scale);
571476bd547bSAdrian Chadd         return AH_FALSE;
571576bd547bSAdrian Chadd     }
571676bd547bSAdrian Chadd 
571776bd547bSAdrian Chadd     /* calculate and quantize Rx IQ correction factors */
571876bd547bSAdrian Chadd     mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
571976bd547bSAdrian Chadd     phs_corr_rx = -phs_rx;
572076bd547bSAdrian Chadd 
572176bd547bSAdrian Chadd     q_q_coff = (mag_corr_rx * 128 / res_scale);
572276bd547bSAdrian Chadd     q_i_coff = (phs_corr_rx * 256 / res_scale);
572376bd547bSAdrian Chadd 
572476bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
572576bd547bSAdrian Chadd         "%s: rx chain %d: mag corr=%d  phase corr=%d\n",
572676bd547bSAdrian Chadd         __func__, chain_idx, q_q_coff, q_i_coff);
572776bd547bSAdrian Chadd 
572876bd547bSAdrian Chadd     if (q_i_coff < -63) {
572976bd547bSAdrian Chadd         q_i_coff = -63;
573076bd547bSAdrian Chadd     }
573176bd547bSAdrian Chadd     if (q_i_coff > 63) {
573276bd547bSAdrian Chadd         q_i_coff = 63;
573376bd547bSAdrian Chadd     }
573476bd547bSAdrian Chadd     if (q_q_coff < -63) {
573576bd547bSAdrian Chadd         q_q_coff = -63;
573676bd547bSAdrian Chadd     }
573776bd547bSAdrian Chadd     if (q_q_coff > 63) {
573876bd547bSAdrian Chadd         q_q_coff = 63;
573976bd547bSAdrian Chadd     }
574076bd547bSAdrian Chadd 
574176bd547bSAdrian Chadd     iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
574276bd547bSAdrian Chadd 
574376bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: rx chain %d: iq corr coeff=%x\n",
574476bd547bSAdrian Chadd         __func__, chain_idx, iqc_coeff[1]);
574576bd547bSAdrian Chadd 
574676bd547bSAdrian Chadd     return AH_TRUE;
574776bd547bSAdrian Chadd }
574876bd547bSAdrian Chadd 
574976bd547bSAdrian Chadd #define MAX_MAG_DELTA 11 //maximum magnitude mismatch delta across gains
575076bd547bSAdrian Chadd #define MAX_PHS_DELTA 10 //maximum phase mismatch delta across gains
575176bd547bSAdrian Chadd #define ABS(x) ((x) >= 0 ? (x) : (-(x)))
575276bd547bSAdrian Chadd 
575376bd547bSAdrian Chadd     u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {
575476bd547bSAdrian Chadd     {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
575576bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
575676bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
575776bd547bSAdrian Chadd     {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
575876bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
575976bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
576076bd547bSAdrian Chadd     {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
576176bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
576276bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
576376bd547bSAdrian Chadd     {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
576476bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
576576bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
576676bd547bSAdrian Chadd     {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
576776bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
576876bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
576976bd547bSAdrian Chadd     {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
577076bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
577176bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
577276bd547bSAdrian Chadd     {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
577376bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
577476bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
577576bd547bSAdrian Chadd     {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
577676bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
577776bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
577876bd547bSAdrian Chadd     };
577976bd547bSAdrian Chadd 
578076bd547bSAdrian Chadd static void
ar9300_tx_iq_cal_outlier_detection(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * ichan,u_int32_t num_chains,struct coeff_t * coeff,HAL_BOOL is_cal_reusable)578176bd547bSAdrian Chadd ar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, u_int32_t num_chains,
578276bd547bSAdrian Chadd     struct coeff_t *coeff, HAL_BOOL is_cal_reusable)
578376bd547bSAdrian Chadd {
578476bd547bSAdrian Chadd     int nmeasurement, ch_idx, im;
578576bd547bSAdrian Chadd     int32_t magnitude, phase;
578676bd547bSAdrian Chadd     int32_t magnitude_max, phase_max;
578776bd547bSAdrian Chadd     int32_t magnitude_min, phase_min;
578876bd547bSAdrian Chadd 
578976bd547bSAdrian Chadd     int32_t magnitude_max_idx, phase_max_idx;
579076bd547bSAdrian Chadd     int32_t magnitude_min_idx, phase_min_idx;
579176bd547bSAdrian Chadd 
579276bd547bSAdrian Chadd     int32_t magnitude_avg, phase_avg;
579376bd547bSAdrian Chadd     int32_t outlier_mag_idx = 0;
579476bd547bSAdrian Chadd     int32_t outlier_phs_idx = 0;
579576bd547bSAdrian Chadd 
579676bd547bSAdrian Chadd 
579776bd547bSAdrian Chadd     if (AR_SREV_POSEIDON(ah)) {
579876bd547bSAdrian Chadd         HALASSERT(num_chains == 0x1);
579976bd547bSAdrian Chadd 
580076bd547bSAdrian Chadd         tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;
580176bd547bSAdrian Chadd         tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;
580276bd547bSAdrian Chadd         tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;
580376bd547bSAdrian Chadd         tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;
580476bd547bSAdrian Chadd         tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;
580576bd547bSAdrian Chadd         tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;
580676bd547bSAdrian Chadd         tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;
580776bd547bSAdrian Chadd         tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;
580876bd547bSAdrian Chadd     }
580976bd547bSAdrian Chadd 
581076bd547bSAdrian Chadd     for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {
581176bd547bSAdrian Chadd         nmeasurement = OS_REG_READ_FIELD(ah,
581276bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0);
581376bd547bSAdrian Chadd         if (nmeasurement > MAX_MEASUREMENT) {
581476bd547bSAdrian Chadd             nmeasurement = MAX_MEASUREMENT;
581576bd547bSAdrian Chadd         }
581676bd547bSAdrian Chadd 
581776bd547bSAdrian Chadd         if (!AR_SREV_SCORPION(ah)) {
581876bd547bSAdrian Chadd             /*
581976bd547bSAdrian Chadd              * reset max/min variable to min/max values so that
582076bd547bSAdrian Chadd              * we always start with 1st calibrated gain value
582176bd547bSAdrian Chadd              */
582276bd547bSAdrian Chadd             magnitude_max = -64;
582376bd547bSAdrian Chadd             phase_max     = -64;
582476bd547bSAdrian Chadd             magnitude_min = 63;
582576bd547bSAdrian Chadd             phase_min     = 63;
582676bd547bSAdrian Chadd             magnitude_avg = 0;
582776bd547bSAdrian Chadd             phase_avg     = 0;
582876bd547bSAdrian Chadd             magnitude_max_idx = 0;
582976bd547bSAdrian Chadd             magnitude_min_idx = 0;
583076bd547bSAdrian Chadd             phase_max_idx = 0;
583176bd547bSAdrian Chadd             phase_min_idx = 0;
583276bd547bSAdrian Chadd 
583376bd547bSAdrian Chadd             /* detect outlier only if nmeasurement > 1 */
583476bd547bSAdrian Chadd             if (nmeasurement > 1) {
583576bd547bSAdrian Chadd                 /* printf("----------- start outlier detection -----------\n"); */
583676bd547bSAdrian Chadd                 /*
583776bd547bSAdrian Chadd                  * find max/min and phase/mag mismatch across all calibrated gains
583876bd547bSAdrian Chadd                  */
583976bd547bSAdrian Chadd                 for (im = 0; im < nmeasurement; im++) {
584076bd547bSAdrian Chadd                     magnitude = coeff->mag_coeff[ch_idx][im][0];
584176bd547bSAdrian Chadd                     phase = coeff->phs_coeff[ch_idx][im][0];
584276bd547bSAdrian Chadd 
584376bd547bSAdrian Chadd                     magnitude_avg = magnitude_avg + magnitude;
584476bd547bSAdrian Chadd                     phase_avg = phase_avg + phase;
584576bd547bSAdrian Chadd                     if (magnitude > magnitude_max) {
584676bd547bSAdrian Chadd                         magnitude_max = magnitude;
584776bd547bSAdrian Chadd                         magnitude_max_idx = im;
584876bd547bSAdrian Chadd                     }
584976bd547bSAdrian Chadd                     if (magnitude < magnitude_min) {
585076bd547bSAdrian Chadd                         magnitude_min = magnitude;
585176bd547bSAdrian Chadd                         magnitude_min_idx = im;
585276bd547bSAdrian Chadd                     }
585376bd547bSAdrian Chadd                     if (phase > phase_max) {
585476bd547bSAdrian Chadd                         phase_max = phase;
585576bd547bSAdrian Chadd                         phase_max_idx = im;
585676bd547bSAdrian Chadd                     }
585776bd547bSAdrian Chadd                     if (phase < phase_min) {
585876bd547bSAdrian Chadd                         phase_min = phase;
585976bd547bSAdrian Chadd                         phase_min_idx = im;
586076bd547bSAdrian Chadd                     }
586176bd547bSAdrian Chadd                 }
586276bd547bSAdrian Chadd                 /* find average (exclude max abs value) */
586376bd547bSAdrian Chadd                 for (im = 0; im < nmeasurement; im++) {
586476bd547bSAdrian Chadd                     magnitude = coeff->mag_coeff[ch_idx][im][0];
586576bd547bSAdrian Chadd                     phase = coeff->phs_coeff[ch_idx][im][0];
586676bd547bSAdrian Chadd                     if ((ABS(magnitude) < ABS(magnitude_max)) ||
586776bd547bSAdrian Chadd                         (ABS(magnitude) < ABS(magnitude_min)))
586876bd547bSAdrian Chadd                     {
586976bd547bSAdrian Chadd                         magnitude_avg = magnitude_avg + magnitude;
587076bd547bSAdrian Chadd                     }
587176bd547bSAdrian Chadd                     if ((ABS(phase) < ABS(phase_max)) ||
587276bd547bSAdrian Chadd                         (ABS(phase) < ABS(phase_min)))
587376bd547bSAdrian Chadd                     {
587476bd547bSAdrian Chadd                         phase_avg = phase_avg + phase;
587576bd547bSAdrian Chadd                     }
587676bd547bSAdrian Chadd                 }
587776bd547bSAdrian Chadd                 magnitude_avg = magnitude_avg / (nmeasurement - 1);
587876bd547bSAdrian Chadd                 phase_avg = phase_avg / (nmeasurement - 1);
587976bd547bSAdrian Chadd 
588076bd547bSAdrian Chadd                 /* detect magnitude outlier */
588176bd547bSAdrian Chadd                 if (ABS(magnitude_max - magnitude_min) > MAX_MAG_DELTA) {
588276bd547bSAdrian Chadd                     if (ABS(magnitude_max - magnitude_avg) >
588376bd547bSAdrian Chadd                         ABS(magnitude_min - magnitude_avg))
588476bd547bSAdrian Chadd                     {
588576bd547bSAdrian Chadd                         /* max is outlier, force to avg */
588676bd547bSAdrian Chadd                         outlier_mag_idx = magnitude_max_idx;
588776bd547bSAdrian Chadd                     } else {
588876bd547bSAdrian Chadd                         /* min is outlier, force to avg */
588976bd547bSAdrian Chadd                         outlier_mag_idx = magnitude_min_idx;
589076bd547bSAdrian Chadd                     }
589176bd547bSAdrian Chadd                     coeff->mag_coeff[ch_idx][outlier_mag_idx][0] = magnitude_avg;
589276bd547bSAdrian Chadd                     coeff->phs_coeff[ch_idx][outlier_mag_idx][0] = phase_avg;
589376bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
589476bd547bSAdrian Chadd                         "[ch%d][outlier mag gain%d]:: "
589576bd547bSAdrian Chadd                         "mag_avg = %d (/128), phase_avg = %d (/256)\n",
589676bd547bSAdrian Chadd                         ch_idx, outlier_mag_idx, magnitude_avg, phase_avg);
589776bd547bSAdrian Chadd                 }
589876bd547bSAdrian Chadd                 /* detect phase outlier */
589976bd547bSAdrian Chadd                 if (ABS(phase_max - phase_min) > MAX_PHS_DELTA) {
590076bd547bSAdrian Chadd                     if (ABS(phase_max-phase_avg) > ABS(phase_min - phase_avg)) {
590176bd547bSAdrian Chadd                         /* max is outlier, force to avg */
590276bd547bSAdrian Chadd                         outlier_phs_idx = phase_max_idx;
590376bd547bSAdrian Chadd                     } else{
590476bd547bSAdrian Chadd                         /* min is outlier, force to avg */
590576bd547bSAdrian Chadd                         outlier_phs_idx = phase_min_idx;
590676bd547bSAdrian Chadd                     }
590776bd547bSAdrian Chadd                     coeff->mag_coeff[ch_idx][outlier_phs_idx][0] = magnitude_avg;
590876bd547bSAdrian Chadd                     coeff->phs_coeff[ch_idx][outlier_phs_idx][0] = phase_avg;
590976bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
591076bd547bSAdrian Chadd                         "[ch%d][outlier phs gain%d]:: "
591176bd547bSAdrian Chadd                         "mag_avg = %d (/128), phase_avg = %d (/256)\n",
591276bd547bSAdrian Chadd                         ch_idx, outlier_phs_idx, magnitude_avg, phase_avg);
591376bd547bSAdrian Chadd                 }
591476bd547bSAdrian Chadd             }
591576bd547bSAdrian Chadd         }
591676bd547bSAdrian Chadd 
591776bd547bSAdrian Chadd         /*printf("------------ after outlier detection -------------\n");*/
591876bd547bSAdrian Chadd         for (im = 0; im < nmeasurement; im++) {
591976bd547bSAdrian Chadd             magnitude = coeff->mag_coeff[ch_idx][im][0];
592076bd547bSAdrian Chadd             phase = coeff->phs_coeff[ch_idx][im][0];
592176bd547bSAdrian Chadd 
592276bd547bSAdrian Chadd             #if 0
592376bd547bSAdrian Chadd             printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n",
592476bd547bSAdrian Chadd                 ch_idx, im, magnitude, phase);
592576bd547bSAdrian Chadd             #endif
592676bd547bSAdrian Chadd 
592776bd547bSAdrian Chadd             coeff->iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7);
592876bd547bSAdrian Chadd 
592976bd547bSAdrian Chadd             if ((im % 2) == 0) {
593076bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
593176bd547bSAdrian Chadd                     tx_corr_coeff[im][ch_idx],
593276bd547bSAdrian Chadd                     AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
593376bd547bSAdrian Chadd                     coeff->iqc_coeff[0]);
593476bd547bSAdrian Chadd             } else {
593576bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
593676bd547bSAdrian Chadd                     tx_corr_coeff[im][ch_idx],
593776bd547bSAdrian Chadd                     AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
593876bd547bSAdrian Chadd                     coeff->iqc_coeff[0]);
593976bd547bSAdrian Chadd             }
594076bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
594176bd547bSAdrian Chadd             ichan->tx_corr_coeff[im][ch_idx] = coeff->iqc_coeff[0];
594276bd547bSAdrian Chadd #endif
594376bd547bSAdrian Chadd         }
594476bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
594576bd547bSAdrian Chadd         ichan->num_measures[ch_idx] = nmeasurement;
594676bd547bSAdrian Chadd #endif
594776bd547bSAdrian Chadd     }
594876bd547bSAdrian Chadd 
594976bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
595076bd547bSAdrian Chadd                      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
595176bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
595276bd547bSAdrian Chadd                      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
595376bd547bSAdrian Chadd 
595476bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
595576bd547bSAdrian Chadd     if (is_cal_reusable) {
595676bd547bSAdrian Chadd         ichan->one_time_txiqcal_done = AH_TRUE;
595776bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_FCS_RTT,
595876bd547bSAdrian Chadd             "(FCS) TXIQCAL saved - %d\n", ichan->channel);
595976bd547bSAdrian Chadd     }
596076bd547bSAdrian Chadd #endif
596176bd547bSAdrian Chadd }
596276bd547bSAdrian Chadd 
596376bd547bSAdrian Chadd #if ATH_SUPPORT_CAL_REUSE
596476bd547bSAdrian Chadd static void
ar9300_tx_iq_cal_apply(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * ichan)596576bd547bSAdrian Chadd ar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
596676bd547bSAdrian Chadd {
596776bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
596876bd547bSAdrian Chadd     int nmeasurement, ch_idx, im;
596976bd547bSAdrian Chadd 
597076bd547bSAdrian Chadd     u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {
597176bd547bSAdrian Chadd         {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
597276bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
597376bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
597476bd547bSAdrian Chadd         {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
597576bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
597676bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
597776bd547bSAdrian Chadd         {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
597876bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
597976bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
598076bd547bSAdrian Chadd         {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
598176bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
598276bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
598376bd547bSAdrian Chadd         {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
598476bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
598576bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
598676bd547bSAdrian Chadd         {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
598776bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
598876bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
598976bd547bSAdrian Chadd         {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
599076bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
599176bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
599276bd547bSAdrian Chadd         {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
599376bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
599476bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
599576bd547bSAdrian Chadd     };
599676bd547bSAdrian Chadd 
599776bd547bSAdrian Chadd     if (AR_SREV_POSEIDON(ah)) {
599876bd547bSAdrian Chadd         HALASSERT(ahp->ah_tx_cal_chainmask == 0x1);
599976bd547bSAdrian Chadd 
600076bd547bSAdrian Chadd         tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;
600176bd547bSAdrian Chadd         tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;
600276bd547bSAdrian Chadd         tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;
600376bd547bSAdrian Chadd         tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;
600476bd547bSAdrian Chadd         tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;
600576bd547bSAdrian Chadd         tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;
600676bd547bSAdrian Chadd         tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;
600776bd547bSAdrian Chadd         tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;
600876bd547bSAdrian Chadd     }
600976bd547bSAdrian Chadd 
601076bd547bSAdrian Chadd     for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {
601176bd547bSAdrian Chadd         if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {
601276bd547bSAdrian Chadd             continue;
601376bd547bSAdrian Chadd         }
601476bd547bSAdrian Chadd         nmeasurement = ichan->num_measures[ch_idx];
601576bd547bSAdrian Chadd 
601676bd547bSAdrian Chadd         for (im = 0; im < nmeasurement; im++) {
601776bd547bSAdrian Chadd             if ((im % 2) == 0) {
601876bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
601976bd547bSAdrian Chadd                     tx_corr_coeff[im][ch_idx],
602076bd547bSAdrian Chadd                     AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
602176bd547bSAdrian Chadd                     ichan->tx_corr_coeff[im][ch_idx]);
602276bd547bSAdrian Chadd             } else {
602376bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah,
602476bd547bSAdrian Chadd                     tx_corr_coeff[im][ch_idx],
602576bd547bSAdrian Chadd                     AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
602676bd547bSAdrian Chadd                     ichan->tx_corr_coeff[im][ch_idx]);
602776bd547bSAdrian Chadd             }
602876bd547bSAdrian Chadd         }
602976bd547bSAdrian Chadd     }
603076bd547bSAdrian Chadd 
603176bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
603276bd547bSAdrian Chadd                      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
603376bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
603476bd547bSAdrian Chadd                      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
603576bd547bSAdrian Chadd }
603676bd547bSAdrian Chadd #endif
603776bd547bSAdrian Chadd 
603876bd547bSAdrian Chadd /*
603976bd547bSAdrian Chadd  * ar9300_tx_iq_cal_hw_run is only needed for osprey/wasp/hornet
604076bd547bSAdrian Chadd  * It is not needed for jupiter/poseidon.
604176bd547bSAdrian Chadd  */
604276bd547bSAdrian Chadd HAL_BOOL
ar9300_tx_iq_cal_hw_run(struct ath_hal * ah)604376bd547bSAdrian Chadd ar9300_tx_iq_cal_hw_run(struct ath_hal *ah)
604476bd547bSAdrian Chadd {
604576bd547bSAdrian Chadd     int is_tx_gain_forced;
604676bd547bSAdrian Chadd 
604776bd547bSAdrian Chadd     is_tx_gain_forced = OS_REG_READ_FIELD(ah,
604876bd547bSAdrian Chadd         AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE);
604976bd547bSAdrian Chadd     if (is_tx_gain_forced) {
605076bd547bSAdrian Chadd         /*printf("Tx gain can not be forced during tx I/Q cal!\n");*/
605176bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0);
605276bd547bSAdrian Chadd     }
605376bd547bSAdrian Chadd 
605476bd547bSAdrian Chadd     /* enable tx IQ cal */
605576bd547bSAdrian Chadd     OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah),
605676bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_START_DO_CAL, AR_PHY_TX_IQCAL_START_DO_CAL);
605776bd547bSAdrian Chadd 
605876bd547bSAdrian Chadd     if (!ath_hal_wait(ah,
6059e113789bSAdrian Chadd             AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 0))
606076bd547bSAdrian Chadd     {
606176bd547bSAdrian Chadd         HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
606276bd547bSAdrian Chadd             "%s: Tx IQ Cal is never completed.\n", __func__);
606376bd547bSAdrian Chadd         return AH_FALSE;
606476bd547bSAdrian Chadd     }
606576bd547bSAdrian Chadd     return AH_TRUE;
606676bd547bSAdrian Chadd }
606776bd547bSAdrian Chadd 
606876bd547bSAdrian Chadd static void
ar9300_tx_iq_cal_post_proc(struct ath_hal * ah,HAL_CHANNEL_INTERNAL * ichan,int iqcal_idx,int max_iqcal,HAL_BOOL is_cal_reusable,HAL_BOOL apply_last_corr)606976bd547bSAdrian Chadd ar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan,
607076bd547bSAdrian Chadd                            int iqcal_idx, int max_iqcal,HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr)
607176bd547bSAdrian Chadd {
607276bd547bSAdrian Chadd     int nmeasurement=0, im, ix, iy, temp;
607376bd547bSAdrian Chadd     struct ath_hal_9300     *ahp = AH9300(ah);
607476bd547bSAdrian Chadd     u_int32_t txiqcal_status[AR9300_MAX_CHAINS] = {
607576bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_STATUS_B0(ah),
607676bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_STATUS_B1,
607776bd547bSAdrian Chadd         AR_PHY_TX_IQCAL_STATUS_B2,
607876bd547bSAdrian Chadd     };
607976bd547bSAdrian Chadd     const u_int32_t chan_info_tab[] = {
608076bd547bSAdrian Chadd         AR_PHY_CHAN_INFO_TAB_0,
608176bd547bSAdrian Chadd         AR_PHY_CHAN_INFO_TAB_1,
608276bd547bSAdrian Chadd         AR_PHY_CHAN_INFO_TAB_2,
608376bd547bSAdrian Chadd     };
608476bd547bSAdrian Chadd     int32_t iq_res[6];
608576bd547bSAdrian Chadd     int32_t ch_idx, j;
608676bd547bSAdrian Chadd     u_int32_t num_chains = 0;
608776bd547bSAdrian Chadd     static struct coeff_t coeff;
608876bd547bSAdrian Chadd     txiqcal_status[0] = AR_PHY_TX_IQCAL_STATUS_B0(ah);
608976bd547bSAdrian Chadd 
609076bd547bSAdrian Chadd     for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {
609176bd547bSAdrian Chadd         if (ahp->ah_tx_chainmask & (1 << ch_idx)) {
609276bd547bSAdrian Chadd             num_chains++;
609376bd547bSAdrian Chadd         }
609476bd547bSAdrian Chadd     }
609576bd547bSAdrian Chadd 
609676bd547bSAdrian Chadd     if (apply_last_corr) {
609776bd547bSAdrian Chadd 	    if (coeff.last_cal == AH_TRUE) {
609876bd547bSAdrian Chadd 		    int32_t magnitude, phase;
609976bd547bSAdrian Chadd 		    int ch_idx, im;
610076bd547bSAdrian Chadd 		    u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {
610176bd547bSAdrian Chadd 			    {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
610276bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
610376bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
610476bd547bSAdrian Chadd 			    {   AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
610576bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
610676bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},
610776bd547bSAdrian Chadd 			    {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
610876bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
610976bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
611076bd547bSAdrian Chadd 			    {   AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,
611176bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,
611276bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},
611376bd547bSAdrian Chadd 			    {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
611476bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
611576bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
611676bd547bSAdrian Chadd 			    {   AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,
611776bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,
611876bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},
611976bd547bSAdrian Chadd 			    {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
612076bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
612176bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
612276bd547bSAdrian Chadd 			    {   AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,
612376bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,
612476bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},
612576bd547bSAdrian Chadd 		    };
612676bd547bSAdrian Chadd 		    for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {
612776bd547bSAdrian Chadd 			    for (im = 0; im < coeff.last_nmeasurement; im++) {
612876bd547bSAdrian Chadd 				    magnitude = coeff.mag_coeff[ch_idx][im][0];
612976bd547bSAdrian Chadd 				    phase = coeff.phs_coeff[ch_idx][im][0];
613076bd547bSAdrian Chadd 
613176bd547bSAdrian Chadd #if 0
613276bd547bSAdrian Chadd 				    printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n",
613376bd547bSAdrian Chadd 						    ch_idx, im, magnitude, phase);
613476bd547bSAdrian Chadd #endif
613576bd547bSAdrian Chadd 
613676bd547bSAdrian Chadd 				    coeff.iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7);
613776bd547bSAdrian Chadd 				    if ((im % 2) == 0) {
613876bd547bSAdrian Chadd 					    OS_REG_RMW_FIELD(ah,
613976bd547bSAdrian Chadd 							    tx_corr_coeff[im][ch_idx],
614076bd547bSAdrian Chadd 							    AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
614176bd547bSAdrian Chadd 							    coeff.iqc_coeff[0]);
614276bd547bSAdrian Chadd 				    } else {
614376bd547bSAdrian Chadd 					    OS_REG_RMW_FIELD(ah,
614476bd547bSAdrian Chadd 							    tx_corr_coeff[im][ch_idx],
614576bd547bSAdrian Chadd 							    AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
614676bd547bSAdrian Chadd 							    coeff.iqc_coeff[0]);
614776bd547bSAdrian Chadd 				    }
614876bd547bSAdrian Chadd 			    }
614976bd547bSAdrian Chadd 		    }
615076bd547bSAdrian Chadd 		    OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
615176bd547bSAdrian Chadd 				    AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
615276bd547bSAdrian Chadd 	    }
615376bd547bSAdrian Chadd 	    return;
615476bd547bSAdrian Chadd     }
615576bd547bSAdrian Chadd 
615676bd547bSAdrian Chadd 
615776bd547bSAdrian Chadd     for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {
615876bd547bSAdrian Chadd         nmeasurement = OS_REG_READ_FIELD(ah,
615976bd547bSAdrian Chadd             AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0);
616076bd547bSAdrian Chadd         if (nmeasurement > MAX_MEASUREMENT) {
616176bd547bSAdrian Chadd             nmeasurement = MAX_MEASUREMENT;
616276bd547bSAdrian Chadd         }
616376bd547bSAdrian Chadd 
616476bd547bSAdrian Chadd         for (im = 0; im < nmeasurement; im++) {
616576bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
616676bd547bSAdrian Chadd                 "%s: Doing Tx IQ Cal for chain %d.\n", __func__, ch_idx);
616776bd547bSAdrian Chadd             if (OS_REG_READ(ah, txiqcal_status[ch_idx]) &
616876bd547bSAdrian Chadd                 AR_PHY_TX_IQCAL_STATUS_FAILED)
616976bd547bSAdrian Chadd             {
617076bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
617176bd547bSAdrian Chadd                     "%s: Tx IQ Cal failed for chain %d.\n", __func__, ch_idx);
617276bd547bSAdrian Chadd                 goto TX_IQ_CAL_FAILED_;
617376bd547bSAdrian Chadd             }
617476bd547bSAdrian Chadd 
617576bd547bSAdrian Chadd             for (j = 0; j < 3; j++) {
617676bd547bSAdrian Chadd                 u_int32_t idx = 2 * j;
617776bd547bSAdrian Chadd                 /* 3 registers for each calibration result */
617876bd547bSAdrian Chadd                 u_int32_t offset = 4 * (3 * im + j);
617976bd547bSAdrian Chadd 
618076bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
618176bd547bSAdrian Chadd                     AR_PHY_CHAN_INFO_TAB_S2_READ, 0);
618276bd547bSAdrian Chadd                 /* 32 bits */
618376bd547bSAdrian Chadd                 iq_res[idx] = OS_REG_READ(ah, chan_info_tab[ch_idx] + offset);
618476bd547bSAdrian Chadd                 OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
618576bd547bSAdrian Chadd                     AR_PHY_CHAN_INFO_TAB_S2_READ, 1);
618676bd547bSAdrian Chadd                 /* 16 bits */
618776bd547bSAdrian Chadd                 iq_res[idx + 1] = 0xffff &
618876bd547bSAdrian Chadd                     OS_REG_READ(ah, chan_info_tab[ch_idx] + offset);
618976bd547bSAdrian Chadd 
619076bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
619176bd547bSAdrian Chadd                     "%s: IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
619276bd547bSAdrian Chadd                     __func__, idx, iq_res[idx], idx + 1, iq_res[idx + 1]);
619376bd547bSAdrian Chadd             }
619476bd547bSAdrian Chadd 
619576bd547bSAdrian Chadd             if (AH_FALSE == ar9300_calc_iq_corr(
619676bd547bSAdrian Chadd                              ah, ch_idx, iq_res, coeff.iqc_coeff))
619776bd547bSAdrian Chadd             {
619876bd547bSAdrian Chadd                 HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
619976bd547bSAdrian Chadd                     "%s: Failed in calculation of IQ correction.\n",
620076bd547bSAdrian Chadd                      __func__);
620176bd547bSAdrian Chadd                 goto TX_IQ_CAL_FAILED_;
620276bd547bSAdrian Chadd             }
620376bd547bSAdrian Chadd 
620476bd547bSAdrian Chadd             coeff.phs_coeff[ch_idx][im][iqcal_idx-1] = coeff.iqc_coeff[0] & 0x7f;
620576bd547bSAdrian Chadd             coeff.mag_coeff[ch_idx][im][iqcal_idx-1] = (coeff.iqc_coeff[0] >> 7) & 0x7f;
620676bd547bSAdrian Chadd             if (coeff.mag_coeff[ch_idx][im][iqcal_idx-1] > 63) {
620776bd547bSAdrian Chadd                 coeff.mag_coeff[ch_idx][im][iqcal_idx-1] -= 128;
620876bd547bSAdrian Chadd             }
620976bd547bSAdrian Chadd             if (coeff.phs_coeff[ch_idx][im][iqcal_idx-1] > 63) {
621076bd547bSAdrian Chadd                 coeff.phs_coeff[ch_idx][im][iqcal_idx-1] -= 128;
621176bd547bSAdrian Chadd             }
621276bd547bSAdrian Chadd #if 0
621376bd547bSAdrian Chadd             ath_hal_printf(ah, "IQCAL::[ch%d][gain%d]:: mag = %d phase = %d \n",
621476bd547bSAdrian Chadd                 ch_idx, im, coeff.mag_coeff[ch_idx][im][iqcal_idx-1],
621576bd547bSAdrian Chadd                 coeff.phs_coeff[ch_idx][im][iqcal_idx-1]);
621676bd547bSAdrian Chadd #endif
621776bd547bSAdrian Chadd         }
621876bd547bSAdrian Chadd     }
621976bd547bSAdrian Chadd     //last iteration; calculate mag and phs
622076bd547bSAdrian Chadd     if (iqcal_idx == max_iqcal) {
622176bd547bSAdrian Chadd         if (max_iqcal>1) {
622276bd547bSAdrian Chadd             for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {
622376bd547bSAdrian Chadd                 for (im = 0; im < nmeasurement; im++) {
622476bd547bSAdrian Chadd                     //sort mag and phs
622576bd547bSAdrian Chadd                     for( ix=0;ix<max_iqcal-1;ix++){
622676bd547bSAdrian Chadd                         for( iy=ix+1;iy<=max_iqcal-1;iy++){
622776bd547bSAdrian Chadd                             if(coeff.mag_coeff[ch_idx][im][iy] <
622876bd547bSAdrian Chadd                                 coeff.mag_coeff[ch_idx][im][ix]) {
622976bd547bSAdrian Chadd                                 //swap
623076bd547bSAdrian Chadd                                 temp=coeff.mag_coeff[ch_idx][im][ix];
623176bd547bSAdrian Chadd                                 coeff.mag_coeff[ch_idx][im][ix] = coeff.mag_coeff[ch_idx][im][iy];
623276bd547bSAdrian Chadd                                 coeff.mag_coeff[ch_idx][im][iy] = temp;
623376bd547bSAdrian Chadd                             }
623476bd547bSAdrian Chadd                             if(coeff.phs_coeff[ch_idx][im][iy] <
623576bd547bSAdrian Chadd                                 coeff.phs_coeff[ch_idx][im][ix]){
623676bd547bSAdrian Chadd                                 //swap
623776bd547bSAdrian Chadd                                 temp=coeff.phs_coeff[ch_idx][im][ix];
623876bd547bSAdrian Chadd                                 coeff.phs_coeff[ch_idx][im][ix]=coeff.phs_coeff[ch_idx][im][iy];
623976bd547bSAdrian Chadd                                 coeff.phs_coeff[ch_idx][im][iy]=temp;
624076bd547bSAdrian Chadd                             }
624176bd547bSAdrian Chadd                         }
624276bd547bSAdrian Chadd                     }
624376bd547bSAdrian Chadd                     //select median; 3rd entry in the sorted array
624476bd547bSAdrian Chadd                     coeff.mag_coeff[ch_idx][im][0] =
624576bd547bSAdrian Chadd                         coeff.mag_coeff[ch_idx][im][max_iqcal/2];
624676bd547bSAdrian Chadd                     coeff.phs_coeff[ch_idx][im][0] =
624776bd547bSAdrian Chadd                         coeff.phs_coeff[ch_idx][im][max_iqcal/2];
624876bd547bSAdrian Chadd                     HALDEBUG(ah, HAL_DEBUG_CALIBRATE,
624976bd547bSAdrian Chadd                         "IQCAL: Median [ch%d][gain%d]:: mag = %d phase = %d \n",
625076bd547bSAdrian Chadd                         ch_idx, im,coeff.mag_coeff[ch_idx][im][0],
625176bd547bSAdrian Chadd                         coeff.phs_coeff[ch_idx][im][0]);
625276bd547bSAdrian Chadd                 }
625376bd547bSAdrian Chadd             }
625476bd547bSAdrian Chadd         }
625576bd547bSAdrian Chadd         ar9300_tx_iq_cal_outlier_detection(ah,ichan, num_chains, &coeff,is_cal_reusable);
625676bd547bSAdrian Chadd     }
625776bd547bSAdrian Chadd 
625876bd547bSAdrian Chadd 
625976bd547bSAdrian Chadd     coeff.last_nmeasurement = nmeasurement;
626076bd547bSAdrian Chadd     coeff.last_cal = AH_TRUE;
626176bd547bSAdrian Chadd 
626276bd547bSAdrian Chadd     return;
626376bd547bSAdrian Chadd 
626476bd547bSAdrian Chadd TX_IQ_CAL_FAILED_:
626576bd547bSAdrian Chadd     /* no need to print this, it is AGC failure not chip stuck */
626676bd547bSAdrian Chadd     /*ath_hal_printf(ah, "Tx IQ Cal failed(%d)\n", line);*/
626776bd547bSAdrian Chadd     coeff.last_cal = AH_FALSE;
626876bd547bSAdrian Chadd     return;
626976bd547bSAdrian Chadd }
627076bd547bSAdrian Chadd 
627176bd547bSAdrian Chadd 
627276bd547bSAdrian Chadd /*
627376bd547bSAdrian Chadd  * ar9300_disable_phy_restart
627476bd547bSAdrian Chadd  *
627576bd547bSAdrian Chadd  * In some BBpanics, we can disable the phyrestart
627676bd547bSAdrian Chadd  * disable_phy_restart
627776bd547bSAdrian Chadd  *      != 0, disable the phy restart in h/w
627876bd547bSAdrian Chadd  *      == 0, enable the phy restart in h/w
627976bd547bSAdrian Chadd  */
ar9300_disable_phy_restart(struct ath_hal * ah,int disable_phy_restart)628076bd547bSAdrian Chadd void ar9300_disable_phy_restart(struct ath_hal *ah, int disable_phy_restart)
628176bd547bSAdrian Chadd {
628276bd547bSAdrian Chadd     u_int32_t val;
628376bd547bSAdrian Chadd 
628476bd547bSAdrian Chadd     val = OS_REG_READ(ah, AR_PHY_RESTART);
628576bd547bSAdrian Chadd     if (disable_phy_restart) {
628676bd547bSAdrian Chadd         val &= ~AR_PHY_RESTART_ENA;
6287e113789bSAdrian Chadd         AH9300(ah)->ah_phyrestart_disabled = 1;
628876bd547bSAdrian Chadd     } else {
628976bd547bSAdrian Chadd         val |= AR_PHY_RESTART_ENA;
6290e113789bSAdrian Chadd         AH9300(ah)->ah_phyrestart_disabled = 0;
629176bd547bSAdrian Chadd     }
629276bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_RESTART, val);
629376bd547bSAdrian Chadd 
629476bd547bSAdrian Chadd     val = OS_REG_READ(ah, AR_PHY_RESTART);
629576bd547bSAdrian Chadd }
629676bd547bSAdrian Chadd 
629776bd547bSAdrian Chadd HAL_BOOL
ar9300_interference_is_present(struct ath_hal * ah)629876bd547bSAdrian Chadd ar9300_interference_is_present(struct ath_hal *ah)
629976bd547bSAdrian Chadd {
630076bd547bSAdrian Chadd     int i;
630176bd547bSAdrian Chadd     struct ath_hal_private  *ahpriv = AH_PRIVATE(ah);
6302e113789bSAdrian Chadd     const struct ieee80211_channel *chan = ahpriv->ah_curchan;
6303e113789bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
6304e113789bSAdrian Chadd 
6305e113789bSAdrian Chadd     if (ichan == NULL) {
6306e113789bSAdrian Chadd         ath_hal_printf(ah, "%s: called with ichan=NULL\n", __func__);
6307e113789bSAdrian Chadd         return AH_FALSE;
6308e113789bSAdrian Chadd     }
630976bd547bSAdrian Chadd 
631076bd547bSAdrian Chadd     /* This function is called after a stuck beacon, if EACS is enabled.
631176bd547bSAdrian Chadd      * If CW interference is severe, then HW goes into a loop of continuous
631276bd547bSAdrian Chadd      * stuck beacons and resets. On reset the NF cal history is cleared.
631376bd547bSAdrian Chadd      * So the median value of the history cannot be used -
631476bd547bSAdrian Chadd      * hence check if any value (Chain 0/Primary Channel)
631576bd547bSAdrian Chadd      * is outside the bounds.
631676bd547bSAdrian Chadd      */
6317e113789bSAdrian Chadd     HAL_NFCAL_HIST_FULL *h = AH_HOME_CHAN_NFCAL_HIST(ah, ichan);
631876bd547bSAdrian Chadd     for (i = 0; i < HAL_NF_CAL_HIST_LEN_FULL; i++) {
631976bd547bSAdrian Chadd         if (h->nf_cal_buffer[i][0] >
6320e113789bSAdrian Chadd             AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta)
632176bd547bSAdrian Chadd         {
632276bd547bSAdrian Chadd             return AH_TRUE;
632376bd547bSAdrian Chadd         }
632476bd547bSAdrian Chadd 
632576bd547bSAdrian Chadd     }
632676bd547bSAdrian Chadd     return AH_FALSE;
632776bd547bSAdrian Chadd }
632876bd547bSAdrian Chadd 
632976bd547bSAdrian Chadd #if ATH_SUPPORT_CRDC
633076bd547bSAdrian Chadd void
ar9300_crdc_rx_notify(struct ath_hal * ah,struct ath_rx_status * rxs)633176bd547bSAdrian Chadd ar9300_crdc_rx_notify(struct ath_hal *ah, struct ath_rx_status *rxs)
633276bd547bSAdrian Chadd {
633376bd547bSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
633476bd547bSAdrian Chadd     int rssi_index;
633576bd547bSAdrian Chadd 
633676bd547bSAdrian Chadd     if ((!AR_SREV_WASP(ah)) ||
633776bd547bSAdrian Chadd         (!ahpriv->ah_config.ath_hal_crdc_enable)) {
633876bd547bSAdrian Chadd         return;
633976bd547bSAdrian Chadd     }
634076bd547bSAdrian Chadd 
634176bd547bSAdrian Chadd     if (rxs->rs_isaggr && rxs->rs_moreaggr) {
634276bd547bSAdrian Chadd         return;
634376bd547bSAdrian Chadd     }
634476bd547bSAdrian Chadd 
634576bd547bSAdrian Chadd     if ((rxs->rs_rssi_ctl0 >= HAL_RSSI_BAD) ||
634676bd547bSAdrian Chadd         (rxs->rs_rssi_ctl1 >= HAL_RSSI_BAD)) {
634776bd547bSAdrian Chadd         return;
634876bd547bSAdrian Chadd     }
634976bd547bSAdrian Chadd 
635076bd547bSAdrian Chadd     rssi_index = ah->ah_crdc_rssi_ptr % HAL_MAX_CRDC_RSSI_SAMPLE;
635176bd547bSAdrian Chadd 
635276bd547bSAdrian Chadd     ah->ah_crdc_rssi_sample[0][rssi_index] = rxs->rs_rssi_ctl0;
635376bd547bSAdrian Chadd     ah->ah_crdc_rssi_sample[1][rssi_index] = rxs->rs_rssi_ctl1;
635476bd547bSAdrian Chadd 
635576bd547bSAdrian Chadd     ah->ah_crdc_rssi_ptr++;
635676bd547bSAdrian Chadd }
635776bd547bSAdrian Chadd 
635876bd547bSAdrian Chadd static int
ar9300_crdc_avg_rssi(struct ath_hal * ah,int chain)635976bd547bSAdrian Chadd ar9300_crdc_avg_rssi(struct ath_hal *ah, int chain)
636076bd547bSAdrian Chadd {
636176bd547bSAdrian Chadd     int crdc_rssi_sum = 0;
636276bd547bSAdrian Chadd     int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr, i;
636376bd547bSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
636476bd547bSAdrian Chadd     int crdc_window = ahpriv->ah_config.ath_hal_crdc_window;
636576bd547bSAdrian Chadd 
636676bd547bSAdrian Chadd     if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) {
636776bd547bSAdrian Chadd         crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE;
636876bd547bSAdrian Chadd     }
636976bd547bSAdrian Chadd 
637076bd547bSAdrian Chadd     for (i = 1; i <= crdc_window; i++) {
637176bd547bSAdrian Chadd         crdc_rssi_sum +=
637276bd547bSAdrian Chadd             ah->ah_crdc_rssi_sample[chain]
637376bd547bSAdrian Chadd             [(crdc_rssi_ptr - i) % HAL_MAX_CRDC_RSSI_SAMPLE];
637476bd547bSAdrian Chadd     }
637576bd547bSAdrian Chadd 
637676bd547bSAdrian Chadd     return crdc_rssi_sum / crdc_window;
637776bd547bSAdrian Chadd }
637876bd547bSAdrian Chadd 
637976bd547bSAdrian Chadd static void
ar9300_crdc_activate(struct ath_hal * ah,int rssi_diff,int enable)638076bd547bSAdrian Chadd ar9300_crdc_activate(struct ath_hal *ah, int rssi_diff, int enable)
638176bd547bSAdrian Chadd {
638276bd547bSAdrian Chadd     int val, orig_val;
638376bd547bSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
638476bd547bSAdrian Chadd     int crdc_numerator = ahpriv->ah_config.ath_hal_crdc_numerator;
638576bd547bSAdrian Chadd     int crdc_denominator = ahpriv->ah_config.ath_hal_crdc_denominator;
638676bd547bSAdrian Chadd     int c = (rssi_diff * crdc_numerator) / crdc_denominator;
638776bd547bSAdrian Chadd 
638876bd547bSAdrian Chadd     val = orig_val = OS_REG_READ(ah, AR_PHY_MULTICHAIN_CTRL);
638976bd547bSAdrian Chadd     val &= 0xffffff00;
639076bd547bSAdrian Chadd     if (enable) {
639176bd547bSAdrian Chadd         val |= 0x1;
639276bd547bSAdrian Chadd         val |= ((c << 1) & 0xff);
639376bd547bSAdrian Chadd     }
639476bd547bSAdrian Chadd     OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_CTRL, val);
639576bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "diff: %02d comp: %02d reg: %08x %08x\n",
639676bd547bSAdrian Chadd         rssi_diff, c, orig_val, val);
639776bd547bSAdrian Chadd }
639876bd547bSAdrian Chadd 
639976bd547bSAdrian Chadd 
ar9300_chain_rssi_diff_compensation(struct ath_hal * ah)640076bd547bSAdrian Chadd void ar9300_chain_rssi_diff_compensation(struct ath_hal *ah)
640176bd547bSAdrian Chadd {
640276bd547bSAdrian Chadd     struct ath_hal_private  *ahpriv = AH_PRIVATE(ah);
640376bd547bSAdrian Chadd     int crdc_window = ahpriv->ah_config.ath_hal_crdc_window;
640476bd547bSAdrian Chadd     int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr;
640576bd547bSAdrian Chadd     int crdc_rssi_thresh = ahpriv->ah_config.ath_hal_crdc_rssithresh;
640676bd547bSAdrian Chadd     int crdc_diff_thresh = ahpriv->ah_config.ath_hal_crdc_diffthresh;
640776bd547bSAdrian Chadd     int avg_rssi[2], avg_rssi_diff;
640876bd547bSAdrian Chadd 
640976bd547bSAdrian Chadd     if ((!AR_SREV_WASP(ah)) ||
641076bd547bSAdrian Chadd         (!ahpriv->ah_config.ath_hal_crdc_enable)) {
641176bd547bSAdrian Chadd         if (ah->ah_crdc_rssi_ptr) {
641276bd547bSAdrian Chadd             ar9300_crdc_activate(ah, 0, 0);
641376bd547bSAdrian Chadd             ah->ah_crdc_rssi_ptr = 0;
641476bd547bSAdrian Chadd         }
641576bd547bSAdrian Chadd         return;
641676bd547bSAdrian Chadd     }
641776bd547bSAdrian Chadd 
641876bd547bSAdrian Chadd     if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) {
641976bd547bSAdrian Chadd         crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE;
642076bd547bSAdrian Chadd     }
642176bd547bSAdrian Chadd 
642276bd547bSAdrian Chadd     if (crdc_rssi_ptr < crdc_window) {
642376bd547bSAdrian Chadd         return;
642476bd547bSAdrian Chadd     }
642576bd547bSAdrian Chadd 
642676bd547bSAdrian Chadd     avg_rssi[0] = ar9300_crdc_avg_rssi(ah, 0);
642776bd547bSAdrian Chadd     avg_rssi[1] = ar9300_crdc_avg_rssi(ah, 1);
642876bd547bSAdrian Chadd     avg_rssi_diff = avg_rssi[1] - avg_rssi[0];
642976bd547bSAdrian Chadd 
643076bd547bSAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "crdc: avg: %02d %02d ",
643176bd547bSAdrian Chadd         avg_rssi[0], avg_rssi[1]);
643276bd547bSAdrian Chadd 
643376bd547bSAdrian Chadd     if ((avg_rssi[0] < crdc_rssi_thresh) &&
643476bd547bSAdrian Chadd         (avg_rssi[1] < crdc_rssi_thresh)) {
643576bd547bSAdrian Chadd         ar9300_crdc_activate(ah, 0, 0);
643676bd547bSAdrian Chadd     } else {
643776bd547bSAdrian Chadd         if (ABS(avg_rssi_diff) >= crdc_diff_thresh) {
643876bd547bSAdrian Chadd             ar9300_crdc_activate(ah, avg_rssi_diff, 1);
643976bd547bSAdrian Chadd         } else {
644076bd547bSAdrian Chadd             ar9300_crdc_activate(ah, 0, 1);
644176bd547bSAdrian Chadd         }
644276bd547bSAdrian Chadd     }
644376bd547bSAdrian Chadd }
644476bd547bSAdrian Chadd #endif
644576bd547bSAdrian Chadd 
644676bd547bSAdrian Chadd #if ATH_ANT_DIV_COMB
644776bd547bSAdrian Chadd HAL_BOOL
ar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal * ah,HAL_BOOL enable,const struct ieee80211_channel * chan)6448e113789bSAdrian Chadd ar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, const struct ieee80211_channel *chan)
644976bd547bSAdrian Chadd {
645076bd547bSAdrian Chadd     u_int32_t value;
645176bd547bSAdrian Chadd     u_int32_t regval;
645276bd547bSAdrian Chadd     struct ath_hal_9300 *ahp = AH9300(ah);
645376bd547bSAdrian Chadd     HAL_CHANNEL_INTERNAL *ichan;
645476bd547bSAdrian Chadd     struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
645576bd547bSAdrian Chadd     HAL_CAPABILITIES *pcap = &ahpriv->ah_caps;
645676bd547bSAdrian Chadd 
64573091d364SAdrian Chadd     HALDEBUG(ah, HAL_DEBUG_RESET | HAL_DEBUG_BT_COEX,
64583091d364SAdrian Chadd       "%s: called; enable=%d\n", __func__, enable);
64593091d364SAdrian Chadd 
646076bd547bSAdrian Chadd     if (AR_SREV_POSEIDON(ah)) {
646176bd547bSAdrian Chadd         // Make sure this scheme is only used for WB225(Astra)
646276bd547bSAdrian Chadd         ahp->ah_lna_div_use_bt_ant_enable = enable;
646376bd547bSAdrian Chadd 
646476bd547bSAdrian Chadd         ichan = ar9300_check_chan(ah, chan);
646576bd547bSAdrian Chadd         if ( ichan == AH_NULL ) {
646676bd547bSAdrian Chadd             HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n",
6467e113789bSAdrian Chadd                      __func__, chan->ic_freq, chan->ic_flags);
646876bd547bSAdrian Chadd             return AH_FALSE;
646976bd547bSAdrian Chadd         }
647076bd547bSAdrian Chadd 
647176bd547bSAdrian Chadd         if ( enable == TRUE ) {
6472e113789bSAdrian Chadd             pcap->halAntDivCombSupport = TRUE;
647376bd547bSAdrian Chadd         } else {
6474e113789bSAdrian Chadd             pcap->halAntDivCombSupport = pcap->halAntDivCombSupportOrg;
647576bd547bSAdrian Chadd         }
647676bd547bSAdrian Chadd 
647776bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
647876bd547bSAdrian Chadd #define AR_SWITCH_TABLE_COM2_ALL_S (0)
647976bd547bSAdrian Chadd         value = ar9300_ant_ctrl_common2_get(ah, IS_CHAN_2GHZ(ichan));
648076bd547bSAdrian Chadd         if ( enable == TRUE ) {
648176bd547bSAdrian Chadd             value &= ~AR_SWITCH_TABLE_COM2_ALL;
6482e113789bSAdrian Chadd             value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable;
648376bd547bSAdrian Chadd         }
64849389d5a9SAdrian Chadd 	HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value);
648576bd547bSAdrian Chadd         OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
648676bd547bSAdrian Chadd 
648776bd547bSAdrian Chadd         value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control);
648876bd547bSAdrian Chadd         /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */
648976bd547bSAdrian Chadd         regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
649076bd547bSAdrian Chadd         regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */
649176bd547bSAdrian Chadd         regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S;
649276bd547bSAdrian Chadd         /* enable_lnadiv */
649376bd547bSAdrian Chadd         regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK);
649476bd547bSAdrian Chadd         regval |= ((value >> 6) & 0x1) <<
649576bd547bSAdrian Chadd                   MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT;
649676bd547bSAdrian Chadd         if ( enable == TRUE ) {
649776bd547bSAdrian Chadd             regval |= ANT_DIV_ENABLE;
649876bd547bSAdrian Chadd         }
649976bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
650076bd547bSAdrian Chadd 
650176bd547bSAdrian Chadd         /* enable fast_div */
650276bd547bSAdrian Chadd         regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
650376bd547bSAdrian Chadd         regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);
650476bd547bSAdrian Chadd         regval |= ((value >> 7) & 0x1) <<
650576bd547bSAdrian Chadd                   BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT;
650676bd547bSAdrian Chadd         if ( enable == TRUE ) {
650776bd547bSAdrian Chadd             regval |= FAST_DIV_ENABLE;
650876bd547bSAdrian Chadd         }
650976bd547bSAdrian Chadd         OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
651076bd547bSAdrian Chadd 
651176bd547bSAdrian Chadd         if ( AR_SREV_POSEIDON_11_OR_LATER(ah) ) {
6512e113789bSAdrian Chadd             if (pcap->halAntDivCombSupport) {
651376bd547bSAdrian Chadd                 /* If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning */
651476bd547bSAdrian Chadd                 regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
651576bd547bSAdrian Chadd                 /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */
651676bd547bSAdrian Chadd                 regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |
651776bd547bSAdrian Chadd                              MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |
651876bd547bSAdrian Chadd                              MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK |
651976bd547bSAdrian Chadd                              MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK));
652076bd547bSAdrian Chadd                 regval |= (HAL_ANT_DIV_COMB_LNA1 <<
652176bd547bSAdrian Chadd                            MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
652276bd547bSAdrian Chadd                 regval |= (HAL_ANT_DIV_COMB_LNA2 <<
652376bd547bSAdrian Chadd                            MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
652476bd547bSAdrian Chadd                 OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
652576bd547bSAdrian Chadd             }
652676bd547bSAdrian Chadd         }
652776bd547bSAdrian Chadd 
652876bd547bSAdrian Chadd         return AH_TRUE;
65293091d364SAdrian Chadd     } else if (AR_SREV_APHRODITE(ah)) {
65303091d364SAdrian Chadd         ahp->ah_lna_div_use_bt_ant_enable = enable;
65313091d364SAdrian Chadd         if (enable) {
65323091d364SAdrian Chadd                 OS_REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, ANT_DIV_ENABLE);
65333091d364SAdrian Chadd                 OS_REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT));
65343091d364SAdrian Chadd                 OS_REG_SET_BIT(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
65353091d364SAdrian Chadd                 OS_REG_SET_BIT(ah, AR_PHY_RESTART, RESTART__ENABLE_ANT_FAST_DIV_M2FLAG__MASK);
65363091d364SAdrian Chadd                 OS_REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
653776bd547bSAdrian Chadd         } else {
65383091d364SAdrian Chadd                 OS_REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, ANT_DIV_ENABLE);
65393091d364SAdrian Chadd                 OS_REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT));
65403091d364SAdrian Chadd                 OS_REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
65413091d364SAdrian Chadd                 OS_REG_CLR_BIT(ah, AR_PHY_RESTART, RESTART__ENABLE_ANT_FAST_DIV_M2FLAG__MASK);
65423091d364SAdrian Chadd                 OS_REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
65433091d364SAdrian Chadd 
65443091d364SAdrian Chadd                 regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
65453091d364SAdrian Chadd                 regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |
65463091d364SAdrian Chadd                              MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |
65473091d364SAdrian Chadd                              MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK |
65483091d364SAdrian Chadd                              MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK));
65493091d364SAdrian Chadd                 regval |= (HAL_ANT_DIV_COMB_LNA1 <<
65503091d364SAdrian Chadd                            MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);
65513091d364SAdrian Chadd                 regval |= (HAL_ANT_DIV_COMB_LNA2 <<
65523091d364SAdrian Chadd                            MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);
65533091d364SAdrian Chadd 
65543091d364SAdrian Chadd                 OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
65553091d364SAdrian Chadd         }
655676bd547bSAdrian Chadd         return AH_TRUE;
655776bd547bSAdrian Chadd     }
65583091d364SAdrian Chadd     return AH_TRUE;
655976bd547bSAdrian Chadd }
656076bd547bSAdrian Chadd #endif /* ATH_ANT_DIV_COMB */
6561