Path: blob/main/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c
48526 views
/*1* Copyright (c) 2013 Qualcomm Atheros, Inc.2*3* Permission to use, copy, modify, and/or distribute this software for any4* purpose with or without fee is hereby granted, provided that the above5* copyright notice and this permission notice appear in all copies.6*7* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH8* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY9* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,10* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM11* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR12* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR13* PERFORMANCE OF THIS SOFTWARE.14*/15161718#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"22#include "ah_devid.h"23#include "ah_desc.h"2425#include "ar9300.h"26#include "ar9300reg.h"27#include "ar9300phy.h"28#include "ar9300desc.h"2930#define FIX_NOISE_FLOOR 1313233/* Additional Time delay to wait after activiting the Base band */34#define BASE_ACTIVATE_DELAY 100 /* usec */35#define RTC_PLL_SETTLE_DELAY 100 /* usec */36#define COEF_SCALE_S 2437#define HT40_CHANNEL_CENTER_SHIFT 10 /* MHz */3839#define DELPT 324041/* XXX Duplicates! (in ar9300desc.h) */42#if 043extern HAL_BOOL ar9300_reset_tx_queue(struct ath_hal *ah, u_int q);44extern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q);45#endif464748#define MAX_MEASUREMENT 849#define MAXIQCAL 350struct coeff_t {51int32_t mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];52int32_t phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];53int32_t iqc_coeff[2];54int last_nmeasurement;55HAL_BOOL last_cal;56};5758static HAL_BOOL ar9300_tx_iq_cal_hw_run(struct ath_hal *ah);59static void ar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan,60int iqcal_idx, int max_iqcal, HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr);61static void ar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan,62u_int32_t num_chains, struct coeff_t *coeff, HAL_BOOL is_cal_reusable);63#if ATH_SUPPORT_CAL_REUSE64static void ar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan);65#endif666768static inline void ar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, int column);69static inline void ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan);70static inline HAL_BOOL ar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_corr);71static inline void ar9300_init_user_settings(struct ath_hal *ah);7273#ifdef HOST_OFFLOAD74/*75* For usb offload solution, some USB registers must be tuned76* to gain better stability/performance but these registers77* might be changed while doing wlan reset so do this here78*/79#define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah) \80do { \81if (AR_SREV_HORNET(__ah) || AR_SREV_WASP(__ah)) { \82volatile u_int32_t *usb_ctrl_r1 = (u_int32_t *) 0xb8116c84; \83volatile u_int32_t *usb_ctrl_r2 = (u_int32_t *) 0xb8116c88; \84*usb_ctrl_r1 = (*usb_ctrl_r1 & 0xffefffff); \85*usb_ctrl_r2 = (*usb_ctrl_r2 & 0xfc1fffff) | (1 << 21) | (3 << 22); \86} \87} while (0)88#else89#define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah)90#endif9192/*93* Note: the below is the version that ships with ath9k.94* The original HAL version is above.95*/9697static void98ar9300_disable_pll_lock_detect(struct ath_hal *ah)99{100/*101* On AR9330 and AR9340 devices, some PHY registers must be102* tuned to gain better stability/performance. These registers103* might be changed while doing wlan reset so the registers must104* be reprogrammed after each reset.105*/106if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah)) {107HALDEBUG(ah, HAL_DEBUG_RESET, "%s: called\n", __func__);108OS_REG_CLR_BIT(ah, AR_PHY_USB_CTRL1, (1 << 20));109OS_REG_RMW(ah, AR_PHY_USB_CTRL2,110(1 << 21) | (0xf << 22),111(1 << 21) | (0x3 << 22));112}113}114115static inline void116ar9300_attach_hw_platform(struct ath_hal *ah)117{118struct ath_hal_9300 *ahp = AH9300(ah);119120ahp->ah_hwp = HAL_TRUE_CHIP;121return;122}123124/* Adjust various register settings based on half/quarter rate clock setting.125* This includes: +USEC, TX/RX latency,126* + IFS params: slot, eifs, misc etc.127* SIFS stays the same.128*/129static void130ar9300_set_ifs_timing(struct ath_hal *ah, struct ieee80211_channel *chan)131{132u_int32_t tx_lat, rx_lat, usec, slot, regval, eifs;133134regval = OS_REG_READ(ah, AR_USEC);135regval &= ~(AR_USEC_RX_LATENCY | AR_USEC_TX_LATENCY | AR_USEC_USEC);136if (IEEE80211_IS_CHAN_HALF(chan)) { /* half rates */137slot = ar9300_mac_to_clks(ah, AR_SLOT_HALF);138eifs = ar9300_mac_to_clks(ah, AR_EIFS_HALF);139if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */140rx_lat = SM(AR_RX_LATENCY_HALF_FAST_CLOCK, AR_USEC_RX_LATENCY);141tx_lat = SM(AR_TX_LATENCY_HALF_FAST_CLOCK, AR_USEC_TX_LATENCY);142usec = SM(AR_USEC_HALF_FAST_CLOCK, AR_USEC_USEC);143} else {144rx_lat = SM(AR_RX_LATENCY_HALF, AR_USEC_RX_LATENCY);145tx_lat = SM(AR_TX_LATENCY_HALF, AR_USEC_TX_LATENCY);146usec = SM(AR_USEC_HALF, AR_USEC_USEC);147}148} else { /* quarter rate */149slot = ar9300_mac_to_clks(ah, AR_SLOT_QUARTER);150eifs = ar9300_mac_to_clks(ah, AR_EIFS_QUARTER);151if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */152rx_lat = SM(AR_RX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_RX_LATENCY);153tx_lat = SM(AR_TX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_TX_LATENCY);154usec = SM(AR_USEC_QUARTER_FAST_CLOCK, AR_USEC_USEC);155} else {156rx_lat = SM(AR_RX_LATENCY_QUARTER, AR_USEC_RX_LATENCY);157tx_lat = SM(AR_TX_LATENCY_QUARTER, AR_USEC_TX_LATENCY);158usec = SM(AR_USEC_QUARTER, AR_USEC_USEC);159}160}161162OS_REG_WRITE(ah, AR_USEC, (usec | regval | tx_lat | rx_lat));163OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);164OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);165}166167168/*169* This inline function configures the chip either170* to encrypt/decrypt management frames or pass thru171*/172static inline void173ar9300_init_mfp(struct ath_hal * ah)174{175u_int32_t mfpcap, mfp_qos;176177ath_hal_getcapability(ah, HAL_CAP_MFP, 0, &mfpcap);178179if (mfpcap == HAL_MFP_QOSDATA) {180/* Treat like legacy hardware. Do not touch the MFP registers. */181HALDEBUG(ah, HAL_DEBUG_RESET, "%s forced to use QOSDATA\n", __func__);182return;183}184185/* MFP support (Sowl 1.0 or greater) */186if (mfpcap == HAL_MFP_HW_CRYPTO) {187/* configure hardware MFP support */188HALDEBUG(ah, HAL_DEBUG_RESET, "%s using HW crypto\n", __func__);189OS_REG_RMW_FIELD(ah,190AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, AR_AES_MUTE_MASK1_FC_MGMT_MFP);191OS_REG_RMW(ah,192AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE,193AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);194/*195* Mask used to construct AAD for CCMP-AES196* Cisco spec defined bits 0-3 as mask197* IEEE802.11w defined as bit 4.198*/199if (ath_hal_get_mfp_qos(ah)) {200mfp_qos = AR_MFP_QOS_MASK_IEEE;201} else {202mfp_qos = AR_MFP_QOS_MASK_CISCO;203}204OS_REG_RMW_FIELD(ah,205AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_QOS, mfp_qos);206} else if (mfpcap == HAL_MFP_PASSTHRU) {207/* Disable en/decrypt by hardware */208HALDEBUG(ah, HAL_DEBUG_RESET, "%s using passthru\n", __func__);209OS_REG_RMW(ah,210AR_PCU_MISC_MODE2,211AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT,212AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);213}214}215216void217ar9300_get_channel_centers(struct ath_hal *ah, const struct ieee80211_channel *chan,218CHAN_CENTERS *centers)219{220int8_t extoff;221struct ath_hal_9300 *ahp = AH9300(ah);222HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);223224if (!IEEE80211_IS_CHAN_HT40(chan)) {225centers->ctl_center = centers->ext_center =226centers->synth_center = ichan->channel;227return;228}229230HALASSERT(IEEE80211_IS_CHAN_HT40(chan));231232/*233* In 20/40 phy mode, the center frequency is234* "between" the primary and extension channels.235*/236if (IEEE80211_IS_CHAN_HT40U(chan)) {237centers->synth_center = ichan->channel + HT40_CHANNEL_CENTER_SHIFT;238extoff = 1;239} else {240centers->synth_center = ichan->channel - HT40_CHANNEL_CENTER_SHIFT;241extoff = -1;242}243244centers->ctl_center =245centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);246centers->ext_center =247centers->synth_center +248(extoff * ((ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_20) ?249HT40_CHANNEL_CENTER_SHIFT : 15));250}251252/*253* Read the noise-floor values from the HW.254* Specifically, read the minimum clear-channel assessment value for255* each chain, for both the control and extension channels.256* (The received power level during clear-channel periods is the257* noise floor.)258* These noise floor values computed by the HW will be stored in the259* NF history buffer.260* The HW sometimes produces bogus NF values. To avoid using these261* bogus values, the NF data is (a) range-limited, and (b) filtered.262* However, this data-processing is done when reading the NF values263* out of the history buffer. The history buffer stores the raw values.264* This allows the NF history buffer to be used to check for interference.265* A single high NF reading might be a bogus HW value, but if the NF266* readings are consistently high, it must be due to interference.267* This is the purpose of storing raw NF values in the history buffer,268* rather than processed values. By looking at a history of NF values269* that have not been range-limited, we can check if they are consistently270* high (due to interference).271*/272#define AH_NF_SIGN_EXTEND(nf) \273((nf) & 0x100) ? \2740 - (((nf) ^ 0x1ff) + 1) : \275(nf)276void277ar9300_upload_noise_floor(struct ath_hal *ah, int is_2g,278int16_t nfarray[HAL_NUM_NF_READINGS])279{280int16_t nf;281int chan, chain;282u_int32_t regs[HAL_NUM_NF_READINGS] = {283/* control channel */284AR_PHY_CCA_0, /* chain 0 */285AR_PHY_CCA_1, /* chain 1 */286AR_PHY_CCA_2, /* chain 2 */287/* extension channel */288AR_PHY_EXT_CCA, /* chain 0 */289AR_PHY_EXT_CCA_1, /* chain 1 */290AR_PHY_EXT_CCA_2, /* chain 2 */291};292u_int8_t chainmask;293294/*295* Within a given channel (ctl vs. ext), the CH0, CH1, and CH2296* masks and shifts are the same, though they differ for the297* control vs. extension channels.298*/299u_int32_t masks[2] = {300AR_PHY_MINCCA_PWR, /* control channel */301AR_PHY_EXT_MINCCA_PWR, /* extention channel */302};303u_int8_t shifts[2] = {304AR_PHY_MINCCA_PWR_S, /* control channel */305AR_PHY_EXT_MINCCA_PWR_S, /* extention channel */306};307308/*309* Force NF calibration for all chains.310*/311if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {312chainmask = 0x01;313} else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(ah)) {314chainmask = 0x03;315} else {316chainmask = 0x07;317}318319for (chan = 0; chan < 2 /*ctl,ext*/; chan++) {320for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {321int i;322323if (!((chainmask >> chain) & 0x1)) {324continue;325}326i = chan * AR9300_MAX_CHAINS + chain;327nf = (OS_REG_READ(ah, regs[i]) & masks[chan]) >> shifts[chan];328nfarray[i] = AH_NF_SIGN_EXTEND(nf);329}330}331}332333/* ar9300_get_min_cca_pwr -334* Used by the scan function for a quick read of the noise floor.335* This is used to detect presence of CW interference such as video bridge.336* The noise floor is assumed to have been already started during reset337* called during channel change. The function checks if the noise floor338* reading is done. In case it has been done, it reads the noise floor value.339* If the noise floor calibration has not been finished, it assumes this is340* due to presence of CW interference an returns a high value for noise floor,341* derived from the CW interference threshold + margin fudge factor.342*/343#define BAD_SCAN_NF_MARGIN (30)344int16_t ar9300_get_min_cca_pwr(struct ath_hal *ah)345{346int16_t nf;347// struct ath_hal_private *ahpriv = AH_PRIVATE(ah);348349350if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) {351nf = MS(OS_REG_READ(ah, AR_PHY_CCA_0), AR9280_PHY_MINCCA_PWR);352if (nf & 0x100) {353nf = 0 - ((nf ^ 0x1ff) + 1);354}355} else {356/* NF calibration is not done, assume CW interference */357nf = AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta +358BAD_SCAN_NF_MARGIN;359}360return nf;361}362363364/*365* Noise Floor values for all chains.366* Most recently updated values from the NF history buffer are used.367*/368void ar9300_chain_noise_floor(struct ath_hal *ah, int16_t *nf_buf,369struct ieee80211_channel *chan, int is_scan)370{371struct ath_hal_9300 *ahp = AH9300(ah);372int i, nf_hist_len, recent_nf_index = 0;373HAL_NFCAL_HIST_FULL *h;374u_int8_t rx_chainmask = ahp->ah_rx_chainmask | (ahp->ah_rx_chainmask << 3);375HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);376HALASSERT(ichan);377378#ifdef ATH_NF_PER_CHAN379/* Fill 0 if valid internal channel is not found */380if (ichan == AH_NULL) {381OS_MEMZERO(nf_buf, sizeof(nf_buf[0])*HAL_NUM_NF_READINGS);382return;383}384h = &ichan->nf_cal_hist;385nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;386#else387/*388* If a scan is not in progress, then the most recent value goes389* into ahpriv->nf_cal_hist. If a scan is in progress, then390* the most recent value goes into ichan->nf_cal_hist.391* Thus, return the value from ahpriv->nf_cal_hist if there's392* no scan, and if the specified channel is the current channel.393* Otherwise, return the noise floor from ichan->nf_cal_hist.394*/395if ((!is_scan) && chan == AH_PRIVATE(ah)->ah_curchan) {396h = &AH_PRIVATE(ah)->nf_cal_hist;397nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;398} else {399/* Fill 0 if valid internal channel is not found */400if (ichan == AH_NULL) {401OS_MEMZERO(nf_buf, sizeof(nf_buf[0])*HAL_NUM_NF_READINGS);402return;403}404/*405* It is okay to treat a HAL_NFCAL_HIST_SMALL struct as if it were a406* HAL_NFCAL_HIST_FULL struct, as long as only the index 0 of the407* nf_cal_buffer is used (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1])408*/409h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;410nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL;411}412#endif413/* Get most recently updated values from nf cal history buffer */414recent_nf_index =415(h->base.curr_index) ? h->base.curr_index - 1 : nf_hist_len - 1;416417for (i = 0; i < HAL_NUM_NF_READINGS; i++) {418/* Fill 0 for unsupported chains */419if (!(rx_chainmask & (1 << i))) {420nf_buf[i] = 0;421continue;422}423nf_buf[i] = h->nf_cal_buffer[recent_nf_index][i];424}425}426427/*428* Return the current NF value in register.429* If the current NF cal is not completed, return 0.430*/431int16_t ar9300_get_nf_from_reg(struct ath_hal *ah, struct ieee80211_channel *chan, int wait_time)432{433int16_t nfarray[HAL_NUM_NF_READINGS] = {0};434int is_2g = 0;435HAL_CHANNEL_INTERNAL *ichan = NULL;436437ichan = ath_hal_checkchannel(ah, chan);438if (ichan == NULL)439return (0);440441if (wait_time <= 0) {442return 0;443}444445if (!ath_hal_waitfor(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF, 0, wait_time)) {446ath_hal_printf(ah, "%s: NF cal is not complete in %dus", __func__, wait_time);447return 0;448}449is_2g = !! (IS_CHAN_2GHZ(ichan));450ar9300_upload_noise_floor(ah, is_2g, nfarray);451452return nfarray[0];453}454455/*456* Pick up the medium one in the noise floor buffer and update the457* corresponding range for valid noise floor values458*/459static int16_t460ar9300_get_nf_hist_mid(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, int reading,461int hist_len)462{463int16_t nfval;464int16_t sort[HAL_NF_CAL_HIST_LEN_FULL]; /* upper bound for hist_len */465int i, j;466467468for (i = 0; i < hist_len; i++) {469sort[i] = h->nf_cal_buffer[i][reading];470HALDEBUG(ah, HAL_DEBUG_NFCAL,471"nf_cal_buffer[%d][%d] = %d\n", i, reading, (int)sort[i]);472}473for (i = 0; i < hist_len - 1; i++) {474for (j = 1; j < hist_len - i; j++) {475if (sort[j] > sort[j - 1]) {476nfval = sort[j];477sort[j] = sort[j - 1];478sort[j - 1] = nfval;479}480}481}482nfval = sort[(hist_len - 1) >> 1];483484return nfval;485}486487static int16_t ar9300_limit_nf_range(struct ath_hal *ah, int16_t nf)488{489if (nf < AH9300(ah)->nfp->min) {490return AH9300(ah)->nfp->nominal;491} else if (nf > AH9300(ah)->nfp->max) {492return AH9300(ah)->nfp->max;493}494return nf;495}496497#ifndef ATH_NF_PER_CHAN498inline static void499ar9300_reset_nf_hist_buff(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)500{501HAL_CHAN_NFCAL_HIST *h = &ichan->nf_cal_hist;502HAL_NFCAL_HIST_FULL *home = &AH_PRIVATE(ah)->nf_cal_hist;503int i;504505/*506* Copy the value for the channel in question into the home-channel507* NF history buffer. The channel NF is probably a value filled in by508* a prior background channel scan, but if no scan has been done then509* it is the nominal noise floor filled in by ath_hal_init_NF_buffer510* for this chip and the channel's band.511* Replicate this channel NF into all entries of the home-channel NF512* history buffer.513* If the channel NF was filled in by a channel scan, it has not had514* bounds limits applied to it yet - do so now. It is important to515* apply bounds limits to the priv_nf value that gets loaded into the516* WLAN chip's min_cca_pwr register field. It is also necessary to517* apply bounds limits to the nf_cal_buffer[] elements. Since we are518* replicating a single NF reading into all nf_cal_buffer elements,519* if the single reading were above the CW_INT threshold, the CW_INT520* check in ar9300_get_nf would immediately conclude that CW interference521* is present, even though we're not supposed to set CW_INT unless522* NF values are _consistently_ above the CW_INT threshold.523* Applying the bounds limits to the nf_cal_buffer contents fixes this524* problem.525*/526for (i = 0; i < HAL_NUM_NF_READINGS; i ++) {527int j;528int16_t nf;529/*530* No need to set curr_index, since it already has a value in531* the range [0..HAL_NF_CAL_HIST_LEN_FULL), and all nf_cal_buffer532* values will be the same.533*/534nf = ar9300_limit_nf_range(ah, h->nf_cal_buffer[0][i]);535for (j = 0; j < HAL_NF_CAL_HIST_LEN_FULL; j++) {536home->nf_cal_buffer[j][i] = nf;537}538AH_PRIVATE(ah)->nf_cal_hist.base.priv_nf[i] = nf;539}540}541#endif542543/*544* Update the noise floor buffer as a ring buffer545*/546static int16_t547ar9300_update_nf_hist_buff(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h,548int16_t *nfarray, int hist_len)549{550int i, nr;551int16_t nf_no_lim_chain0;552553nf_no_lim_chain0 = ar9300_get_nf_hist_mid(ah, h, 0, hist_len);554555HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] BEFORE\n", __func__, __LINE__);556for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) {557for (i = 0; i < HAL_NUM_NF_READINGS; i++) {558HALDEBUG(ah, HAL_DEBUG_NFCAL,559"nf_cal_buffer[%d][%d] = %d\n",560nr, i, (int)h->nf_cal_buffer[nr][i]);561}562}563for (i = 0; i < HAL_NUM_NF_READINGS; i++) {564h->nf_cal_buffer[h->base.curr_index][i] = nfarray[i];565h->base.priv_nf[i] = ar9300_limit_nf_range(566ah, ar9300_get_nf_hist_mid(ah, h, i, hist_len));567}568HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] AFTER\n", __func__, __LINE__);569for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) {570for (i = 0; i < HAL_NUM_NF_READINGS; i++) {571HALDEBUG(ah, HAL_DEBUG_NFCAL,572"nf_cal_buffer[%d][%d] = %d\n",573nr, i, (int)h->nf_cal_buffer[nr][i]);574}575}576577if (++h->base.curr_index >= hist_len) {578h->base.curr_index = 0;579}580581return nf_no_lim_chain0;582}583584#ifdef UNUSED585static HAL_BOOL586get_noise_floor_thresh(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *chan,587int16_t *nft)588{589struct ath_hal_9300 *ahp = AH9300(ah);590591592switch (chan->channel_flags & CHANNEL_ALL_NOTURBO) {593case CHANNEL_A:594case CHANNEL_A_HT20:595case CHANNEL_A_HT40PLUS:596case CHANNEL_A_HT40MINUS:597*nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_5);598break;599case CHANNEL_B:600case CHANNEL_G:601case CHANNEL_G_HT20:602case CHANNEL_G_HT40PLUS:603case CHANNEL_G_HT40MINUS:604*nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_2);605break;606default:607HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel flags 0x%x\n",608__func__, chan->channel_flags);609return AH_FALSE;610}611return AH_TRUE;612}613#endif614615/*616* Read the NF and check it against the noise floor threshhold617*/618#define IS(_c, _f) (((_c)->channel_flags & _f) || 0)619static int620ar9300_store_new_nf(struct ath_hal *ah, struct ieee80211_channel *chan,621int is_scan)622{623// struct ath_hal_private *ahpriv = AH_PRIVATE(ah);624int nf_hist_len;625int16_t nf_no_lim;626int16_t nfarray[HAL_NUM_NF_READINGS] = {0};627HAL_NFCAL_HIST_FULL *h;628int is_2g = 0;629HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);630struct ath_hal_9300 *ahp = AH9300(ah);631632if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {633u_int32_t tsf32, nf_cal_dur_tsf;634/*635* The reason the NF calibration did not complete may just be that636* not enough time has passed since the NF calibration was started,637* because under certain conditions (when first moving to a new638* channel) the NF calibration may be checked very repeatedly.639* Or, there may be CW interference keeping the NF calibration640* from completing. Check the delta time between when the NF641* calibration was started and now to see whether the NF calibration642* should have already completed (but hasn't, probably due to CW643* interference), or hasn't had enough time to finish yet.644*/645/*646* AH_NF_CAL_DUR_MAX_TSF - A conservative maximum time that the647* HW should need to finish a NF calibration. If the HW648* does not complete a NF calibration within this time period,649* there must be a problem - probably CW interference.650* AH_NF_CAL_PERIOD_MAX_TSF - A conservative maximum time between651* check of the HW's NF calibration being finished.652* If the difference between the current TSF and the TSF653* recorded when the NF calibration started is larger than this654* value, the TSF must have been reset.655* In general, we expect the TSF to only be reset during656* regular operation for STAs, not for APs. However, an657* AP's TSF could be reset when joining an IBSS.658* There's an outside chance that this could result in the659* CW_INT flag being erroneously set, if the TSF adjustment660* is smaller than AH_NF_CAL_PERIOD_MAX_TSF but larger than661* AH_NF_CAL_DUR_TSF. However, even if this does happen,662* it shouldn't matter, as the IBSS case shouldn't be663* concerned about CW_INT.664*/665/* AH_NF_CAL_DUR_TSF - 90 sec in usec units */666#define AH_NF_CAL_DUR_TSF (90 * 1000 * 1000)667/* AH_NF_CAL_PERIOD_MAX_TSF - 180 sec in usec units */668#define AH_NF_CAL_PERIOD_MAX_TSF (180 * 1000 * 1000)669/* wraparound handled by using unsigned values */670tsf32 = ar9300_get_tsf32(ah);671nf_cal_dur_tsf = tsf32 - AH9300(ah)->nf_tsf32;672if (nf_cal_dur_tsf > AH_NF_CAL_PERIOD_MAX_TSF) {673/*674* The TSF must have gotten reset during the NF cal -675* just reset the NF TSF timestamp, so the next time676* this function is called, the timestamp comparison677* will be valid.678*/679AH9300(ah)->nf_tsf32 = tsf32;680} else if (nf_cal_dur_tsf > AH_NF_CAL_DUR_TSF) {681HALDEBUG(ah, HAL_DEBUG_CALIBRATE,682"%s: NF did not complete in calibration window\n", __func__);683/* the NF incompletion is probably due to CW interference */684chan->ic_state |= IEEE80211_CHANSTATE_CWINT;685}686return 0; /* HW's NF measurement not finished */687}688HALDEBUG(ah, HAL_DEBUG_NFCAL,689"%s[%d] chan %d\n", __func__, __LINE__, ichan->channel);690is_2g = !! IS_CHAN_2GHZ(ichan);691ar9300_upload_noise_floor(ah, is_2g, nfarray);692693/* Update the NF buffer for each chain masked by chainmask */694#ifdef ATH_NF_PER_CHAN695h = &ichan->nf_cal_hist;696nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;697#else698if (is_scan) {699/*700* This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct701* rather than a HAL_NFCAL_HIST_FULL struct.702* As long as we only use the first history element of nf_cal_buffer703* (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use704* HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably.705*/706h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;707nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL;708} else {709h = &AH_PRIVATE(ah)->nf_cal_hist;710nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;711}712#endif713714/*715* nf_no_lim = median value from NF history buffer without bounds limits,716* priv_nf = median value from NF history buffer with bounds limits.717*/718nf_no_lim = ar9300_update_nf_hist_buff(ah, h, nfarray, nf_hist_len);719ichan->rawNoiseFloor = h->base.priv_nf[0];720721/* check if there is interference */722// ichan->channel_flags &= (~CHANNEL_CW_INT);723/*724* Use AR9300_EMULATION to check for emulation purpose as PCIE Device ID725* 0xABCD is recognized as valid Osprey as WAR in some EVs.726*/727if (nf_no_lim > ahp->nfp->nominal + ahp->nf_cw_int_delta) {728/*729* Since this CW interference check is being applied to the730* median element of the NF history buffer, this indicates that731* the CW interference is persistent. A single high NF reading732* will not show up in the median, and thus will not cause the733* CW_INT flag to be set.734*/735HALDEBUG(ah, HAL_DEBUG_NFCAL,736"%s: NF Cal: CW interferer detected through NF: %d\n",737__func__, nf_no_lim);738chan->ic_state |= IEEE80211_CHANSTATE_CWINT;739}740return 1; /* HW's NF measurement finished */741}742#undef IS743744static inline void745ar9300_get_delta_slope_values(struct ath_hal *ah, u_int32_t coef_scaled,746u_int32_t *coef_mantissa, u_int32_t *coef_exponent)747{748u_int32_t coef_exp, coef_man;749750/*751* ALGO -> coef_exp = 14-floor(log2(coef));752* floor(log2(x)) is the highest set bit position753*/754for (coef_exp = 31; coef_exp > 0; coef_exp--) {755if ((coef_scaled >> coef_exp) & 0x1) {756break;757}758}759/* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */760HALASSERT(coef_exp);761coef_exp = 14 - (coef_exp - COEF_SCALE_S);762763764/*765* ALGO -> coef_man = floor(coef* 2^coef_exp+0.5);766* The coefficient is already shifted up for scaling767*/768coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));769770*coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp);771*coef_exponent = coef_exp - 16;772}773774#define MAX_ANALOG_START 319 /* XXX */775776/*777* Delta slope coefficient computation.778* Required for OFDM operation.779*/780static void781ar9300_set_delta_slope(struct ath_hal *ah, struct ieee80211_channel *chan)782{783u_int32_t coef_scaled, ds_coef_exp, ds_coef_man;784u_int32_t fclk = COEFF; /* clock * 2.5 */785786u_int32_t clock_mhz_scaled = 0x1000000 * fclk;787CHAN_CENTERS centers;788789/*790* half and quarter rate can divide the scaled clock by 2 or 4791* scale for selected channel bandwidth792*/793if (IEEE80211_IS_CHAN_HALF(chan)) {794clock_mhz_scaled = clock_mhz_scaled >> 1;795} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {796clock_mhz_scaled = clock_mhz_scaled >> 2;797}798799/*800* ALGO -> coef = 1e8/fcarrier*fclock/40;801* scaled coef to provide precision for this floating calculation802*/803ar9300_get_channel_centers(ah, chan, ¢ers);804coef_scaled = clock_mhz_scaled / centers.synth_center;805806ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp);807808OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_MAN, ds_coef_man);809OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);810811/*812* For Short GI,813* scaled coeff is 9/10 that of normal coeff814*/815coef_scaled = (9 * coef_scaled) / 10;816817ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp);818819/* for short gi */820OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_MAN, ds_coef_man);821OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_EXP, ds_coef_exp);822}823824#define IS(_c, _f) (IEEE80211_IS_ ## _f(_c))825826/*827* XXX FreeBSD: This should be turned into something generic in ath_hal!828*/829HAL_CHANNEL_INTERNAL *830ar9300_check_chan(struct ath_hal *ah, const struct ieee80211_channel *chan)831{832833if (chan == NULL) {834return AH_NULL;835}836837if ((IS(chan, CHAN_2GHZ) ^ IS(chan, CHAN_5GHZ)) == 0) {838HALDEBUG(ah, HAL_DEBUG_CHANNEL,839"%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n",840__func__, chan->ic_freq , chan->ic_flags);841return AH_NULL;842}843844/*845* FreeBSD sets multiple flags, so this will fail.846*/847#if 0848if ((IS(chan, CHAN_OFDM) ^ IS(chan, CHAN_CCK) ^ IS(chan, CHAN_DYN) ^849IS(chan, CHAN_HT20) ^ IS(chan, CHAN_HT40U) ^850IS(chan, CHAN_HT40D)) == 0)851{852HALDEBUG(ah, HAL_DEBUG_CHANNEL,853"%s: invalid channel %u/0x%x; not marked as "854"OFDM or CCK or DYN or HT20 or HT40PLUS or HT40MINUS\n",855__func__, chan->ic_freq , chan->ic_flags);856return AH_NULL;857}858#endif859860return (ath_hal_checkchannel(ah, chan));861}862#undef IS863864static void865ar9300_set_11n_regs(struct ath_hal *ah, struct ieee80211_channel *chan,866HAL_HT_MACMODE macmode)867{868u_int32_t phymode;869// struct ath_hal_9300 *ahp = AH9300(ah);870u_int32_t enable_dac_fifo;871872/* XXX */873enable_dac_fifo =874OS_REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO;875876/* Enable 11n HT, 20 MHz */877phymode =878AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_SHORT_GI_40879| enable_dac_fifo;880/* Configure baseband for dynamic 20/40 operation */881if (IEEE80211_IS_CHAN_HT40(chan)) {882phymode |= AR_PHY_GC_DYN2040_EN;883/* Configure control (primary) channel at +-10MHz */884if (IEEE80211_IS_CHAN_HT40U(chan)) {885phymode |= AR_PHY_GC_DYN2040_PRI_CH;886}887888#if 0889/* Configure 20/25 spacing */890if (ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_25) {891phymode |= AR_PHY_GC_DYN2040_EXT_CH;892}893#endif894}895896/* make sure we preserve INI settings */897phymode |= OS_REG_READ(ah, AR_PHY_GEN_CTRL);898899/* EV 62881/64991 - turn off Green Field detection for Maverick STA beta */900phymode &= ~AR_PHY_GC_GF_DETECT_EN;901902OS_REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode);903904/* Set IFS timing for half/quarter rates */905if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) {906u_int32_t modeselect = OS_REG_READ(ah, AR_PHY_MODE);907908if (IEEE80211_IS_CHAN_HALF(chan)) {909modeselect |= AR_PHY_MS_HALF_RATE;910} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {911modeselect |= AR_PHY_MS_QUARTER_RATE;912}913OS_REG_WRITE(ah, AR_PHY_MODE, modeselect);914915ar9300_set_ifs_timing(ah, chan);916OS_REG_RMW_FIELD(917ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 0x3);918}919920/* Configure MAC for 20/40 operation */921ar9300_set_11n_mac2040(ah, macmode);922923/* global transmit timeout (25 TUs default)*/924/* XXX - put this elsewhere??? */925OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);926927/* carrier sense timeout */928OS_REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);929}930931/*932* Spur mitigation for MRC CCK933*/934static void935ar9300_spur_mitigate_mrc_cck(struct ath_hal *ah, struct ieee80211_channel *chan)936{937int i;938/* spur_freq_for_osprey - hardcoded by Systems team for now. */939u_int32_t spur_freq_for_osprey[4] = { 2420, 2440, 2464, 2480 };940u_int32_t spur_freq_for_jupiter[2] = { 2440, 2464};941int cur_bb_spur, negative = 0, cck_spur_freq;942u_int8_t* spur_fbin_ptr = NULL;943int synth_freq;944int range = 10;945int max_spurcounts = OSPREY_EEPROM_MODAL_SPURS;946HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);947948/*949* Need to verify range +/- 10 MHz in control channel, otherwise spur950* is out-of-band and can be ignored.951*/952if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) ||953AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {954spur_fbin_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1);955if (spur_fbin_ptr[0] == 0) {956return; /* No spur in the mode */957}958if (IEEE80211_IS_CHAN_HT40(chan)) {959range = 19;960if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH)961== 0x0)962{963synth_freq = ichan->channel + 10;964} else {965synth_freq = ichan->channel - 10;966}967} else {968range = 10;969synth_freq = ichan->channel;970}971} else if(AR_SREV_JUPITER(ah)) {972range = 5;973max_spurcounts = 2; /* Hardcoded by Jupiter Systems team for now. */974synth_freq = ichan->channel;975} else {976range = 10;977max_spurcounts = 4; /* Hardcoded by Osprey Systems team for now. */978synth_freq = ichan->channel;979}980981for (i = 0; i < max_spurcounts; i++) {982negative = 0;983984if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) ||985AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {986cur_bb_spur =987FBIN2FREQ(spur_fbin_ptr[i], HAL_FREQ_BAND_2GHZ) - synth_freq;988} else if(AR_SREV_JUPITER(ah)) {989cur_bb_spur = spur_freq_for_jupiter[i] - synth_freq;990} else {991cur_bb_spur = spur_freq_for_osprey[i] - synth_freq;992}993994if (cur_bb_spur < 0) {995negative = 1;996cur_bb_spur = -cur_bb_spur;997}998if (cur_bb_spur < range) {999cck_spur_freq = (int)((cur_bb_spur << 19) / 11);1000if (negative == 1) {1001cck_spur_freq = -cck_spur_freq;1002}1003cck_spur_freq = cck_spur_freq & 0xfffff;1004/*OS_REG_WRITE_field(ah, BB_agc_control.ycok_max, 0x7);*/1005OS_REG_RMW_FIELD(ah,1006AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7);1007/*OS_REG_WRITE_field(ah, BB_cck_spur_mit.spur_rssi_thr, 0x7f);*/1008OS_REG_RMW_FIELD(ah,1009AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f);1010/*OS_REG_WRITE(ah, BB_cck_spur_mit.spur_filter_type, 0x2);*/1011OS_REG_RMW_FIELD(ah,1012AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE, 0x2);1013/*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x1);*/1014OS_REG_RMW_FIELD(ah,1015AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x1);1016/*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, cck_spur_freq);*/1017OS_REG_RMW_FIELD(ah,1018AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ,1019cck_spur_freq);1020return;1021}1022}10231024/*OS_REG_WRITE(ah, BB_agc_control.ycok_max, 0x5);*/1025OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5);1026/*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x0);*/1027OS_REG_RMW_FIELD(ah,1028AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0);1029/*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, 0x0);*/1030OS_REG_RMW_FIELD(ah,1031AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0x0);1032}10331034/* Spur mitigation for OFDM */1035static void1036ar9300_spur_mitigate_ofdm(struct ath_hal *ah, struct ieee80211_channel *chan)1037{1038int synth_freq;1039int range = 10;1040int freq_offset = 0;1041int spur_freq_sd = 0;1042int spur_subchannel_sd = 0;1043int spur_delta_phase = 0;1044int mask_index = 0;1045int i;1046int mode;1047u_int8_t* spur_chans_ptr;1048struct ath_hal_9300 *ahp;1049ahp = AH9300(ah);1050HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);10511052if (IS_CHAN_5GHZ(ichan)) {1053spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 0);1054mode = 0;1055} else {1056spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1);1057mode = 1;1058}10591060if (IEEE80211_IS_CHAN_HT40(chan)) {1061range = 19;1062if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH)1063== 0x0)1064{1065synth_freq = ichan->channel - 10;1066} else {1067synth_freq = ichan->channel + 10;1068}1069} else {1070range = 10;1071synth_freq = ichan->channel;1072}10731074/* Clean all spur register fields */1075OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0);1076OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, 0);1077OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0);1078OS_REG_RMW_FIELD(ah,1079AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 0);1080OS_REG_RMW_FIELD(ah,1081AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0);1082OS_REG_RMW_FIELD(ah,1083AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0);1084OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0);1085OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 0);1086OS_REG_RMW_FIELD(ah,1087AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 0);1088OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0);1089OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0);1090OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0);1091OS_REG_RMW_FIELD(ah,1092AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0);1093OS_REG_RMW_FIELD(ah,1094AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0);1095OS_REG_RMW_FIELD(ah,1096AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0);1097OS_REG_RMW_FIELD(ah,1098AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0);1099OS_REG_RMW_FIELD(ah,1100AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0);1101OS_REG_RMW_FIELD(ah,1102AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0);1103OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0);11041105i = 0;1106while (spur_chans_ptr[i] && i < 5) {1107freq_offset = FBIN2FREQ(spur_chans_ptr[i], mode) - synth_freq;1108if (abs(freq_offset) < range) {1109/*1110printf(1111"Spur Mitigation for OFDM: Synth Frequency = %d, "1112"Spur Frequency = %d\n",1113synth_freq, FBIN2FREQ(spur_chans_ptr[i], mode));1114*/1115if (IEEE80211_IS_CHAN_HT40(chan)) {1116if (freq_offset < 0) {1117if (OS_REG_READ_FIELD(1118ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0)1119{1120spur_subchannel_sd = 1;1121} else {1122spur_subchannel_sd = 0;1123}1124spur_freq_sd = ((freq_offset + 10) << 9) / 11;1125} else {1126if (OS_REG_READ_FIELD(ah,1127AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0)1128{1129spur_subchannel_sd = 0;1130} else {1131spur_subchannel_sd = 1;1132}1133spur_freq_sd = ((freq_offset - 10) << 9) / 11;1134}1135spur_delta_phase = (freq_offset << 17) / 5;1136} else {1137spur_subchannel_sd = 0;1138spur_freq_sd = (freq_offset << 9) / 11;1139spur_delta_phase = (freq_offset << 18) / 5;1140}1141spur_freq_sd = spur_freq_sd & 0x3ff;1142spur_delta_phase = spur_delta_phase & 0xfffff;1143/*1144printf(1145"spur_subchannel_sd = %d, spur_freq_sd = 0x%x, "1146"spur_delta_phase = 0x%x\n", spur_subchannel_sd,1147spur_freq_sd, spur_delta_phase);1148*/11491150/* OFDM Spur mitigation */1151OS_REG_RMW_FIELD(ah,1152AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0x1);1153OS_REG_RMW_FIELD(ah,1154AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd);1155OS_REG_RMW_FIELD(ah,1156AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE,1157spur_delta_phase);1158OS_REG_RMW_FIELD(ah,1159AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD,1160spur_subchannel_sd);1161OS_REG_RMW_FIELD(ah,1162AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0x1);1163OS_REG_RMW_FIELD(ah,1164AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR,11650x1);1166OS_REG_RMW_FIELD(ah,1167AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0x1);1168OS_REG_RMW_FIELD(ah,1169AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34);1170OS_REG_RMW_FIELD(ah,1171AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1);11721173/*1174* Do not subtract spur power from noise floor for wasp.1175* This causes the maximum client test (on Veriwave) to fail1176* when run on spur channel (2464 MHz).1177* Refer to ev#82746 and ev#82744.1178*/1179if (!AR_SREV_WASP(ah) && (OS_REG_READ_FIELD(ah, AR_PHY_MODE,1180AR_PHY_MODE_DYNAMIC) == 0x1)) {1181OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,1182AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1);1183}11841185mask_index = (freq_offset << 4) / 5;1186if (mask_index < 0) {1187mask_index = mask_index - 1;1188}1189mask_index = mask_index & 0x7f;1190/*printf("Bin 0x%x\n", mask_index);*/11911192OS_REG_RMW_FIELD(ah,1193AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0x1);1194OS_REG_RMW_FIELD(ah,1195AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0x1);1196OS_REG_RMW_FIELD(ah,1197AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1);1198OS_REG_RMW_FIELD(ah,1199AR_PHY_PILOT_SPUR_MASK,1200AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index);1201OS_REG_RMW_FIELD(ah,1202AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A,1203mask_index);1204OS_REG_RMW_FIELD(ah,1205AR_PHY_CHAN_SPUR_MASK,1206AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index);1207OS_REG_RMW_FIELD(ah,1208AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A,12090xc);1210OS_REG_RMW_FIELD(ah,1211AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A,12120xc);1213OS_REG_RMW_FIELD(ah,1214AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0);1215OS_REG_RMW_FIELD(ah,1216AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff);1217/*1218printf("BB_timing_control_4 = 0x%x\n",1219OS_REG_READ(ah, AR_PHY_TIMING4));1220printf("BB_timing_control_11 = 0x%x\n",1221OS_REG_READ(ah, AR_PHY_TIMING11));1222printf("BB_ext_chan_scorr_thr = 0x%x\n",1223OS_REG_READ(ah, AR_PHY_SFCORR_EXT));1224printf("BB_spur_mask_controls = 0x%x\n",1225OS_REG_READ(ah, AR_PHY_SPUR_REG));1226printf("BB_pilot_spur_mask = 0x%x\n",1227OS_REG_READ(ah, AR_PHY_PILOT_SPUR_MASK));1228printf("BB_chan_spur_mask = 0x%x\n",1229OS_REG_READ(ah, AR_PHY_CHAN_SPUR_MASK));1230printf("BB_vit_spur_mask_A = 0x%x\n",1231OS_REG_READ(ah, AR_PHY_SPUR_MASK_A));1232*/1233break;1234}1235i++;1236}1237}123812391240/*1241* Convert to baseband spur frequency given input channel frequency1242* and compute register settings below.1243*/1244static void1245ar9300_spur_mitigate(struct ath_hal *ah, struct ieee80211_channel *chan)1246{1247ar9300_spur_mitigate_ofdm(ah, chan);1248ar9300_spur_mitigate_mrc_cck(ah, chan);1249}12501251/**************************************************************1252* ar9300_channel_change1253* Assumes caller wants to change channel, and not reset.1254*/1255static inline HAL_BOOL1256ar9300_channel_change(struct ath_hal *ah, struct ieee80211_channel *chan,1257HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode)1258{12591260u_int32_t synth_delay, qnum;1261struct ath_hal_9300 *ahp = AH9300(ah);12621263/* TX must be stopped by now */1264for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {1265if (ar9300_num_tx_pending(ah, qnum)) {1266HALDEBUG(ah, HAL_DEBUG_QUEUE,1267"%s: Transmit frames pending on queue %d\n", __func__, qnum);1268HALASSERT(0);1269return AH_FALSE;1270}1271}127212731274/*1275* Kill last Baseband Rx Frame - Request analog bus grant1276*/1277OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);1278if (!ath_hal_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,1279AR_PHY_RFBUS_GRANT_EN))1280{1281HALDEBUG(ah, HAL_DEBUG_PHYIO,1282"%s: Could not kill baseband RX\n", __func__);1283return AH_FALSE;1284}128512861287/* Setup 11n MAC/Phy mode registers */1288ar9300_set_11n_regs(ah, chan, macmode);12891290/*1291* Change the synth1292*/1293if (!ahp->ah_rf_hal.set_channel(ah, chan)) {1294HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: failed to set channel\n", __func__);1295return AH_FALSE;1296}12971298/*1299* Some registers get reinitialized during ATH_INI_POST INI programming.1300*/1301ar9300_init_user_settings(ah);13021303/*1304* Setup the transmit power values.1305*1306* After the public to private hal channel mapping, ichan contains the1307* valid regulatory power value.1308* ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan.1309*/1310if (ar9300_eeprom_set_transmit_power(1311ah, &ahp->ah_eeprom, chan, ath_hal_getctl(ah, chan),1312ath_hal_getantennaallowed(ah, chan),1313ath_hal_get_twice_max_regpower(AH_PRIVATE(ah), ichan, chan),1314AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit)) != HAL_OK)1315{1316HALDEBUG(ah, HAL_DEBUG_EEPROM,1317"%s: error init'ing transmit power\n", __func__);1318return AH_FALSE;1319}13201321/*1322* Release the RFBus Grant.1323*/1324OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);13251326/*1327* Write spur immunity and delta slope for OFDM enabled modes (A, G, Turbo)1328*/1329if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) {1330ar9300_set_delta_slope(ah, chan);1331} else {1332/* Set to Ini default */1333OS_REG_WRITE(ah, AR_PHY_TIMING3, 0x9c0a9f6b);1334OS_REG_WRITE(ah, AR_PHY_SGI_DELTA, 0x00046384);1335}13361337ar9300_spur_mitigate(ah, chan);133813391340/*1341* Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN).1342* Read the phy active delay register. Value is in 100ns increments.1343*/1344synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;1345if (IEEE80211_IS_CHAN_CCK(chan)) {1346synth_delay = (4 * synth_delay) / 22;1347} else {1348synth_delay /= 10;1349}13501351OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY);13521353/*1354* Do calibration.1355*/13561357return AH_TRUE;1358}13591360void1361ar9300_set_operating_mode(struct ath_hal *ah, int opmode)1362{1363u_int32_t val;13641365val = OS_REG_READ(ah, AR_STA_ID1);1366val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);1367switch (opmode) {1368case HAL_M_HOSTAP:1369OS_REG_WRITE(ah, AR_STA_ID1,1370val | AR_STA_ID1_STA_AP | AR_STA_ID1_KSRCH_MODE);1371OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);1372break;1373case HAL_M_IBSS:1374OS_REG_WRITE(ah, AR_STA_ID1,1375val | AR_STA_ID1_ADHOC | AR_STA_ID1_KSRCH_MODE);1376OS_REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);1377break;1378case HAL_M_STA:1379case HAL_M_MONITOR:1380OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);1381break;1382}1383}13841385/* XXX need the logic for Osprey */1386void1387ar9300_init_pll(struct ath_hal *ah, struct ieee80211_channel *chan)1388{1389u_int32_t pll;1390u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz;1391HAL_CHANNEL_INTERNAL *ichan = NULL;13921393if (chan)1394ichan = ath_hal_checkchannel(ah, chan);13951396if (AR_SREV_HORNET(ah)) {1397if (clk_25mhz) {1398/* Hornet uses PLL_CONTROL_2. Xtal is 25MHz for Hornet.1399* REFDIV set to 0x1.1400* $xtal_freq = 25;1401* $PLL2_div = (704/$xtal_freq); # 176 * 4 = 704.1402* MAC and BB run at 176 MHz.1403* $PLL2_divint = int($PLL2_div);1404* $PLL2_divfrac = $PLL2_div - $PLL2_divint;1405* $PLL2_divfrac = int($PLL2_divfrac * 0x4000); # 2^141406* $PLL2_Val = ($PLL2_divint & 0x3f) << 19 | (0x1) << 14 |1407* $PLL2_divfrac & 0x3fff;1408* Therefore, $PLL2_Val = 0xe04a3d1409*/1410#define DPLL2_KD_VAL 0x1D1411#define DPLL2_KI_VAL 0x061412#define DPLL3_PHASE_SHIFT_VAL 0x114131414/* Rewrite DDR PLL2 and PLL3 */1415/* program DDR PLL ki and kd value, ki=0x6, kd=0x1d */1416OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x18e82f01);14171418/* program DDR PLL phase_shift to 0x1 */1419OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3,1420AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);14211422OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);1423OS_DELAY(1000);14241425/* program refdiv, nint, frac to RTC register */1426OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0xe04a3d);14271428/* program BB PLL ki and kd value, ki=0x6, kd=0x1d */1429OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1430AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL);1431OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1432AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL);14331434/* program BB PLL phase_shift to 0x1 */1435OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3,1436AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);1437} else { /* 40MHz */1438#undef DPLL2_KD_VAL1439#undef DPLL2_KI_VAL1440#define DPLL2_KD_VAL 0x3D1441#define DPLL2_KI_VAL 0x061442/* Rewrite DDR PLL2 and PLL3 */1443/* program DDR PLL ki and kd value, ki=0x6, kd=0x3d */1444OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x19e82f01);14451446/* program DDR PLL phase_shift to 0x1 */1447OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3,1448AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);14491450OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);1451OS_DELAY(1000);14521453/* program refdiv, nint, frac to RTC register */1454OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);14551456/* program BB PLL ki and kd value, ki=0x6, kd=0x3d */1457OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1458AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL);1459OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1460AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL);14611462/* program BB PLL phase_shift to 0x1 */1463OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3,1464AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);1465}1466OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);1467OS_DELAY(1000);1468} else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {1469OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_PLL_PWD, 0x1);14701471/* program BB PLL ki and kd value, ki=0x4, kd=0x40 */1472OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1473AR_PHY_BB_DPLL2_KD, 0x40);1474OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1475AR_PHY_BB_DPLL2_KI, 0x4);14761477OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1,1478AR_PHY_BB_DPLL1_REFDIV, 0x5);1479OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1,1480AR_PHY_BB_DPLL1_NINI, 0x58);1481OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1,1482AR_PHY_BB_DPLL1_NFRAC, 0x0);14831484OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1485AR_PHY_BB_DPLL2_OUTDIV, 0x1);1486OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1487AR_PHY_BB_DPLL2_LOCAL_PLL, 0x1);1488OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1489AR_PHY_BB_DPLL2_EN_NEGTRIG, 0x1);14901491/* program BB PLL phase_shift to 0x6 */1492OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3,1493AR_PHY_BB_DPLL3_PHASE_SHIFT, 0x6);14941495OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2,1496AR_PHY_BB_DPLL2_PLL_PWD, 0x0);1497OS_DELAY(1000);14981499OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);1500OS_DELAY(1000);1501} else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {1502#define SRIF_PLL 11503u_int32_t regdata, pll2_divint, pll2_divfrac;15041505#ifndef SRIF_PLL1506u_int32_t pll2_clkmode;1507#endif15081509#ifdef SRIF_PLL1510u_int32_t refdiv;1511#endif1512if (clk_25mhz) {1513#ifndef SRIF_PLL1514pll2_divint = 0x1c;1515pll2_divfrac = 0xa3d7;1516#else1517if (AR_SREV_HONEYBEE(ah)) {1518pll2_divint = 0x1c;1519pll2_divfrac = 0xa3d2;1520refdiv = 1;1521} else {1522pll2_divint = 0x54;1523pll2_divfrac = 0x1eb85;1524refdiv = 3;1525}1526#endif1527} else {1528#ifndef SRIF_PLL1529pll2_divint = 0x11;1530pll2_divfrac = 0x26666;1531#else1532if (AR_SREV_WASP(ah)) {1533pll2_divint = 88;1534pll2_divfrac = 0;1535refdiv = 5;1536} else {1537pll2_divint = 0x11;1538pll2_divfrac = 0x26666;1539refdiv = 1;1540}1541#endif1542}1543#ifndef SRIF_PLL1544pll2_clkmode = 0x3d;1545#endif1546/* PLL programming through SRIF Local Mode */1547OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); /* Bypass mode */1548OS_DELAY(1000);1549do {1550regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);1551if (AR_SREV_HONEYBEE(ah)) {1552regdata = regdata | (0x1 << 22);1553} else {1554regdata = regdata | (0x1 << 16);1555}1556OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 1 */1557OS_DELAY(100);1558/* override int, frac, refdiv */1559#ifndef SRIF_PLL1560OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL,1561((1 << 27) | (pll2_divint << 18) | pll2_divfrac));1562#else1563OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL,1564((refdiv << 27) | (pll2_divint << 18) | pll2_divfrac));1565#endif1566OS_DELAY(100);1567regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);1568#ifndef SRIF_PLL1569regdata = (regdata & 0x80071fff) |1570(0x1 << 30) | (0x1 << 13) | (0x6 << 26) | (pll2_clkmode << 19);1571#else1572if (AR_SREV_WASP(ah)) {1573regdata = (regdata & 0x80071fff) |1574(0x1 << 30) | (0x1 << 13) | (0x4 << 26) | (0x18 << 19);1575} else if (AR_SREV_HONEYBEE(ah)) {1576/*1577* Kd=10, Ki=2, Outdiv=1, Local PLL=0, Phase Shift=41578*/1579regdata = (regdata & 0x01c00fff) |1580(0x1 << 31) | (0x2 << 29) | (0xa << 25) | (0x1 << 19) | (0x6 << 12);1581} else {1582regdata = (regdata & 0x80071fff) |1583(0x3 << 30) | (0x1 << 13) | (0x4 << 26) | (0x60 << 19);1584}1585#endif1586/* Ki, Kd, Local PLL, Outdiv */1587OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata);1588regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE);1589if (AR_SREV_HONEYBEE(ah)) {1590regdata = (regdata & 0xffbfffff);1591} else {1592regdata = (regdata & 0xfffeffff);1593}1594OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 0 */1595OS_DELAY(1000);1596if (AR_SREV_WASP(ah)) {1597/* clear do measure */1598regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);1599regdata &= ~(1 << 30);1600OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);1601OS_DELAY(100);16021603/* set do measure */1604regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);1605regdata |= (1 << 30);1606OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);16071608/* wait for measure done */1609do {1610regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL4);1611} while ((regdata & (1 << 3)) == 0);16121613/* clear do measure */1614regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3);1615regdata &= ~(1 << 30);1616OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata);16171618/* get measure sqsum dvc */1619regdata = (OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3) & 0x007FFFF8) >> 3;1620} else {1621break;1622}1623} while (regdata >= 0x40000);16241625/* Remove from Bypass mode */1626OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);1627OS_DELAY(1000);1628} else {1629pll = SM(0x5, AR_RTC_PLL_REFDIV);16301631/* Supposedly not needed on Osprey */1632#if 01633if (chan && IS_CHAN_HALF_RATE(chan)) {1634pll |= SM(0x1, AR_RTC_PLL_CLKSEL);1635} else if (chan && IS_CHAN_QUARTER_RATE(chan)) {1636pll |= SM(0x2, AR_RTC_PLL_CLKSEL);1637}1638#endif1639if (ichan && IS_CHAN_5GHZ(ichan)) {1640pll |= SM(0x28, AR_RTC_PLL_DIV);1641/*1642* When doing fast clock, set PLL to 0x142c1643*/1644if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {1645pll = 0x142c;1646}1647} else {1648pll |= SM(0x2c, AR_RTC_PLL_DIV);1649}16501651OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);1652}16531654/* TODO:1655* For multi-band owl, switch between bands by reiniting the PLL.1656*/1657OS_DELAY(RTC_PLL_SETTLE_DELAY);16581659OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK,1660AR_RTC_FORCE_DERIVED_CLK | AR_RTC_PCIE_RST_PWDN_EN);16611662/* XXX TODO: honeybee? */1663if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {1664if (clk_25mhz) {1665OS_REG_WRITE(ah,1666AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); /* 32KHz sleep clk */1667OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);1668OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);1669} else {1670OS_REG_WRITE(ah,1671AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); /* 32KHz sleep clk */1672OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);1673OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);1674}1675OS_DELAY(100);1676}1677}16781679static inline HAL_BOOL1680ar9300_set_reset(struct ath_hal *ah, int type)1681{1682u_int32_t rst_flags;1683u_int32_t tmp_reg;1684struct ath_hal_9300 *ahp = AH9300(ah);16851686HALASSERT(type == HAL_RESET_WARM || type == HAL_RESET_COLD);16871688/*1689* RTC Force wake should be done before resetting the MAC.1690* MDK/ART does it that way.1691*/1692OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);1693OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */1694OS_REG_WRITE(ah,1695AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);16961697/* Reset AHB */1698/* Bug26871 */1699tmp_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE));1700if (AR_SREV_WASP(ah)) {1701if (tmp_reg & (AR9340_INTR_SYNC_LOCAL_TIMEOUT)) {1702OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0);1703OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF);1704}1705} else {1706if (tmp_reg & (AR9300_INTR_SYNC_LOCAL_TIMEOUT | AR9300_INTR_SYNC_RADM_CPL_TIMEOUT)) {1707OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0);1708OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF);1709}1710else {1711/* NO AR_RC_AHB in Osprey */1712/*OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_AHB);*/1713}1714}17151716rst_flags = AR_RTC_RC_MAC_WARM;1717if (type == HAL_RESET_COLD) {1718rst_flags |= AR_RTC_RC_MAC_COLD;1719}17201721#ifdef AH_SUPPORT_HORNET1722/* Hornet WAR: trigger SoC to reset WMAC if ...1723* (1) doing cold reset. Ref: EV 692541724* (2) beacon pending. Ref: EV 709831725*/1726if (AR_SREV_HORNET(ah) &&1727(ar9300_num_tx_pending(1728ah, AH_PRIVATE(ah)->ah_caps.halTotalQueues - 1) != 0 ||1729type == HAL_RESET_COLD))1730{1731u_int32_t time_out;1732#define AR_SOC_RST_RESET 0xB806001C1733#define AR_SOC_BOOT_STRAP 0xB80600AC1734#define AR_SOC_WLAN_RST 0x00000800 /* WLAN reset */1735#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val);1736#define REG_READ(_reg) *((volatile u_int32_t *)(_reg))1737HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Hornet SoC reset WMAC.\n", __func__);17381739REG_WRITE(AR_SOC_RST_RESET,1740REG_READ(AR_SOC_RST_RESET) | AR_SOC_WLAN_RST);1741REG_WRITE(AR_SOC_RST_RESET,1742REG_READ(AR_SOC_RST_RESET) & (~AR_SOC_WLAN_RST));17431744time_out = 0;17451746while (1) {1747tmp_reg = REG_READ(AR_SOC_BOOT_STRAP);1748if ((tmp_reg & 0x10) == 0) {1749break;1750}1751if (time_out > 20) {1752break;1753}1754OS_DELAY(10000);1755time_out++;1756}17571758OS_REG_WRITE(ah, AR_RTC_RESET, 1);1759#undef REG_READ1760#undef REG_WRITE1761#undef AR_SOC_WLAN_RST1762#undef AR_SOC_RST_RESET1763#undef AR_SOC_BOOT_STRAP1764}1765#endif /* AH_SUPPORT_HORNET */17661767#ifdef AH_SUPPORT_SCORPION1768if (AR_SREV_SCORPION(ah)) {1769#define DDR_CTL_CONFIG_ADDRESS 0xb80000001770#define DDR_CTL_CONFIG_OFFSET 0x01081771#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MSB 291772#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB 211773#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK 0x3fe000001774#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(x) (((x) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) >> DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB)1775#define DDR_CTL_CONFIG_CLIENT_ACTIVITY_SET(x) (((x) << DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK)1776#define MAC_DMA_CFG_ADDRESS 0xb81000001777#define MAC_DMA_CFG_OFFSET 0x001417781779#define MAC_DMA_CFG_HALT_REQ_MSB 111780#define MAC_DMA_CFG_HALT_REQ_LSB 111781#define MAC_DMA_CFG_HALT_REQ_MASK 0x000008001782#define MAC_DMA_CFG_HALT_REQ_GET(x) (((x) & MAC_DMA_CFG_HALT_REQ_MASK) >> MAC_DMA_CFG_HALT_REQ_LSB)1783#define MAC_DMA_CFG_HALT_REQ_SET(x) (((x) << MAC_DMA_CFG_HALT_REQ_LSB) & MAC_DMA_CFG_HALT_REQ_MASK)1784#define MAC_DMA_CFG_HALT_ACK_MSB 121785#define MAC_DMA_CFG_HALT_ACK_LSB 121786#define MAC_DMA_CFG_HALT_ACK_MASK 0x000010001787#define MAC_DMA_CFG_HALT_ACK_GET(x) (((x) & MAC_DMA_CFG_HALT_ACK_MASK) >> MAC_DMA_CFG_HALT_ACK_LSB)1788#define MAC_DMA_CFG_HALT_ACK_SET(x) (((x) << MAC_DMA_CFG_HALT_ACK_LSB) & MAC_DMA_CFG_HALT_ACK_MASK)17891790#define RST_RESET 0xB806001c1791#define RTC_RESET (1<<27)17921793#define REG_READ(_reg) *((volatile u_int32_t *)(_reg))1794#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val);17951796#define DDR_REG_READ(_ah, _reg) \1797*((volatile u_int32_t *)( DDR_CTL_CONFIG_ADDRESS + (_reg)))1798#define DDR_REG_WRITE(_ah, _reg, _val) \1799*((volatile u_int32_t *)(DDR_CTL_CONFIG_ADDRESS + (_reg))) = (_val)18001801OS_REG_WRITE(ah,MAC_DMA_CFG_OFFSET, (OS_REG_READ(ah,MAC_DMA_CFG_OFFSET) & ~MAC_DMA_CFG_HALT_REQ_MASK) |1802MAC_DMA_CFG_HALT_REQ_SET(1));18031804{1805int count;1806u_int32_t data;18071808count = 0;1809while (!MAC_DMA_CFG_HALT_ACK_GET(OS_REG_READ(ah, MAC_DMA_CFG_OFFSET) ))1810{1811count++;1812if (count > 10) {1813ath_hal_printf(ah, "Halt ACK timeout\n");1814break;1815}1816OS_DELAY(10);1817}18181819data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET);1820HALDEBUG(ah, HAL_DEBUG_RESET, "check DDR Activity - HIGH\n");18211822count = 0;1823while (DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(data)) {1824// AVE_DEBUG(0,"DDR Activity - HIGH\n");1825HALDEBUG(ah, HAL_DEBUG_RESET, "DDR Activity - HIGH\n");1826count++;1827OS_DELAY(10);1828data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET);1829if (count > 10) {1830ath_hal_printf(ah, "DDR Activity timeout\n");1831break;1832}1833}1834}183518361837{1838//Force RTC reset1839REG_WRITE(RST_RESET, (REG_READ(RST_RESET) | RTC_RESET));1840OS_DELAY(10);1841REG_WRITE(RST_RESET, (REG_READ(RST_RESET) & ~RTC_RESET));1842OS_DELAY(10);1843OS_REG_WRITE(ah, AR_RTC_RESET, 0);1844OS_DELAY(10);1845OS_REG_WRITE(ah, AR_RTC_RESET, 1);1846OS_DELAY(10);1847HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Scorpion SoC RTC reset done.\n", __func__);1848}1849#undef REG_READ1850#undef REG_WRITE1851}1852#endif /* AH_SUPPORT_SCORPION */18531854/*1855* Set Mac(BB,Phy) Warm Reset1856*/1857OS_REG_WRITE(ah, AR_RTC_RC, rst_flags);18581859OS_DELAY(50); /* XXX 50 usec */18601861/*1862* Clear resets and force wakeup1863*/1864OS_REG_WRITE(ah, AR_RTC_RC, 0);1865if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) {1866HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,1867"%s: RTC stuck in MAC reset\n", __FUNCTION__);1868HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,1869"%s: AR_RTC_RC = 0x%x\n", __func__, OS_REG_READ(ah, AR_RTC_RC));1870return AH_FALSE;1871}18721873/* Clear AHB reset */1874OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0);1875ar9300_disable_pll_lock_detect(ah);18761877ar9300_attach_hw_platform(ah);18781879ahp->ah_chip_reset_done = 1;1880return AH_TRUE;1881}18821883static inline HAL_BOOL1884ar9300_set_reset_power_on(struct ath_hal *ah)1885{1886/* Force wake */1887OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);1888OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */1889OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,1890AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);1891/*1892* RTC reset and clear. Some delay in between is needed1893* to give the chip time to settle.1894*/1895OS_REG_WRITE(ah, AR_RTC_RESET, 0);1896OS_DELAY(2);1897OS_REG_WRITE(ah, AR_RTC_RESET, 1);18981899/*1900* Poll till RTC is ON1901*/1902if (!ath_hal_wait(ah,1903AR_RTC_STATUS, AR_RTC_STATUS_M,1904AR_RTC_STATUS_ON))1905{1906HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,1907"%s: RTC not waking up for %d\n", __FUNCTION__, 1000);1908return AH_FALSE;1909}19101911/*1912* Read Revisions from Chip right after RTC is on for the first time.1913* This helps us detect the chip type early and initialize it accordingly.1914*/1915ar9300_read_revisions(ah);19161917/*1918* Warm reset if we aren't really powering on,1919* just restarting the driver.1920*/1921return ar9300_set_reset(ah, HAL_RESET_WARM);1922}19231924/*1925* Write the given reset bit mask into the reset register1926*/1927HAL_BOOL1928ar9300_set_reset_reg(struct ath_hal *ah, u_int32_t type)1929{1930HAL_BOOL ret = AH_FALSE;19311932/*1933* Set force wake1934*/1935OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val);1936OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */1937OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,1938AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);19391940switch (type) {1941case HAL_RESET_POWER_ON:1942ret = ar9300_set_reset_power_on(ah);1943break;1944case HAL_RESET_WARM:1945case HAL_RESET_COLD:1946ret = ar9300_set_reset(ah, type);1947break;1948default:1949break;1950}19511952#if ATH_SUPPORT_MCI1953if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {1954OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);1955}1956#endif19571958return ret;1959}19601961/*1962* Places the PHY and Radio chips into reset. A full reset1963* must be called to leave this state. The PCI/MAC/PCU are1964* not placed into reset as we must receive interrupt to1965* re-enable the hardware.1966*/1967HAL_BOOL1968ar9300_phy_disable(struct ath_hal *ah)1969{1970if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) {1971return AH_FALSE;1972}19731974#ifdef ATH_SUPPORT_LED1975#define REG_READ(_reg) *((volatile u_int32_t *)(_reg))1976#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val);1977#define ATH_GPIO_OE 0xB80400001978#define ATH_GPIO_OUT 0xB8040008 /* GPIO Ouput Value reg.*/1979if (AR_SREV_WASP(ah)) {1980if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {1981REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13)));1982}1983else {1984REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));1985}1986}1987else if (AR_SREV_SCORPION(ah)) {1988if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {1989REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13)));1990}1991else {1992REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));1993}1994/* Turn off JMPST led */1995REG_WRITE(ATH_GPIO_OUT, (REG_READ(ATH_GPIO_OUT) | (0x1 << 15)));1996}1997else if (AR_SREV_HONEYBEE(ah)) {1998REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12)));1999}2000#undef REG_READ2001#undef REG_WRITE2002#endif20032004if ( AR_SREV_OSPREY(ah) ) {2005OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1), 0x0, 0x1f);2006}200720082009ar9300_init_pll(ah, AH_NULL);2010ar9300_disable_pll_lock_detect(ah);20112012return AH_TRUE;2013}20142015/*2016* Places all of hardware into reset2017*/2018HAL_BOOL2019ar9300_disable(struct ath_hal *ah)2020{2021if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {2022return AH_FALSE;2023}2024if (!ar9300_set_reset_reg(ah, HAL_RESET_COLD)) {2025return AH_FALSE;2026}20272028ar9300_init_pll(ah, AH_NULL);20292030return AH_TRUE;2031}20322033/*2034* TODO: Only write the PLL if we're changing to or from CCK mode2035*2036* WARNING: The order of the PLL and mode registers must be correct.2037*/2038static inline void2039ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan)2040{2041u_int32_t rf_mode = 0;20422043if (chan == AH_NULL) {2044return;2045}2046switch (AH9300(ah)->ah_hwp) {2047case HAL_TRUE_CHIP:2048rf_mode |= (IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_G(chan)) ?2049AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;2050break;2051default:2052HALASSERT(0);2053break;2054}2055/* Phy mode bits for 5GHz channels requiring Fast Clock */2056if ( IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {2057rf_mode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);2058}2059OS_REG_WRITE(ah, AR_PHY_MODE, rf_mode);2060}20612062/*2063* Places the hardware into reset and then pulls it out of reset2064*/2065HAL_BOOL2066ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_RESET_TYPE reset_type)2067{2068struct ath_hal_9300 *ahp = AH9300(ah);2069int type = HAL_RESET_WARM;20702071OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);20722073/*2074* Warm reset is optimistic.2075*2076* If the TX/RX DMA engines aren't shut down (eg, they're2077* wedged) then we're better off doing a full cold reset2078* to try and shake that condition.2079*/2080if (ahp->ah_chip_full_sleep ||2081(ah->ah_config.ah_force_full_reset == 1) ||2082(reset_type == HAL_RESET_FORCE_COLD) ||2083(reset_type == HAL_RESET_BBPANIC) ||2084OS_REG_READ(ah, AR_Q_TXE) ||2085(OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) {2086HALDEBUG(ah, HAL_DEBUG_RESET,2087"%s: full reset; reset_type=%d, full_sleep=%d\n",2088__func__, reset_type, ahp->ah_chip_full_sleep);2089type = HAL_RESET_COLD;2090}20912092if (!ar9300_set_reset_reg(ah, type)) {2093return AH_FALSE;2094}20952096/* Bring out of sleep mode (AGAIN) */2097if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {2098return AH_FALSE;2099}21002101ahp->ah_chip_full_sleep = AH_FALSE;21022103if (AR_SREV_HORNET(ah)) {2104ar9300_internal_regulator_apply(ah);2105}21062107ar9300_init_pll(ah, chan);21082109/*2110* Perform warm reset before the mode/PLL/turbo registers2111* are changed in order to deactivate the radio. Mode changes2112* with an active radio can result in corrupted shifts to the2113* radio device.2114*/2115ar9300_set_rf_mode(ah, chan);21162117return AH_TRUE;2118}21192120/* ar9300_setup_calibration2121* Setup HW to collect samples used for current cal2122*/2123inline static void2124ar9300_setup_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal)2125{2126/* Select calibration to run */2127switch (curr_cal->cal_data->cal_type) {2128case IQ_MISMATCH_CAL:2129/* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */2130OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4,2131AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,2132curr_cal->cal_data->cal_count_max);2133OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);21342135HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2136"%s: starting IQ Mismatch Calibration\n", __func__);21372138/* Kick-off cal */2139OS_REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);21402141break;2142case TEMP_COMP_CAL:2143if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) ||2144AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {2145OS_REG_RMW_FIELD(ah,2146AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1);2147OS_REG_RMW_FIELD(ah,2148AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1);2149} else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {2150OS_REG_RMW_FIELD(ah,2151AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_LOCAL, 1);2152OS_REG_RMW_FIELD(ah,2153AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_START, 1);2154} else {2155OS_REG_RMW_FIELD(ah,2156AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1);2157OS_REG_RMW_FIELD(ah,2158AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1);2159}21602161HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2162"%s: starting Temperature Compensation Calibration\n", __func__);2163break;2164default:2165HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,2166"%s called with incorrect calibration type.\n", __func__);2167}2168}21692170/* ar9300_reset_calibration2171* Initialize shared data structures and prepare a cal to be run.2172*/2173inline static void2174ar9300_reset_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal)2175{2176struct ath_hal_9300 *ahp = AH9300(ah);2177int i;21782179/* Setup HW for new calibration */2180ar9300_setup_calibration(ah, curr_cal);21812182/* Change SW state to RUNNING for this calibration */2183curr_cal->cal_state = CAL_RUNNING;21842185/* Reset data structures shared between different calibrations */2186for (i = 0; i < AR9300_MAX_CHAINS; i++) {2187ahp->ah_meas0.sign[i] = 0;2188ahp->ah_meas1.sign[i] = 0;2189ahp->ah_meas2.sign[i] = 0;2190ahp->ah_meas3.sign[i] = 0;2191}21922193ahp->ah_cal_samples = 0;2194}21952196#ifdef XXX_UNUSED_FUNCTION2197/*2198* Find out which of the RX chains are enabled2199*/2200static u_int32_t2201ar9300_get_rx_chain_mask(struct ath_hal *ah)2202{2203u_int32_t ret_val = OS_REG_READ(ah, AR_PHY_RX_CHAINMASK);2204/* The bits [2:0] indicate the rx chain mask and are to be2205* interpreted as follows:2206* 00x => Only chain 0 is enabled2207* 01x => Chain 1 and 0 enabled2208* 1xx => Chain 2,1 and 0 enabled2209*/2210return (ret_val & 0x7);2211}2212#endif22132214static void2215ar9300_get_nf_hist_base(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan,2216int is_scan, int16_t nf[])2217{2218HAL_NFCAL_BASE *h_base;22192220#ifdef ATH_NF_PER_CHAN2221h_base = &chan->nf_cal_hist.base;2222#else2223if (is_scan) {2224/*2225* The channel we are currently on is not the home channel,2226* so we shouldn't use the home channel NF buffer's values on2227* this channel. Instead, use the NF single value already2228* read for this channel. (Or, if we haven't read the NF for2229* this channel yet, the SW default for this chip/band will2230* be used.)2231*/2232h_base = &chan->nf_cal_hist.base;2233} else {2234/* use the home channel NF info */2235h_base = &AH_PRIVATE(ah)->nf_cal_hist.base;2236}2237#endif2238OS_MEMCPY(nf, h_base->priv_nf, sizeof(h_base->priv_nf));2239}22402241HAL_BOOL2242ar9300_load_nf(struct ath_hal *ah, int16_t nf[])2243{2244int i, j;2245int32_t val;2246/* XXX where are EXT regs defined */2247const u_int32_t ar9300_cca_regs[] = {2248AR_PHY_CCA_0,2249AR_PHY_CCA_1,2250AR_PHY_CCA_2,2251AR_PHY_EXT_CCA,2252AR_PHY_EXT_CCA_1,2253AR_PHY_EXT_CCA_2,2254};2255u_int8_t chainmask;22562257/*2258* Force NF calibration for all chains, otherwise Vista station2259* would conduct a bad performance2260*/2261if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {2262chainmask = 0x9;2263} else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(ah)) {2264chainmask = 0x1b;2265} else {2266chainmask = 0x3F;2267}22682269/*2270* Write filtered NF values into max_cca_pwr register parameter2271* so we can load below.2272*/2273for (i = 0; i < HAL_NUM_NF_READINGS; i++) {2274if (chainmask & (1 << i)) {2275val = OS_REG_READ(ah, ar9300_cca_regs[i]);2276val &= 0xFFFFFE00;2277val |= (((u_int32_t)(nf[i]) << 1) & 0x1ff);2278OS_REG_WRITE(ah, ar9300_cca_regs[i], val);2279}2280}22812282HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s: load %d %d %d %d %d %d\n",2283__func__,2284nf[0], nf[1], nf[2],2285nf[3], nf[4], nf[5]);22862287/*2288* Load software filtered NF value into baseband internal min_cca_pwr2289* variable.2290*/2291OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);2292OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);2293OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);22942295/* Wait for load to complete, should be fast, a few 10s of us. */2296/* Changed the max delay 250us back to 10000us, since 250us often2297* results in NF load timeout and causes deaf condition2298* during stress testing 12/12/20092299*/2300for (j = 0; j < 10000; j++) {2301if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){2302break;2303}2304OS_DELAY(10);2305}2306if (j == 10000) {2307/*2308* We timed out waiting for the noisefloor to load, probably2309* due to an in-progress rx. Simply return here and allow2310* the load plenty of time to complete before the next2311* calibration interval. We need to avoid trying to load -502312* (which happens below) while the previous load is still in2313* progress as this can cause rx deafness (see EV 66368,62830).2314* Instead by returning here, the baseband nf cal will2315* just be capped by our present noisefloor until the next2316* calibration timer.2317*/2318HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,2319"%s: *** TIMEOUT while waiting for nf to load: "2320"AR_PHY_AGC_CONTROL=0x%x ***\n",2321__func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL));2322return AH_FALSE;2323}23242325/*2326* Restore max_cca_power register parameter again so that we're not capped2327* by the median we just loaded. This will be initial (and max) value2328* of next noise floor calibration the baseband does.2329*/2330for (i = 0; i < HAL_NUM_NF_READINGS; i++) {2331if (chainmask & (1 << i)) {2332val = OS_REG_READ(ah, ar9300_cca_regs[i]);2333val &= 0xFFFFFE00;2334val |= (((u_int32_t)(-50) << 1) & 0x1ff);2335OS_REG_WRITE(ah, ar9300_cca_regs[i], val);2336}2337}2338return AH_TRUE;2339}23402341/* ar9300_per_calibration2342* Generic calibration routine.2343* Recalibrate the lower PHY chips to account for temperature/environment2344* changes.2345*/2346inline static void2347ar9300_per_calibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan,2348u_int8_t rxchainmask, HAL_CAL_LIST *curr_cal, HAL_BOOL *is_cal_done)2349{2350struct ath_hal_9300 *ahp = AH9300(ah);23512352/* Cal is assumed not done until explicitly set below */2353*is_cal_done = AH_FALSE;23542355/* Calibration in progress. */2356if (curr_cal->cal_state == CAL_RUNNING) {2357/* Check to see if it has finished. */2358if (!(OS_REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) {2359int i, num_chains = 0;2360for (i = 0; i < AR9300_MAX_CHAINS; i++) {2361if (rxchainmask & (1 << i)) {2362num_chains++;2363}2364}23652366/*2367* Accumulate cal measures for active chains2368*/2369curr_cal->cal_data->cal_collect(ah, num_chains);23702371ahp->ah_cal_samples++;23722373if (ahp->ah_cal_samples >= curr_cal->cal_data->cal_num_samples) {2374/*2375* Process accumulated data2376*/2377curr_cal->cal_data->cal_post_proc(ah, num_chains);23782379/* Calibration has finished. */2380ichan->calValid |= curr_cal->cal_data->cal_type;2381curr_cal->cal_state = CAL_DONE;2382*is_cal_done = AH_TRUE;2383} else {2384/* Set-up collection of another sub-sample until we2385* get desired number2386*/2387ar9300_setup_calibration(ah, curr_cal);2388}2389}2390} else if (!(ichan->calValid & curr_cal->cal_data->cal_type)) {2391/* If current cal is marked invalid in channel, kick it off */2392ar9300_reset_calibration(ah, curr_cal);2393}2394}23952396static void2397ar9300_start_nf_cal(struct ath_hal *ah)2398{2399struct ath_hal_9300 *ahp = AH9300(ah);2400OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);2401OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);2402OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);2403AH9300(ah)->nf_tsf32 = ar9300_get_tsf32(ah);24042405/*2406* We are reading the NF values before we start the NF operation, because2407* of that we are getting very high values like -45.2408* This triggers the CW_INT detected and EACS module triggers the channel change2409* chip_reset_done value is used to fix this issue.2410* chip_reset_flag is set during the RTC reset.2411* chip_reset_flag is cleared during the starting NF operation.2412* if flag is set we will clear the flag and will not read the NF values.2413*/2414ahp->ah_chip_reset_done = 0;2415}24162417/* ar9300_calibration2418* Wrapper for a more generic Calibration routine. Primarily to abstract to2419* upper layers whether there is 1 or more calibrations to be run.2420*/2421HAL_BOOL2422ar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask,2423HAL_BOOL do_nf_cal, HAL_BOOL *is_cal_done, int is_scan,2424u_int32_t *sched_cals)2425{2426struct ath_hal_9300 *ahp = AH9300(ah);2427HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr;2428HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);2429int16_t nf_buf[HAL_NUM_NF_READINGS];24302431*is_cal_done = AH_TRUE;243224332434/* XXX: For initial wasp bringup - disable periodic calibration */2435/* Invalid channel check */2436if (ichan == AH_NULL) {2437HALDEBUG(ah, HAL_DEBUG_CHANNEL,2438"%s: invalid channel %u/0x%x; no mapping\n",2439__func__, chan->ic_freq, chan->ic_flags);2440return AH_FALSE;2441}24422443HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2444"%s: Entering, Doing NF Cal = %d\n", __func__, do_nf_cal);2445HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 0 Rx IQ Cal Correction 0x%08x\n",2446__func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));2447if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) {2448HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2449"%s: Chain 1 Rx IQ Cal Correction 0x%08x\n",2450__func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B1));2451if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah) && !AR_SREV_HONEYBEE(ah)) {2452HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2453"%s: Chain 2 Rx IQ Cal Correction 0x%08x\n",2454__func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B2));2455}2456}24572458OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq);24592460/* For given calibration:2461* 1. Call generic cal routine2462* 2. When this cal is done (is_cal_done) if we have more cals waiting2463* (eg after reset), mask this to upper layers by not propagating2464* is_cal_done if it is set to TRUE.2465* Instead, change is_cal_done to FALSE and setup the waiting cal(s)2466* to be run.2467*/2468if (curr_cal && (curr_cal->cal_data->cal_type & *sched_cals) &&2469(curr_cal->cal_state == CAL_RUNNING ||2470curr_cal->cal_state == CAL_WAITING))2471{2472ar9300_per_calibration(ah, ichan, rxchainmask, curr_cal, is_cal_done);24732474if (*is_cal_done == AH_TRUE) {2475ahp->ah_cal_list_curr = curr_cal = curr_cal->cal_next;24762477if (curr_cal && curr_cal->cal_state == CAL_WAITING) {2478*is_cal_done = AH_FALSE;2479ar9300_reset_calibration(ah, curr_cal);2480} else {2481*sched_cals &= ~IQ_MISMATCH_CAL;2482}2483}2484}24852486/* Do NF cal only at longer intervals */2487if (do_nf_cal) {2488int nf_done;24892490/* Get the value from the previous NF cal and update history buffer */2491nf_done = ar9300_store_new_nf(ah, chan, is_scan);2492#if 02493if (ichan->channel_flags & CHANNEL_CW_INT) {2494chan->channel_flags |= CHANNEL_CW_INT;2495}2496#endif2497chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;24982499if (nf_done) {2500int ret;2501/*2502* Load the NF from history buffer of the current channel.2503* NF is slow time-variant, so it is OK to use a historical value.2504*/2505ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);25062507ret = ar9300_load_nf(ah, nf_buf);2508/* start NF calibration, without updating BB NF register*/2509ar9300_start_nf_cal(ah);25102511/*2512* If we failed the NF cal then tell the upper layer that we2513* failed so we can do a full reset2514*/2515if (! ret)2516return AH_FALSE;2517}2518}2519return AH_TRUE;2520}25212522/* ar9300_iq_cal_collect2523* Collect data from HW to later perform IQ Mismatch Calibration2524*/2525void2526ar9300_iq_cal_collect(struct ath_hal *ah, u_int8_t num_chains)2527{2528struct ath_hal_9300 *ahp = AH9300(ah);2529int i;25302531/*2532* Accumulate IQ cal measures for active chains2533*/2534for (i = 0; i < num_chains; i++) {2535ahp->ah_total_power_meas_i[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i));2536ahp->ah_total_power_meas_q[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i));2537ahp->ah_total_iq_corr_meas[i] =2538(int32_t) OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i));2539HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2540"%d: Chn %d "2541"Reg Offset(0x%04x)pmi=0x%08x; "2542"Reg Offset(0x%04x)pmq=0x%08x; "2543"Reg Offset (0x%04x)iqcm=0x%08x;\n",2544ahp->ah_cal_samples,2545i,2546(unsigned) AR_PHY_CAL_MEAS_0(i),2547ahp->ah_total_power_meas_i[i],2548(unsigned) AR_PHY_CAL_MEAS_1(i),2549ahp->ah_total_power_meas_q[i],2550(unsigned) AR_PHY_CAL_MEAS_2(i),2551ahp->ah_total_iq_corr_meas[i]);2552}2553}25542555/* ar9300_iq_calibration2556* Use HW data to perform IQ Mismatch Calibration2557*/2558void2559ar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains)2560{2561struct ath_hal_9300 *ahp = AH9300(ah);2562u_int32_t power_meas_q, power_meas_i, iq_corr_meas;2563u_int32_t q_coff_denom, i_coff_denom;2564int32_t q_coff, i_coff;2565int iq_corr_neg, i;2566HAL_CHANNEL_INTERNAL *ichan;2567static const u_int32_t offset_array[3] = {2568AR_PHY_RX_IQCAL_CORR_B0,2569AR_PHY_RX_IQCAL_CORR_B1,2570AR_PHY_RX_IQCAL_CORR_B2,2571};25722573ichan = ath_hal_checkchannel(ah, AH_PRIVATE(ah)->ah_curchan);25742575for (i = 0; i < num_chains; i++) {2576power_meas_i = ahp->ah_total_power_meas_i[i];2577power_meas_q = ahp->ah_total_power_meas_q[i];2578iq_corr_meas = ahp->ah_total_iq_corr_meas[i];25792580HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2581"Starting IQ Cal and Correction for Chain %d\n", i);2582HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2583"Orignal: Chn %diq_corr_meas = 0x%08x\n",2584i, ahp->ah_total_iq_corr_meas[i]);25852586iq_corr_neg = 0;25872588/* iq_corr_meas is always negative. */2589if (iq_corr_meas > 0x80000000) {2590iq_corr_meas = (0xffffffff - iq_corr_meas) + 1;2591iq_corr_neg = 1;2592}25932594HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2595"Chn %d pwr_meas_i = 0x%08x\n", i, power_meas_i);2596HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2597"Chn %d pwr_meas_q = 0x%08x\n", i, power_meas_q);2598HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2599"iq_corr_neg is 0x%08x\n", iq_corr_neg);26002601i_coff_denom = (power_meas_i / 2 + power_meas_q / 2) / 256;2602q_coff_denom = power_meas_q / 64;26032604/* Protect against divide-by-0 */2605if ((i_coff_denom != 0) && (q_coff_denom != 0)) {2606/* IQ corr_meas is already negated if iqcorr_neg == 1 */2607i_coff = iq_corr_meas / i_coff_denom;2608q_coff = power_meas_i / q_coff_denom - 64;2609HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2610"Chn %d i_coff = 0x%08x\n", i, i_coff);2611HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2612"Chn %d q_coff = 0x%08x\n", i, q_coff);26132614/* Force bounds on i_coff */2615if (i_coff >= 63) {2616i_coff = 63;2617} else if (i_coff <= -63) {2618i_coff = -63;2619}26202621/* Negate i_coff if iq_corr_neg == 0 */2622if (iq_corr_neg == 0x0) {2623i_coff = -i_coff;2624}26252626/* Force bounds on q_coff */2627if (q_coff >= 63) {2628q_coff = 63;2629} else if (q_coff <= -63) {2630q_coff = -63;2631}26322633i_coff = i_coff & 0x7f;2634q_coff = q_coff & 0x7f;26352636HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2637"Chn %d : i_coff = 0x%x q_coff = 0x%x\n", i, i_coff, q_coff);2638HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2639"Register offset (0x%04x) before update = 0x%x\n",2640offset_array[i], OS_REG_READ(ah, offset_array[i]));26412642OS_REG_RMW_FIELD(ah, offset_array[i],2643AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff);2644OS_REG_RMW_FIELD(ah, offset_array[i],2645AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff);26462647/* store the RX cal results */2648if (ichan != NULL) {2649ahp->ah_rx_cal_corr[i] = OS_REG_READ(ah, offset_array[i]) & 0x7fff;2650ahp->ah_rx_cal_complete = AH_TRUE;2651ahp->ah_rx_cal_chan = ichan->channel;2652// ahp->ah_rx_cal_chan_flag = ichan->channel_flags &~ CHANNEL_PASSIVE;2653ahp->ah_rx_cal_chan_flag = 0; /* XXX */2654} else {2655/* XXX? Is this what I should do? */2656ahp->ah_rx_cal_complete = AH_FALSE;26572658}26592660HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2661"Register offset (0x%04x) QI COFF (bitfields 0x%08x) "2662"after update = 0x%x\n",2663offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,2664OS_REG_READ(ah, offset_array[i]));2665HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2666"Register offset (0x%04x) QQ COFF (bitfields 0x%08x) "2667"after update = 0x%x\n",2668offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,2669OS_REG_READ(ah, offset_array[i]));2670HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2671"IQ Cal and Correction done for Chain %d\n", i);2672}2673}26742675OS_REG_SET_BIT(ah,2676AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);2677HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2678"IQ Cal and Correction (offset 0x%04x) enabled "2679"(bit position 0x%08x). New Value 0x%08x\n",2680(unsigned) (AR_PHY_RX_IQCAL_CORR_B0),2681AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,2682OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));2683}26842685/*2686* When coming back from offchan, we do not perform RX IQ Cal.2687* But the chip reset will clear all previous results2688* We store the previous results and restore here.2689*/2690static void2691ar9300_rx_iq_cal_restore(struct ath_hal *ah)2692{2693struct ath_hal_9300 *ahp = AH9300(ah);2694u_int32_t i_coff, q_coff;2695HAL_BOOL is_restore = AH_FALSE;2696int i;2697static const u_int32_t offset_array[3] = {2698AR_PHY_RX_IQCAL_CORR_B0,2699AR_PHY_RX_IQCAL_CORR_B1,2700AR_PHY_RX_IQCAL_CORR_B2,2701};27022703for (i=0; i<AR9300_MAX_CHAINS; i++) {2704if (ahp->ah_rx_cal_corr[i]) {2705i_coff = (ahp->ah_rx_cal_corr[i] &2706AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF) >>2707AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S;2708q_coff = (ahp->ah_rx_cal_corr[i] &2709AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF) >>2710AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S;27112712OS_REG_RMW_FIELD(ah, offset_array[i],2713AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff);2714OS_REG_RMW_FIELD(ah, offset_array[i],2715AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff);27162717is_restore = AH_TRUE;2718}2719}27202721if (is_restore)2722OS_REG_SET_BIT(ah,2723AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);27242725HALDEBUG(ah, HAL_DEBUG_CALIBRATE,2726"%s: IQ Cal and Correction (offset 0x%04x) enabled "2727"(bit position 0x%08x). New Value 0x%08x\n",2728__func__,2729(unsigned) (AR_PHY_RX_IQCAL_CORR_B0),2730AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,2731OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));2732}27332734/*2735* Set a limit on the overall output power. Used for dynamic2736* transmit power control and the like.2737*2738* NB: limit is in units of 0.5 dbM.2739*/2740HAL_BOOL2741ar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit,2742u_int16_t extra_txpow, u_int16_t tpc_in_db)2743{2744struct ath_hal_9300 *ahp = AH9300(ah);2745struct ath_hal_private *ahpriv = AH_PRIVATE(ah);2746const struct ieee80211_channel *chan = ahpriv->ah_curchan;2747HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);27482749if (NULL == chan) {2750return AH_FALSE;2751}27522753ahpriv->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);2754ahpriv->ah_extraTxPow = extra_txpow;27552756if(chan == NULL) {2757return AH_FALSE;2758}2759if (ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan,2760ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan),2761ath_hal_get_twice_max_regpower(ahpriv, ichan, chan),2762AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)) != HAL_OK)2763{2764return AH_FALSE;2765}2766return AH_TRUE;2767}27682769/*2770* Exported call to check for a recent gain reading and return2771* the current state of the thermal calibration gain engine.2772*/2773HAL_RFGAIN2774ar9300_get_rfgain(struct ath_hal *ah)2775{2776return HAL_RFGAIN_INACTIVE;2777}27782779#define HAL_GREEN_AP_RX_MASK 0x127802781static inline void2782ar9300_init_chain_masks(struct ath_hal *ah, int rx_chainmask, int tx_chainmask)2783{2784if (AH9300(ah)->green_ap_ps_on) {2785rx_chainmask = HAL_GREEN_AP_RX_MASK;2786}2787if (rx_chainmask == 0x5) {2788OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);2789}2790OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);2791OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);27922793/*2794* Adaptive Power Management:2795* Some 3 stream chips exceed the PCIe power requirements.2796* This workaround will reduce power consumption by using 2 tx chains2797* for 1 and 2 stream rates (5 GHz only).2798*2799* Set the self gen mask to 2 tx chains when APM is enabled.2800*2801*/2802if (AH_PRIVATE(ah)->ah_caps.halApmEnable && (tx_chainmask == 0x7)) {2803OS_REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);2804}2805else {2806OS_REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);2807}28082809if (tx_chainmask == 0x5) {2810OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN);2811}2812}28132814/*2815* Override INI values with chip specific configuration.2816*/2817static inline void2818ar9300_override_ini(struct ath_hal *ah, struct ieee80211_channel *chan)2819{2820u_int32_t val;2821HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;28222823/*2824* Set the RX_ABORT and RX_DIS and clear it only after2825* RXE is set for MAC. This prevents frames with2826* corrupted descriptor status.2827*/2828OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));2829/*2830* For Merlin and above, there is a new feature that allows Multicast2831* search based on both MAC Address and Key ID.2832* By default, this feature is enabled.2833* But since the driver is not using this feature, we switch it off;2834* otherwise multicast search based on MAC addr only will fail.2835*/2836val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);2837OS_REG_WRITE(ah, AR_PCU_MISC_MODE2,2838val | AR_BUG_58603_FIX_ENABLE | AR_AGG_WEP_ENABLE);283928402841/* Osprey revision specific configuration */28422843/* Osprey 2.0+ - if SW RAC support is disabled, must also disable2844* the Osprey 2.0 hardware RAC fix.2845*/2846if (p_cap->halIsrRacSupport == AH_FALSE) {2847OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_MISSING_TX_INTR_FIX_ENABLE);2848}28492850/* try to enable old pal if it is needed for h/w green tx */2851ar9300_hwgreentx_set_pal_spare(ah, 1);2852}28532854static inline void2855ar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr,2856int column)2857{2858int i, reg_writes = 0;28592860/* New INI format: Array may be undefined (pre, core, post arrays) */2861if (ini_arr->ia_array == NULL) {2862return;2863}28642865/*2866* New INI format: Pre, core, and post arrays for a given subsystem may be2867* modal (> 2 columns) or non-modal (2 columns).2868* Determine if the array is non-modal and force the column to 1.2869*/2870if (column >= ini_arr->ia_columns) {2871column = 1;2872}28732874for (i = 0; i < ini_arr->ia_rows; i++) {2875u_int32_t reg = INI_RA(ini_arr, i, 0);2876u_int32_t val = INI_RA(ini_arr, i, column);28772878/*2879** Determine if this is a shift register value2880** (reg >= 0x16000 && reg < 0x17000 for Osprey) ,2881** and insert the configured delay if so.2882** -this delay is not required for Osprey (EV#71410)2883*/2884OS_REG_WRITE(ah, reg, val);2885WAR_6773(reg_writes);28862887}2888}28892890static inline HAL_STATUS2891ar9300_process_ini(struct ath_hal *ah, struct ieee80211_channel *chan,2892HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode)2893{2894int reg_writes = 0;2895struct ath_hal_9300 *ahp = AH9300(ah);2896u_int modes_index, modes_txgaintable_index = 0;2897int i;2898HAL_STATUS status;2899struct ath_hal_private *ahpriv = AH_PRIVATE(ah);2900/* Setup the indices for the next set of register array writes */2901/* TODO:2902* If the channel marker is indicative of the current mode rather2903* than capability, we do not need to check the phy mode below.2904*/2905#if 02906switch (chan->channel_flags & CHANNEL_ALL) {2907case CHANNEL_A:2908case CHANNEL_A_HT20:2909if (AR_SREV_SCORPION(ah)){2910if (chan->channel <= 5350){2911modes_txgaintable_index = 1;2912}else if ((chan->channel > 5350) && (chan->channel <= 5600)){2913modes_txgaintable_index = 3;2914}else if (chan->channel > 5600){2915modes_txgaintable_index = 5;2916}2917}2918modes_index = 1;2919freq_index = 1;2920break;29212922case CHANNEL_A_HT40PLUS:2923case CHANNEL_A_HT40MINUS:2924if (AR_SREV_SCORPION(ah)){2925if (chan->channel <= 5350){2926modes_txgaintable_index = 2;2927}else if ((chan->channel > 5350) && (chan->channel <= 5600)){2928modes_txgaintable_index = 4;2929}else if (chan->channel > 5600){2930modes_txgaintable_index = 6;2931}2932}2933modes_index = 2;2934freq_index = 1;2935break;29362937case CHANNEL_PUREG:2938case CHANNEL_G_HT20:2939case CHANNEL_B:2940if (AR_SREV_SCORPION(ah)){2941modes_txgaintable_index = 8;2942}else if (AR_SREV_HONEYBEE(ah)){2943modes_txgaintable_index = 1;2944}2945modes_index = 4;2946freq_index = 2;2947break;29482949case CHANNEL_G_HT40PLUS:2950case CHANNEL_G_HT40MINUS:2951if (AR_SREV_SCORPION(ah)){2952modes_txgaintable_index = 7;2953}else if (AR_SREV_HONEYBEE(ah)){2954modes_txgaintable_index = 1;2955}2956modes_index = 3;2957freq_index = 2;2958break;29592960case CHANNEL_108G:2961modes_index = 5;2962freq_index = 2;2963break;29642965default:2966HALASSERT(0);2967return HAL_EINVAL;2968}2969#endif29702971/* FreeBSD */2972if (IS_CHAN_5GHZ(ichan)) {2973if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) {2974if (AR_SREV_SCORPION(ah)){2975if (ichan->channel <= 5350){2976modes_txgaintable_index = 2;2977}else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){2978modes_txgaintable_index = 4;2979}else if (ichan->channel > 5600){2980modes_txgaintable_index = 6;2981}2982}2983modes_index = 2;2984} else if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_HT20(chan)) {2985if (AR_SREV_SCORPION(ah)){2986if (ichan->channel <= 5350){2987modes_txgaintable_index = 1;2988}else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){2989modes_txgaintable_index = 3;2990}else if (ichan->channel > 5600){2991modes_txgaintable_index = 5;2992}2993}2994modes_index = 1;2995} else2996return HAL_EINVAL;2997} else if (IS_CHAN_2GHZ(ichan)) {2998if (IEEE80211_IS_CHAN_108G(chan)) {2999modes_index = 5;3000} else if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) {3001if (AR_SREV_SCORPION(ah)){3002modes_txgaintable_index = 7;3003} else if (AR_SREV_HONEYBEE(ah)){3004modes_txgaintable_index = 1;3005}3006modes_index = 3;3007} else if (IEEE80211_IS_CHAN_HT20(chan) || IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_PUREG(chan)) {3008if (AR_SREV_SCORPION(ah)){3009modes_txgaintable_index = 8;3010} else if (AR_SREV_HONEYBEE(ah)){3011modes_txgaintable_index = 1;3012}3013modes_index = 4;3014} else3015return HAL_EINVAL;3016} else3017return HAL_EINVAL;30183019#if 03020/* Set correct Baseband to analog shift setting to access analog chips. */3021OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);3022#endif30233024HALDEBUG(ah, HAL_DEBUG_RESET,3025"ar9300_process_ini: "3026"Skipping OS-REG-WRITE(ah, AR-PHY(0), 0x00000007)\n");3027HALDEBUG(ah, HAL_DEBUG_RESET,3028"ar9300_process_ini: no ADDac programming\n");302930303031/*3032* Osprey 2.0+ - new INI format.3033* Each subsystem has a pre, core, and post array.3034*/3035for (i = 0; i < ATH_INI_NUM_SPLIT; i++) {3036ar9300_prog_ini(ah, &ahp->ah_ini_soc[i], modes_index);3037ar9300_prog_ini(ah, &ahp->ah_ini_mac[i], modes_index);3038ar9300_prog_ini(ah, &ahp->ah_ini_bb[i], modes_index);3039ar9300_prog_ini(ah, &ahp->ah_ini_radio[i], modes_index);3040if ((i == ATH_INI_POST) && (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah))) {3041ar9300_prog_ini(ah, &ahp->ah_ini_radio_post_sys2ant, modes_index);3042}30433044}30453046if (!(AR_SREV_SOC(ah))) {3047/* Doubler issue : Some board doesn't work well with MCS15. Turn off doubler after freq locking is complete*/3048//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));3049OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |30501 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */3051//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));30523053OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |30541 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */3055OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |30561 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */3057OS_DELAY(200);30583059//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));3060OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */3061OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */3062OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */3063//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));30643065OS_DELAY(1);30663067//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));3068OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */3069OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */3070OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */3071//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));30723073OS_DELAY(200);30743075//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));3076OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf);3077//OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_SYNTH12, 1<< 16); /* clr charge pump */3078//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));30793080OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |30811 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */3082OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |30831 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */3084OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S |30851 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */3086//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));3087}30883089/* Write rxgain Array Parameters */3090REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain, 1, reg_writes);3091HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain programming\n");30923093if (AR_SREV_JUPITER_20_OR_LATER(ah)) {3094/*3095* CUS217 mix LNA mode.3096*/3097if (ar9300_rx_gain_index_get(ah) == 2) {3098REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bb_core, 1, reg_writes);3099REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bb_postamble,3100modes_index, reg_writes);3101}31023103/*3104* 5G-XLNA3105*/3106if ((ar9300_rx_gain_index_get(ah) == 2) ||3107(ar9300_rx_gain_index_get(ah) == 3)) {3108REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_xlna, modes_index,3109reg_writes);3110}3111}31123113if (AR_SREV_SCORPION(ah)) {3114/* Write rxgain bounds Array */3115REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, modes_index, reg_writes);3116HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain table bounds programming\n");3117}3118/* UB124 xLNA settings */3119if (AR_SREV_WASP(ah) && ar9300_rx_gain_index_get(ah) == 2) {3120#define REG_WRITE(_reg,_val) *((volatile u_int32_t *)(_reg)) = (_val);3121#define REG_READ(_reg) *((volatile u_int32_t *)(_reg))3122u_int32_t val;3123/* B8040000: bit[0]=0, bit[3]=0; */3124val = REG_READ(0xB8040000);3125val &= 0xfffffff6;3126REG_WRITE(0xB8040000, val);3127/* B804002c: bit[31:24]=0x2e; bit[7:0]=0x2f; */3128val = REG_READ(0xB804002c);3129val &= 0x00ffff00;3130val |= 0x2e00002f;3131REG_WRITE(0xB804002c, val);3132/* B804006c: bit[1]=1; */3133val = REG_READ(0xB804006c);3134val |= 0x2;3135REG_WRITE(0xB804006c, val);3136#undef REG_READ3137#undef REG_WRITE3138}313931403141/* Write txgain Array Parameters */3142if (AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {3143REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_txgaintable_index,3144reg_writes);3145}else{3146REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_index, reg_writes);3147}3148HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Tx Gain programming\n");314931503151/* For 5GHz channels requiring Fast Clock, apply different modal values */3152if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) {3153HALDEBUG(ah, HAL_DEBUG_RESET,3154"%s: Fast clock enabled, use special ini values\n", __func__);3155REG_WRITE_ARRAY(&ahp->ah_ini_modes_additional, modes_index, reg_writes);3156}31573158if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {3159HALDEBUG(ah, HAL_DEBUG_RESET,3160"%s: use xtal ini for AH9300(ah)->clk_25mhz: %d\n",3161__func__, AH9300(ah)->clk_25mhz);3162REG_WRITE_ARRAY(3163&ahp->ah_ini_modes_additional, 1/*modes_index*/, reg_writes);3164}31653166if (AR_SREV_WASP(ah) && (AH9300(ah)->clk_25mhz == 0)) {3167HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Apply 40MHz ini settings\n", __func__);3168REG_WRITE_ARRAY(3169&ahp->ah_ini_modes_additional_40mhz, 1/*modesIndex*/, reg_writes);3170}31713172/* Handle Japan Channel 14 channel spreading */3173if (2484 == ichan->channel) {3174ar9300_prog_ini(ah, &ahp->ah_ini_japan2484, 1);3175}31763177#if 03178/* XXX TODO! */3179if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) {3180ar9300_prog_ini(ah, &ahp->ah_ini_BTCOEX_MAX_TXPWR, 1);3181}3182#endif31833184/* Override INI with chip specific configuration */3185ar9300_override_ini(ah, chan);31863187/* Setup 11n MAC/Phy mode registers */3188ar9300_set_11n_regs(ah, chan, macmode);31893190/*3191* Moved ar9300_init_chain_masks() here to ensure the swap bit is set before3192* the pdadc table is written. Swap must occur before any radio dependent3193* replicated register access. The pdadc curve addressing in particular3194* depends on the consistent setting of the swap bit.3195*/3196ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask);31973198/*3199* Setup the transmit power values.3200*3201* After the public to private hal channel mapping, ichan contains the3202* valid regulatory power value.3203* ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan.3204*/3205status = ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan,3206ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan),3207ath_hal_get_twice_max_regpower(ahpriv, ichan, chan),3208AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit));3209if (status != HAL_OK) {3210HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,3211"%s: error init'ing transmit power\n", __func__);3212return HAL_EIO;3213}321432153216return HAL_OK;3217#undef N3218}32193220/* ar9300_is_cal_supp3221* Determine if calibration is supported by device and channel flags3222*/3223inline static HAL_BOOL3224ar9300_is_cal_supp(struct ath_hal *ah, const struct ieee80211_channel *chan,3225HAL_CAL_TYPES cal_type)3226{3227struct ath_hal_9300 *ahp = AH9300(ah);3228HAL_BOOL retval = AH_FALSE;32293230switch (cal_type & ahp->ah_supp_cals) {3231case IQ_MISMATCH_CAL:3232/* Run IQ Mismatch for non-CCK only */3233if (!IEEE80211_IS_CHAN_B(chan)) {3234retval = AH_TRUE;3235}3236break;3237case TEMP_COMP_CAL:3238retval = AH_TRUE;3239break;3240}32413242return retval;3243}324432453246#if 03247/* ar9285_pa_cal3248* PA Calibration for Kite 1.1 and later versions of Kite.3249* - from system's team.3250*/3251static inline void3252ar9285_pa_cal(struct ath_hal *ah)3253{3254u_int32_t reg_val;3255int i, lo_gn, offs_6_1, offs_0;3256u_int8_t reflo;3257u_int32_t phy_test2_reg_val, phy_adc_ctl_reg_val;3258u_int32_t an_top2_reg_val, phy_tst_dac_reg_val;325932603261/* Kite 1.1 WAR for Bug 356663262* Increase the LDO value to 1.28V before accessing analog Reg */3263if (AR_SREV_KITE_11(ah)) {3264OS_REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14) );3265}3266an_top2_reg_val = OS_REG_READ(ah, AR9285_AN_TOP2);32673268/* set pdv2i pdrxtxbb */3269reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1);3270reg_val |= ((0x1 << 5) | (0x1 << 7));3271OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val);32723273/* clear pwddb */3274reg_val = OS_REG_READ(ah, AR9285_AN_RF2G7);3275reg_val &= 0xfffffffd;3276OS_REG_WRITE(ah, AR9285_AN_RF2G7, reg_val);32773278/* clear enpacal */3279reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);3280reg_val &= 0xfffff7ff;3281OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);32823283/* set offcal */3284reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2);3285reg_val |= (0x1 << 12);3286OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val);32873288/* set pdpadrv1=pdpadrv2=pdpaout=1 */3289reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);3290reg_val |= (0x7 << 23);3291OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);32923293/* Read back reflo, increase it by 1 and write it. */3294reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);3295reflo = ((reg_val >> 26) & 0x7);32963297if (reflo < 0x7) {3298reflo++;3299}3300reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26));3301OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);33023303reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);3304reflo = ((reg_val >> 26) & 0x7);33053306/* use TX single carrier to transmit3307* dac const3308* reg. 153309*/3310phy_tst_dac_reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST);3311OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, ((0x7ff << 11) | 0x7ff));3312reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST);33133314/* source is dac const3315* reg. 23316*/3317phy_test2_reg_val = OS_REG_READ(ah, AR_PHY_TEST2);3318OS_REG_WRITE(ah, AR_PHY_TEST2, ((0x1 << 7) | (0x1 << 1)));3319reg_val = OS_REG_READ(ah, AR_PHY_TEST2);33203321/* set dac on3322* reg. 113323*/3324phy_adc_ctl_reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL);3325OS_REG_WRITE(ah, AR_PHY_ADC_CTL, 0x80008000);3326reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL);33273328OS_REG_WRITE(ah, AR9285_AN_TOP2, (0x1 << 27) | (0x1 << 17) | (0x1 << 16) |3329(0x1 << 14) | (0x1 << 12) | (0x1 << 11) |3330(0x1 << 7) | (0x1 << 5));33313332OS_DELAY(10); /* 10 usec */33333334/* clear off[6:0] */3335reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);3336reg_val &= 0xfc0fffff;3337OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);3338reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);3339reg_val &= 0xfdffffff;3340OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);33413342offs_6_1 = 0;3343for (i = 6; i > 0; i--) {3344/* sef off[$k]==1 */3345reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);3346reg_val &= 0xfc0fffff;3347reg_val = reg_val | (0x1 << (19 + i)) | ((offs_6_1) << 20);3348OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);3349lo_gn = (OS_REG_READ(ah, AR9285_AN_RF2G9)) & 0x1;3350offs_6_1 = offs_6_1 | (lo_gn << (i - 1));3351}33523353reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6);3354reg_val &= 0xfc0fffff;3355reg_val = reg_val | ((offs_6_1 - 1) << 20);3356OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val);33573358/* set off_0=1; */3359reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);3360reg_val &= 0xfdffffff;3361reg_val = reg_val | (0x1 << 25);3362OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);33633364lo_gn = OS_REG_READ(ah, AR9285_AN_RF2G9) & 0x1;3365offs_0 = lo_gn;33663367reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);3368reg_val &= 0xfdffffff;3369reg_val = reg_val | (offs_0 << 25);3370OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);33713372/* clear pdv2i */3373reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1);3374reg_val &= 0xffffff5f;3375OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val);33763377/* set enpacal */3378reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);3379reg_val |= (0x1 << 11);3380OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);33813382/* clear offcal */3383reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2);3384reg_val &= 0xffffefff;3385OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val);33863387/* set pdpadrv1=pdpadrv2=pdpaout=0 */3388reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1);3389reg_val &= 0xfc7fffff;3390OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val);33913392/* Read back reflo, decrease it by 1 and write it. */3393reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);3394reflo = (reg_val >> 26) & 0x7;3395if (reflo) {3396reflo--;3397}3398reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26));3399OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val);3400reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3);3401reflo = (reg_val >> 26) & 0x7;34023403/* write back registers */3404OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, phy_tst_dac_reg_val);3405OS_REG_WRITE(ah, AR_PHY_TEST2, phy_test2_reg_val);3406OS_REG_WRITE(ah, AR_PHY_ADC_CTL, phy_adc_ctl_reg_val);3407OS_REG_WRITE(ah, AR9285_AN_TOP2, an_top2_reg_val);34083409/* Kite 1.1 WAR for Bug 356663410* Decrease the LDO value back to 1.20V */3411if (AR_SREV_KITE_11(ah)) {3412OS_REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);3413}3414}3415#endif34163417/* ar9300_run_init_cals3418* Runs non-periodic calibrations3419*/3420inline static HAL_BOOL3421ar9300_run_init_cals(struct ath_hal *ah, int init_cal_count)3422{3423struct ath_hal_9300 *ahp = AH9300(ah);3424HAL_CHANNEL_INTERNAL ichan; /* bogus */3425HAL_BOOL is_cal_done;3426HAL_CAL_LIST *curr_cal;3427const HAL_PERCAL_DATA *cal_data;3428int i;34293430curr_cal = ahp->ah_cal_list_curr;3431if (curr_cal == AH_NULL) {3432return AH_FALSE;3433}3434cal_data = curr_cal->cal_data;3435ichan.calValid = 0;34363437for (i = 0; i < init_cal_count; i++) {3438/* Reset this Cal */3439ar9300_reset_calibration(ah, curr_cal);3440/* Poll for offset calibration complete */3441if (!ath_hal_wait(3442ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL, 0))3443{3444HALDEBUG(ah, HAL_DEBUG_CALIBRATE,3445"%s: Cal %d failed to complete in 100ms.\n",3446__func__, curr_cal->cal_data->cal_type);3447/* Re-initialize list pointers for periodic cals */3448ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr3449= AH_NULL;3450return AH_FALSE;3451}3452/* Run this cal */3453ar9300_per_calibration(3454ah, &ichan, ahp->ah_rx_chainmask, curr_cal, &is_cal_done);3455if (is_cal_done == AH_FALSE) {3456HALDEBUG(ah, HAL_DEBUG_CALIBRATE,3457"%s: Not able to run Init Cal %d.\n", __func__,3458curr_cal->cal_data->cal_type);3459}3460if (curr_cal->cal_next) {3461curr_cal = curr_cal->cal_next;3462}3463}34643465/* Re-initialize list pointers for periodic cals */3466ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL;3467return AH_TRUE;3468}34693470#if 03471static void3472ar9300_tx_carrier_leak_war(struct ath_hal *ah)3473{3474unsigned long tx_gain_table_max;3475unsigned long reg_bb_cl_map_0_b0 = 0xffffffff;3476unsigned long reg_bb_cl_map_1_b0 = 0xffffffff;3477unsigned long reg_bb_cl_map_2_b0 = 0xffffffff;3478unsigned long reg_bb_cl_map_3_b0 = 0xffffffff;3479unsigned long tx_gain, cal_run = 0;3480unsigned long cal_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];3481unsigned long cal_gain_index[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];3482unsigned long new_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1];3483int i, j;34843485OS_MEMSET(new_gain, 0, sizeof(new_gain));3486/*printf(" Running TxCarrierLeakWAR\n");*/34873488/* process tx gain table, we use cl_map_hw_gen=0. */3489OS_REG_RMW_FIELD(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_MAP_HW_GEN, 0);34903491//the table we used is txbb_gc[2:0], 1dB[2:1].3492tx_gain_table_max = OS_REG_READ_FIELD(ah,3493AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX);34943495for (i = 0; i <= tx_gain_table_max; i++) {3496tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4);3497cal_gain[i] = (((tx_gain >> 5)& 0x7) << 2) |3498(((tx_gain >> 1) & 0x3) << 0);3499if (i == 0) {3500cal_gain_index[i] = cal_run;3501new_gain[i] = 1;3502cal_run++;3503} else {3504new_gain[i] = 1;3505for (j = 0; j < i; j++) {3506/*3507printf("i=%d, j=%d cal_gain[$i]=0x%04x\n", i, j, cal_gain[i]);3508*/3509if (new_gain[i]) {3510if ((cal_gain[i] != cal_gain[j])) {3511new_gain[i] = 1;3512} else {3513/* if old gain found, use old cal_run value. */3514new_gain[i] = 0;3515cal_gain_index[i] = cal_gain_index[j];3516}3517}3518}3519/* if new gain found, increase cal_run */3520if (new_gain[i] == 1) {3521cal_gain_index[i] = cal_run;3522cal_run++;3523}3524}35253526reg_bb_cl_map_0_b0 = (reg_bb_cl_map_0_b0 & ~(0x1 << i)) |3527((cal_gain_index[i] >> 0 & 0x1) << i);3528reg_bb_cl_map_1_b0 = (reg_bb_cl_map_1_b0 & ~(0x1 << i)) |3529((cal_gain_index[i] >> 1 & 0x1) << i);3530reg_bb_cl_map_2_b0 = (reg_bb_cl_map_2_b0 & ~(0x1 << i)) |3531((cal_gain_index[i] >> 2 & 0x1) << i);3532reg_bb_cl_map_3_b0 = (reg_bb_cl_map_3_b0 & ~(0x1 << i)) |3533((cal_gain_index[i] >> 3 & 0x1) << i);35343535/*3536printf("i=%2d, cal_gain[$i]= 0x%04x, cal_run= %d, "3537"cal_gain_index[i]=%d, new_gain[i] = %d\n",3538i, cal_gain[i], cal_run, cal_gain_index[i], new_gain[i]);3539*/3540}3541OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B0, reg_bb_cl_map_0_b0);3542OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B0, reg_bb_cl_map_1_b0);3543OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B0, reg_bb_cl_map_2_b0);3544OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B0, reg_bb_cl_map_3_b0);3545if (AR_SREV_WASP(ah)) {3546OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B1, reg_bb_cl_map_0_b0);3547OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B1, reg_bb_cl_map_1_b0);3548OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B1, reg_bb_cl_map_2_b0);3549OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B1, reg_bb_cl_map_3_b0);3550}3551}3552#endif355335543555static inline void3556ar9300_invalidate_saved_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)3557{3558#if ATH_SUPPORT_CAL_REUSE3559if (AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse &3560ATH_CAL_REUSE_REDO_IN_FULL_RESET)3561{3562ichan->one_time_txiqcal_done = AH_FALSE;3563ichan->one_time_txclcal_done = AH_FALSE;3564}3565#endif3566}35673568static inline HAL_BOOL3569ar9300_restore_rtt_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)3570{3571HAL_BOOL restore_status = AH_FALSE;35723573return restore_status;3574}35753576/* ar9300_init_cal3577* Initialize Calibration infrastructure3578*/3579static inline HAL_BOOL3580ar9300_init_cal_internal(struct ath_hal *ah, struct ieee80211_channel *chan,3581HAL_CHANNEL_INTERNAL *ichan,3582HAL_BOOL enable_rtt, HAL_BOOL do_rtt_cal, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr)3583{3584struct ath_hal_9300 *ahp = AH9300(ah);3585HAL_BOOL txiqcal_success_flag = AH_FALSE;3586HAL_BOOL cal_done = AH_FALSE;3587int iqcal_idx = 0;3588HAL_BOOL do_sep_iq_cal = AH_FALSE;3589HAL_BOOL do_agc_cal = do_rtt_cal;3590HAL_BOOL is_cal_reusable = AH_TRUE;3591#if ATH_SUPPORT_CAL_REUSE3592HAL_BOOL cal_reuse_enable = AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse &3593ATH_CAL_REUSE_ENABLE;3594HAL_BOOL clc_success = AH_FALSE;3595int32_t ch_idx, j, cl_tab_reg;3596u_int32_t BB_cl_tab_entry = MAX_BB_CL_TABLE_ENTRY;3597u_int32_t BB_cl_tab_b[AR9300_MAX_CHAINS] = {3598AR_PHY_CL_TAB_0,3599AR_PHY_CL_TAB_1,3600AR_PHY_CL_TAB_23601};3602#endif36033604if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {3605/* Hornet: 1 x 1 */3606ahp->ah_rx_cal_chainmask = 0x1;3607ahp->ah_tx_cal_chainmask = 0x1;3608} else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah) || AR_SREV_HONEYBEE(ah)) {3609/* Wasp/Jupiter: 2 x 2 */3610ahp->ah_rx_cal_chainmask = 0x3;3611ahp->ah_tx_cal_chainmask = 0x3;3612} else {3613/*3614* Osprey needs to be configured for the correct chain mode3615* before running AGC/TxIQ cals.3616*/3617if (ahp->ah_enterprise_mode & AR_ENT_OTP_CHAIN2_DISABLE) {3618/* chain 2 disabled - 2 chain mode */3619ahp->ah_rx_cal_chainmask = 0x3;3620ahp->ah_tx_cal_chainmask = 0x3;3621} else {3622ahp->ah_rx_cal_chainmask = 0x7;3623ahp->ah_tx_cal_chainmask = 0x7;3624}3625}3626ar9300_init_chain_masks(ah, ahp->ah_rx_cal_chainmask, ahp->ah_tx_cal_chainmask);362736283629if (ahp->tx_cl_cal_enable) {3630#if ATH_SUPPORT_CAL_REUSE3631/* disable Carrie Leak or set do_agc_cal accordingly */3632if (cal_reuse_enable && ichan->one_time_txclcal_done)3633{3634OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);3635} else3636#endif /* ATH_SUPPORT_CAL_REUSE */3637{3638OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);3639do_agc_cal = AH_TRUE;3640}3641}36423643/* Do Tx IQ Calibration here for osprey hornet and wasp */3644/* XXX: For initial wasp bringup - check and enable this */3645/* EV 74233: Tx IQ fails to complete for half/quarter rates */3646if (!(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) {3647if (ahp->tx_iq_cal_enable) {3648/* this should be eventually moved to INI file */3649OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah),3650AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT);36513652/*3653* For poseidon and later chips,3654* Tx IQ cal HW run will be a part of AGC calibration3655*/3656if (ahp->tx_iq_cal_during_agc_cal) {3657/*3658* txiqcal_success_flag always set to 1 to run3659* ar9300_tx_iq_cal_post_proc3660* if following AGC cal passes3661*/3662#if ATH_SUPPORT_CAL_REUSE3663if (!cal_reuse_enable || !ichan->one_time_txiqcal_done)3664{3665txiqcal_success_flag = AH_TRUE;3666OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),3667OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) |3668AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);3669} else {3670OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),3671OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) &3672(~AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL));3673}3674#else3675if (OS_REG_READ_FIELD(ah,3676AR_PHY_TX_IQCAL_CONTROL_0(ah),3677AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)){3678if (apply_last_iqcorr == AH_TRUE) {3679OS_REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),3680AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);3681txiqcal_success_flag = AH_FALSE;3682} else {3683txiqcal_success_flag = AH_TRUE;3684}3685}else{3686txiqcal_success_flag = AH_FALSE;3687}3688#endif3689if (txiqcal_success_flag) {3690do_agc_cal = AH_TRUE;3691}3692} else3693#if ATH_SUPPORT_CAL_REUSE3694if (!cal_reuse_enable || !ichan->one_time_txiqcal_done)3695#endif3696{3697do_sep_iq_cal = AH_TRUE;3698do_agc_cal = AH_TRUE;3699}3700}3701}37023703#if ATH_SUPPORT_MCI3704if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&3705IS_CHAN_2GHZ(ichan) &&3706(ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&3707do_agc_cal &&3708!(ah->ah_config.ath_hal_mci_config &3709ATH_MCI_CONFIG_DISABLE_MCI_CAL))3710{3711u_int32_t payload[4] = {0, 0, 0, 0};37123713/* Send CAL_REQ only when BT is AWAKE. */3714HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_REQ 0x%X\n",3715__func__, ahp->ah_mci_wlan_cal_seq);3716MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_REQ);3717payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_seq++;3718ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);37193720/* Wait BT_CAL_GRANT for 50ms */3721HALDEBUG(ah, HAL_DEBUG_BT_COEX,3722"(MCI) %s: Wait for BT_CAL_GRANT\n", __func__);3723if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000))3724{3725HALDEBUG(ah, HAL_DEBUG_BT_COEX,3726"(MCI) %s: Got BT_CAL_GRANT.\n", __func__);3727}3728else {3729is_cal_reusable = AH_FALSE;3730HALDEBUG(ah, HAL_DEBUG_BT_COEX,3731"(MCI) %s: BT is not responding.\n", __func__);3732}3733}3734#endif /* ATH_SUPPORT_MCI */37353736if (do_sep_iq_cal)3737{3738/* enable Tx IQ Calibration HW for osprey/hornet/wasp */3739txiqcal_success_flag = ar9300_tx_iq_cal_hw_run(ah);3740OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);3741OS_DELAY(5);3742OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);3743}3744#if 03745if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) {3746ar9300_tx_carrier_leak_war(ah);3747}3748#endif3749/*3750* Calibrate the AGC3751*3752* Tx IQ cal is a part of AGC cal for Jupiter/Poseidon, etc.3753* please enable the bit of txiqcal_control_0[31] in INI file3754* for Jupiter/Poseidon/etc.3755*/3756if(!AR_SREV_SCORPION(ah)) {3757if (do_agc_cal || !skip_if_none) {3758OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,3759OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);37603761/* Poll for offset calibration complete */3762cal_done = ath_hal_wait(ah,3763AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0);3764if (!cal_done) {3765HALDEBUG(ah, HAL_DEBUG_FCS_RTT,3766"(FCS) CAL NOT DONE!!! - %d\n", ichan->channel);3767}3768} else {3769cal_done = AH_TRUE;3770}3771/*3772* Tx IQ cal post-processing in SW3773* This part of code should be common to all chips,3774* no chip specific code for Jupiter/Posdeion except for register names.3775*/3776if (txiqcal_success_flag) {3777ar9300_tx_iq_cal_post_proc(ah,ichan, 1, 1,is_cal_reusable, AH_FALSE);3778}3779} else {3780if (!txiqcal_success_flag) {3781OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,3782OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);3783if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,37840)) {3785HALDEBUG(ah, HAL_DEBUG_CALIBRATE,3786"%s: offset calibration failed to complete in 1ms; "3787"noisy environment?\n", __func__);3788return AH_FALSE;3789}3790if (apply_last_iqcorr == AH_TRUE) {3791ar9300_tx_iq_cal_post_proc(ah, ichan, 0, 0, is_cal_reusable, AH_TRUE);3792}3793} else {3794for (iqcal_idx=0;iqcal_idx<MAXIQCAL;iqcal_idx++) {3795OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,3796OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);37973798/* Poll for offset calibration complete */3799if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL,3800AR_PHY_AGC_CONTROL_CAL, 0)) {3801HALDEBUG(ah, HAL_DEBUG_CALIBRATE,3802"%s: offset calibration failed to complete in 1ms; "3803"noisy environment?\n", __func__);3804return AH_FALSE;3805}3806/*3807* Tx IQ cal post-processing in SW3808* This part of code should be common to all chips,3809* no chip specific code for Jupiter/Posdeion except for register names.3810*/3811ar9300_tx_iq_cal_post_proc(ah, ichan, iqcal_idx+1, MAXIQCAL, is_cal_reusable, AH_FALSE);3812}3813}3814}381538163817#if ATH_SUPPORT_MCI3818if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&3819IS_CHAN_2GHZ(ichan) &&3820(ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&3821do_agc_cal &&3822!(ah->ah_config.ath_hal_mci_config &3823ATH_MCI_CONFIG_DISABLE_MCI_CAL))3824{3825u_int32_t payload[4] = {0, 0, 0, 0};38263827HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_DONE 0x%X\n",3828__func__, ahp->ah_mci_wlan_cal_done);3829MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);3830payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_done++;3831ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);3832}3833#endif /* ATH_SUPPORT_MCI */383438353836if (!cal_done && !AR_SREV_SCORPION(ah) )3837{3838HALDEBUG(ah, HAL_DEBUG_CALIBRATE,3839"%s: offset calibration failed to complete in 1ms; "3840"noisy environment?\n", __func__);3841return AH_FALSE;3842}38433844#if 03845/* Beacon stuck fix, refer to EV 120056 */3846if(IS_CHAN_2GHZ(chan) && AR_SREV_SCORPION(ah))3847OS_REG_WRITE(ah, AR_PHY_TIMING5, OS_REG_READ(ah,AR_PHY_TIMING5) & ~AR_PHY_TIMING5_CYCPWR_THR1_ENABLE);3848#endif38493850#if 03851/* Do PA Calibration */3852if (AR_SREV_KITE(ah) && AR_SREV_KITE_11_OR_LATER(ah)) {3853ar9285_pa_cal(ah);3854}3855#endif38563857#if ATH_SUPPORT_CAL_REUSE3858if (ichan->one_time_txiqcal_done) {3859ar9300_tx_iq_cal_apply(ah, ichan);3860HALDEBUG(ah, HAL_DEBUG_FCS_RTT,3861"(FCS) TXIQCAL applied - %d\n", ichan->channel);3862}3863#endif /* ATH_SUPPORT_CAL_REUSE */38643865#if ATH_SUPPORT_CAL_REUSE3866if (cal_reuse_enable && ahp->tx_cl_cal_enable)3867{3868clc_success = (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) &3869AR_PHY_AGC_CONTROL_CLC_SUCCESS) ? 1 : 0;38703871if (ichan->one_time_txclcal_done)3872{3873/* reapply CL cal results */3874for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {3875if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {3876continue;3877}3878cl_tab_reg = BB_cl_tab_b[ch_idx];3879for (j = 0; j < BB_cl_tab_entry; j++) {3880OS_REG_WRITE(ah, cl_tab_reg, ichan->tx_clcal[ch_idx][j]);3881cl_tab_reg += 4;3882}3883}3884HALDEBUG(ah, HAL_DEBUG_FCS_RTT,3885"(FCS) TX CL CAL applied - %d\n", ichan->channel);3886}3887else if (is_cal_reusable && clc_success) {3888/* save CL cal results */3889for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {3890if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {3891continue;3892}3893cl_tab_reg = BB_cl_tab_b[ch_idx];3894for (j = 0; j < BB_cl_tab_entry; j++) {3895ichan->tx_clcal[ch_idx][j] = OS_REG_READ(ah, cl_tab_reg);3896cl_tab_reg += 4;3897}3898}3899ichan->one_time_txclcal_done = AH_TRUE;3900HALDEBUG(ah, HAL_DEBUG_FCS_RTT,3901"(FCS) TX CL CAL saved - %d\n", ichan->channel);3902}3903}3904#endif /* ATH_SUPPORT_CAL_REUSE */39053906/* Revert chainmasks to their original values before NF cal */3907ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask);39083909#if !FIX_NOISE_FLOOR3910/*3911* Do NF calibration after DC offset and other CALs.3912* Per system engineers, noise floor value can sometimes be 20 dB3913* higher than normal value if DC offset and noise floor cal are3914* triggered at the same time.3915*/3916OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,3917OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);3918#endif39193920/* Initialize list pointers */3921ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL;39223923/*3924* Enable IQ, ADC Gain, ADC DC Offset Cals3925*/3926/* Setup all non-periodic, init time only calibrations */3927/* XXX: Init DC Offset not working yet */3928#ifdef not_yet3929if (AH_TRUE == ar9300_is_cal_supp(ah, chan, ADC_DC_INIT_CAL)) {3930INIT_CAL(&ahp->ah_adc_dc_cal_init_data);3931INSERT_CAL(ahp, &ahp->ah_adc_dc_cal_init_data);3932}39333934/* Initialize current pointer to first element in list */3935ahp->ah_cal_list_curr = ahp->ah_cal_list;39363937if (ahp->ah_cal_list_curr) {3938if (ar9300_run_init_cals(ah, 0) == AH_FALSE) {3939return AH_FALSE;3940}3941}3942#endif3943/* end - Init time calibrations */39443945/* Do not do RX cal in case of offchan, or cal data already exists on same channel*/3946if (ahp->ah_skip_rx_iq_cal) {3947HALDEBUG(ah, HAL_DEBUG_CALIBRATE,3948"Skip RX IQ Cal\n");3949return AH_TRUE;3950}39513952/* If Cals are supported, add them to list via INIT/INSERT_CAL */3953if (AH_TRUE == ar9300_is_cal_supp(ah, chan, IQ_MISMATCH_CAL)) {3954INIT_CAL(&ahp->ah_iq_cal_data);3955INSERT_CAL(ahp, &ahp->ah_iq_cal_data);3956HALDEBUG(ah, HAL_DEBUG_CALIBRATE,3957"%s: enabling IQ Calibration.\n", __func__);3958}3959if (AH_TRUE == ar9300_is_cal_supp(ah, chan, TEMP_COMP_CAL)) {3960INIT_CAL(&ahp->ah_temp_comp_cal_data);3961INSERT_CAL(ahp, &ahp->ah_temp_comp_cal_data);3962HALDEBUG(ah, HAL_DEBUG_CALIBRATE,3963"%s: enabling Temperature Compensation Calibration.\n", __func__);3964}39653966/* Initialize current pointer to first element in list */3967ahp->ah_cal_list_curr = ahp->ah_cal_list;39683969/* Reset state within current cal */3970if (ahp->ah_cal_list_curr) {3971ar9300_reset_calibration(ah, ahp->ah_cal_list_curr);3972}39733974/* Mark all calibrations on this channel as being invalid */3975ichan->calValid = 0;39763977return AH_TRUE;3978}39793980static inline HAL_BOOL3981ar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr)3982{3983HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);3984HAL_BOOL do_rtt_cal = AH_TRUE;3985HAL_BOOL enable_rtt = AH_FALSE;39863987HALASSERT(ichan);39883989return ar9300_init_cal_internal(ah, chan, ichan, enable_rtt, do_rtt_cal, skip_if_none, apply_last_iqcorr);3990}39913992/* ar9300_reset_cal_valid3993* Entry point for upper layers to restart current cal.3994* Reset the calibration valid bit in channel.3995*/3996void3997ar9300_reset_cal_valid(struct ath_hal *ah, const struct ieee80211_channel *chan,3998HAL_BOOL *is_cal_done, u_int32_t cal_type)3999{4000struct ath_hal_9300 *ahp = AH9300(ah);4001HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);4002HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr;40034004*is_cal_done = AH_TRUE;40054006if (curr_cal == AH_NULL) {4007return;4008}4009if (ichan == AH_NULL) {4010HALDEBUG(ah, HAL_DEBUG_CALIBRATE,4011"%s: invalid channel %u/0x%x; no mapping\n",4012__func__, chan->ic_freq, chan->ic_flags);4013return;4014}40154016if (!(cal_type & IQ_MISMATCH_CAL)) {4017*is_cal_done = AH_FALSE;4018return;4019}40204021/* Expected that this calibration has run before, post-reset.4022* Current state should be done4023*/4024if (curr_cal->cal_state != CAL_DONE) {4025HALDEBUG(ah, HAL_DEBUG_CALIBRATE,4026"%s: Calibration state incorrect, %d\n",4027__func__, curr_cal->cal_state);4028return;4029}40304031/* Verify Cal is supported on this channel */4032if (ar9300_is_cal_supp(ah, chan, curr_cal->cal_data->cal_type) == AH_FALSE) {4033return;4034}40354036HALDEBUG(ah, HAL_DEBUG_CALIBRATE,4037"%s: Resetting Cal %d state for channel %u/0x%x\n", __func__,4038curr_cal->cal_data->cal_type, chan->ic_freq, chan->ic_flags);40394040/* Disable cal validity in channel */4041ichan->calValid &= ~curr_cal->cal_data->cal_type;4042curr_cal->cal_state = CAL_WAITING;4043/* Indicate to upper layers that we need polling */4044*is_cal_done = AH_FALSE;4045}40464047static inline void4048ar9300_set_dma(struct ath_hal *ah)4049{4050u_int32_t regval;4051struct ath_hal_9300 *ahp = AH9300(ah);4052struct ath_hal_private *ahpriv = AH_PRIVATE(ah);4053HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;40544055#if 04056/*4057* set AHB_MODE not to do cacheline prefetches4058*/4059regval = OS_REG_READ(ah, AR_AHB_MODE);4060OS_REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);4061#endif40624063/*4064* let mac dma reads be in 128 byte chunks4065*/4066regval = OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;4067OS_REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);40684069/*4070* Restore TX Trigger Level to its pre-reset value.4071* The initial value depends on whether aggregation is enabled, and is4072* adjusted whenever underruns are detected.4073*/4074/*4075OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, AH_PRIVATE(ah)->ah_tx_trig_level);4076*/4077/*4078* Osprey 1.0 bug (EV 61936). Don't change trigger level from .ini default.4079* Osprey 2.0 - hardware recommends using the default INI settings.4080*/4081#if 04082OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, 0x3f);4083#endif4084/*4085* let mac dma writes be in 128 byte chunks4086*/4087regval = OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;4088OS_REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);40894090/*4091* Setup receive FIFO threshold to hold off TX activities4092*/4093OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);40944095/*4096* reduce the number of usable entries in PCU TXBUF to avoid4097* wrap around bugs. (bug 20428)4098*/40994100if (AR_SREV_WASP(ah) &&4101(AH_PRIVATE((ah))->ah_macRev > AR_SREV_REVISION_WASP_12)) {4102/* Wasp 1.3 fix for EV#85395 requires usable entries4103* to be set to 0x5004104*/4105OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, 0x500);4106} else {4107OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE);4108}41094110/*4111* Enable HPQ for UAPSD4112*/4113if (pCap->halHwUapsdTrig == AH_TRUE) {4114/* Only enable this if HAL capabilities says it is OK */4115if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {4116OS_REG_WRITE(ah, AR_HP_Q_CONTROL,4117AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN);4118}4119} else {4120/* use default value from ini file - which disable HPQ queue usage */4121}41224123/*4124* set the transmit status ring4125*/4126ar9300_reset_tx_status_ring(ah);41274128/*4129* set rxbp threshold. Must be non-zero for RX_EOL to occur.4130* For Osprey 2.0+, keep the original thresholds4131* otherwise performance is lost due to excessive RX EOL interrupts.4132*/4133OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1);4134OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1);41354136/*4137* set receive buffer size.4138*/4139if (ahp->rx_buf_size) {4140OS_REG_WRITE(ah, AR_DATABUF, ahp->rx_buf_size);4141}4142}41434144static inline void4145ar9300_init_bb(struct ath_hal *ah, struct ieee80211_channel *chan)4146{4147u_int32_t synth_delay;41484149/*4150* Wait for the frequency synth to settle (synth goes on4151* via AR_PHY_ACTIVE_EN). Read the phy active delay register.4152* Value is in 100ns increments.4153*/4154synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;4155if (IEEE80211_IS_CHAN_CCK(chan)) {4156synth_delay = (4 * synth_delay) / 22;4157} else {4158synth_delay /= 10;4159}41604161/* Activate the PHY (includes baseband activate + synthesizer on) */4162OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);41634164/*4165* There is an issue if the AP starts the calibration before4166* the base band timeout completes. This could result in the4167* rx_clear false triggering. As a workaround we add delay an4168* extra BASE_ACTIVATE_DELAY usecs to ensure this condition4169* does not happen.4170*/4171OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY);4172}41734174static inline void4175ar9300_init_interrupt_masks(struct ath_hal *ah, HAL_OPMODE opmode)4176{4177struct ath_hal_9300 *ahp = AH9300(ah);4178u_int32_t msi_cfg = 0;4179u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT;41804181/*4182* Setup interrupt handling. Note that ar9300_reset_tx_queue4183* manipulates the secondary IMR's as queues are enabled4184* and disabled. This is done with RMW ops to insure the4185* settings we make here are preserved.4186*/4187ahp->ah_mask_reg =4188AR_IMR_TXERR | AR_IMR_TXURN |4189AR_IMR_RXERR | AR_IMR_RXORN |4190AR_IMR_BCNMISC;41914192if (ahp->ah_intr_mitigation_rx) {4193/* enable interrupt mitigation for rx */4194ahp->ah_mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR | AR_IMR_RXOK_HP;4195msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR;4196} else {4197ahp->ah_mask_reg |= AR_IMR_RXOK_LP | AR_IMR_RXOK_HP;4198msi_cfg |= AR_INTCFG_MSI_RXOK;4199}4200if (ahp->ah_intr_mitigation_tx) {4201/* enable interrupt mitigation for tx */4202ahp->ah_mask_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR;4203msi_cfg |= AR_INTCFG_MSI_TXINTM | AR_INTCFG_MSI_TXMINTR;4204} else {4205ahp->ah_mask_reg |= AR_IMR_TXOK;4206msi_cfg |= AR_INTCFG_MSI_TXOK;4207}4208if (opmode == HAL_M_HOSTAP) {4209ahp->ah_mask_reg |= AR_IMR_MIB;4210}42114212OS_REG_WRITE(ah, AR_IMR, ahp->ah_mask_reg);4213OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);4214ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2);42154216if (ah->ah_config.ath_hal_enable_msi) {4217/* Cache MSI register value */4218ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI));4219ahp->ah_msi_reg |= AR_PCIE_MSI_HW_DBI_WR_EN;4220if (AR_SREV_POSEIDON(ah)) {4221ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64;4222} else {4223ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR;4224}4225/* Program MSI configuration */4226OS_REG_WRITE(ah, AR_INTCFG, msi_cfg);4227}42284229/*4230* debug - enable to see all synchronous interrupts status4231*/4232/* Clear any pending sync cause interrupts */4233OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE), 0xFFFFFFFF);42344235/* Allow host interface sync interrupt sources to set cause bit */4236if (AR_SREV_POSEIDON(ah)) {4237sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR;4238}4239else if (AR_SREV_WASP(ah)) {4240sync_en_def = AR9340_INTR_SYNC_DEFAULT;4241}4242OS_REG_WRITE(ah,4243AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), sync_en_def);42444245/* _Disable_ host interface sync interrupt when cause bits set */4246OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 0);42474248OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0);4249OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 0);4250OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE), 0);4251OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK), 0);4252}42534254static inline void4255ar9300_init_qos(struct ath_hal *ah)4256{4257OS_REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); /* XXX magic */4258OS_REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); /* XXX magic */42594260/* Turn on NOACK Support for QoS packets */4261OS_REG_WRITE(ah, AR_QOS_NO_ACK,4262SM(2, AR_QOS_NO_ACK_TWO_BIT) |4263SM(5, AR_QOS_NO_ACK_BIT_OFF) |4264SM(0, AR_QOS_NO_ACK_BYTE_OFF));42654266/*4267* initialize TXOP for all TIDs4268*/4269OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);4270OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);4271OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);4272OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);4273OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);4274}42754276static inline void4277ar9300_init_user_settings(struct ath_hal *ah)4278{4279struct ath_hal_9300 *ahp = AH9300(ah);42804281/* Restore user-specified settings */4282HALDEBUG(ah, HAL_DEBUG_RESET,4283"--AP %s ahp->ah_misc_mode 0x%x\n", __func__, ahp->ah_misc_mode);4284if (ahp->ah_misc_mode != 0) {4285OS_REG_WRITE(ah,4286AR_PCU_MISC, OS_REG_READ(ah, AR_PCU_MISC) | ahp->ah_misc_mode);4287}4288if (ahp->ah_get_plcp_hdr) {4289OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM);4290}4291if (ahp->ah_slot_time != (u_int) -1) {4292ar9300_set_slot_time(ah, ahp->ah_slot_time);4293}4294if (ahp->ah_ack_timeout != (u_int) -1) {4295ar9300_set_ack_timeout(ah, ahp->ah_ack_timeout);4296}4297if (AH_PRIVATE(ah)->ah_diagreg != 0) {4298OS_REG_SET_BIT(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);4299}4300if (ahp->ah_beacon_rssi_threshold != 0) {4301ar9300_set_hw_beacon_rssi_threshold(ah, ahp->ah_beacon_rssi_threshold);4302}4303//#ifdef ATH_SUPPORT_DFS4304if (ahp->ah_cac_quiet_enabled) {4305ar9300_cac_tx_quiet(ah, 1);4306}4307//#endif /* ATH_SUPPORT_DFS */4308}43094310int4311ar9300_get_spur_info(struct ath_hal * ah, int *enable, int len, u_int16_t *freq)4312{4313// struct ath_hal_private *ap = AH_PRIVATE(ah);4314int i, j;43154316for (i = 0; i < len; i++) {4317freq[i] = 0;4318}43194320*enable = ah->ah_config.ath_hal_spur_mode;4321for (i = 0, j = 0; i < AR_EEPROM_MODAL_SPURS; i++) {4322if (AH9300(ah)->ath_hal_spur_chans[i][0] != AR_NO_SPUR) {4323freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][0];4324HALDEBUG(ah, HAL_DEBUG_ANI,4325"1. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][0]);4326}4327if (AH9300(ah)->ath_hal_spur_chans[i][1] != AR_NO_SPUR) {4328freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][1];4329HALDEBUG(ah, HAL_DEBUG_ANI,4330"2. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][1]);4331}4332}43334334return 0;4335}43364337#define ATH_HAL_2GHZ_FREQ_MIN 200004338#define ATH_HAL_2GHZ_FREQ_MAX 299994339#define ATH_HAL_5GHZ_FREQ_MIN 500004340#define ATH_HAL_5GHZ_FREQ_MAX 5999943414342#if 04343int4344ar9300_set_spur_info(struct ath_hal * ah, int enable, int len, u_int16_t *freq)4345{4346struct ath_hal_private *ap = AH_PRIVATE(ah);4347int i, j, k;43484349ap->ah_config.ath_hal_spur_mode = enable;43504351if (ap->ah_config.ath_hal_spur_mode == SPUR_ENABLE_IOCTL) {4352for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {4353AH9300(ah)->ath_hal_spur_chans[i][0] = AR_NO_SPUR;4354AH9300(ah)->ath_hal_spur_chans[i][1] = AR_NO_SPUR;4355}4356for (i = 0, j = 0, k = 0; i < len; i++) {4357if (freq[i] > ATH_HAL_2GHZ_FREQ_MIN &&4358freq[i] < ATH_HAL_2GHZ_FREQ_MAX)4359{4360/* 2GHz Spur */4361if (j < AR_EEPROM_MODAL_SPURS) {4362AH9300(ah)->ath_hal_spur_chans[j++][1] = freq[i];4363HALDEBUG(ah, HAL_DEBUG_ANI, "1 set spur %d\n", freq[i]);4364}4365} else if (freq[i] > ATH_HAL_5GHZ_FREQ_MIN &&4366freq[i] < ATH_HAL_5GHZ_FREQ_MAX)4367{4368/* 5Ghz Spur */4369if (k < AR_EEPROM_MODAL_SPURS) {4370AH9300(ah)->ath_hal_spur_chans[k++][0] = freq[i];4371HALDEBUG(ah, HAL_DEBUG_ANI, "2 set spur %d\n", freq[i]);4372}4373}4374}4375}43764377return 0;4378}4379#endif43804381#define ar9300_check_op_mode(_opmode) \4382((_opmode == HAL_M_STA) || (_opmode == HAL_M_IBSS) ||\4383(_opmode == HAL_M_HOSTAP) || (_opmode == HAL_M_MONITOR))43844385438643874388#ifndef ATH_NF_PER_CHAN4389/*4390* To fixed first reset noise floor value not correct issue4391* For ART need it to fixed low rate sens too low issue4392*/4393static int4394First_NFCal(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan,4395int is_scan, struct ieee80211_channel *chan)4396{4397HAL_NFCAL_HIST_FULL *nfh;4398int i, j, k;4399int16_t nfarray[HAL_NUM_NF_READINGS] = {0};4400int is_2g = 0;4401int nf_hist_len;4402int stats = 0;44034404int16_t nf_buf[HAL_NUM_NF_READINGS];4405#define IS(_c, _f) (((_c)->channel_flags & _f) || 0)440644074408if ((!is_scan) &&4409chan->ic_freq == AH_PRIVATE(ah)->ah_curchan->ic_freq)4410{4411nfh = &AH_PRIVATE(ah)->nf_cal_hist;4412} else {4413nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;4414}44154416ar9300_start_nf_cal(ah);4417for (j = 0; j < 10000; j++) {4418if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){4419break;4420}4421OS_DELAY(10);4422}4423if (j < 10000) {4424is_2g = IEEE80211_IS_CHAN_2GHZ(chan);4425ar9300_upload_noise_floor(ah, is_2g, nfarray);44264427if (is_scan) {4428/*4429* This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct4430* rather than a HAL_NFCAL_HIST_FULL struct.4431* As long as we only use the first history element of nf_cal_buffer4432* (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use4433* HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably.4434*/4435nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist;4436nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL;4437} else {4438nfh = &AH_PRIVATE(ah)->nf_cal_hist;4439nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL;4440}44414442for (i = 0; i < HAL_NUM_NF_READINGS; i ++) {4443for (k = 0; k < HAL_NF_CAL_HIST_LEN_FULL; k++) {4444nfh->nf_cal_buffer[k][i] = nfarray[i];4445}4446nfh->base.priv_nf[i] = ar9300_limit_nf_range(ah,4447ar9300_get_nf_hist_mid(ah, nfh, i, nf_hist_len));4448}444944504451//ar9300StoreNewNf(ah, ichan, is_scan);44524453/*4454* See if the NF value from the old channel should be4455* retained when switching to a new channel.4456* TBD: this may need to be changed, as it wipes out the4457* purpose of saving NF values for each channel.4458*/4459for (i = 0; i < HAL_NUM_NF_READINGS; i++)4460{4461if (IEEE80211_IS_CHAN_2GHZ(chan))4462{4463if (nfh->nf_cal_buffer[0][i] <4464AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ)4465{4466ichan->nf_cal_hist.nf_cal_buffer[0][i] =4467AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];4468}4469} else {4470if (AR_SREV_AR9580(ah)) {4471if (nfh->nf_cal_buffer[0][i] <4472AR_PHY_CCA_NOM_VAL_PEACOCK_5GHZ)4473{4474ichan->nf_cal_hist.nf_cal_buffer[0][i] =4475AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];4476}4477} else {4478if (nfh->nf_cal_buffer[0][i] <4479AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ)4480{4481ichan->nf_cal_hist.nf_cal_buffer[0][i] =4482AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i];4483}4484}4485}4486}4487/*4488* Copy the channel's NF buffer, which may have been modified4489* just above here, to the full NF history buffer.4490*/4491ar9300_reset_nf_hist_buff(ah, ichan);4492ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);4493ar9300_load_nf(ah, nf_buf);4494/* XXX TODO: handle failure from load_nf */4495stats = 0;4496} else {4497stats = 1;4498}4499#undef IS4500return stats;4501}4502#endif450345044505/*4506* Places the device in and out of reset and then places sane4507* values in the registers based on EEPROM config, initialization4508* vectors (as determined by the mode), and station configuration4509*4510* b_channel_change is used to preserve DMA/PCU registers across4511* a HW Reset during channel change.4512*/4513HAL_BOOL4514ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan,4515HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask,4516HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change,4517HAL_STATUS *status, HAL_RESET_TYPE reset_type, int is_scan)4518{4519#define FAIL(_code) do { ecode = _code; goto bad; } while (0)4520u_int32_t save_led_state;4521struct ath_hal_9300 *ahp = AH9300(ah);4522struct ath_hal_private *ap = AH_PRIVATE(ah);4523HAL_CHANNEL_INTERNAL *ichan;4524//const struct ieee80211_channel *curchan = ap->ah_curchan;4525#if ATH_SUPPORT_MCI4526HAL_BOOL save_full_sleep = ahp->ah_chip_full_sleep;4527#endif4528u_int32_t save_def_antenna;4529u_int32_t mac_sta_id1;4530HAL_STATUS ecode;4531int i, rx_chainmask;4532int nf_hist_buff_reset = 0;4533int16_t nf_buf[HAL_NUM_NF_READINGS];4534#ifdef ATH_FORCE_PPM4535u_int32_t save_force_val, tmp_reg;4536#endif4537u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz;4538HAL_BOOL stopped, cal_ret;4539HAL_BOOL apply_last_iqcorr = AH_FALSE;4540uint64_t tsf;45414542if (OS_REG_READ(ah, AR_IER) == AR_IER_ENABLE) {4543HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "** Reset called with WLAN "4544"interrupt enabled %08x **\n", ar9300_get_interrupts(ah));4545}45464547/*4548* Set the status to "ok" by default to cover the cases4549* where we return false without going to "bad"4550*/4551HALASSERT(status);4552*status = HAL_OK;4553if ((ah->ah_config.ath_hal_sta_update_tx_pwr_enable)) {4554AH9300(ah)->green_tx_status = HAL_RSSI_TX_POWER_NONE;4555}45564557#if ATH_SUPPORT_MCI4558if (AH_PRIVATE(ah)->ah_caps.halMciSupport &&4559(AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)))4560{4561ar9300_mci_2g5g_changed(ah, IEEE80211_IS_CHAN_2GHZ(chan));4562}4563#endif45644565ahp->ah_ext_prot_spacing = extprotspacing;4566ahp->ah_tx_chainmask = txchainmask & ap->ah_caps.halTxChainMask;4567ahp->ah_rx_chainmask = rxchainmask & ap->ah_caps.halRxChainMask;4568ahp->ah_tx_cal_chainmask = ap->ah_caps.halTxChainMask;4569ahp->ah_rx_cal_chainmask = ap->ah_caps.halRxChainMask;45704571/*4572* Keep the previous optinal txchainmask value4573*/45744575HALASSERT(ar9300_check_op_mode(opmode));45764577OS_MARK(ah, AH_MARK_RESET, b_channel_change);45784579/*4580* Map public channel to private.4581*/4582ichan = ar9300_check_chan(ah, chan);4583if (ichan == AH_NULL) {4584HALDEBUG(ah, HAL_DEBUG_CHANNEL,4585"%s: invalid channel %u/0x%x; no mapping\n",4586__func__, chan->ic_freq, chan->ic_flags);4587FAIL(HAL_EINVAL);4588}45894590ichan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */4591#if 04592chan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */4593#endif45944595if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) {4596/* Need to stop RX DMA before reset otherwise chip might hang */4597stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */4598ar9300_set_rx_filter(ah, 0);4599stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */4600if (!stopped) {4601/*4602* During the transition from full sleep to reset,4603* recv DMA regs are not available to be read4604*/4605HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,4606"%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__);4607b_channel_change = AH_FALSE;4608}4609} else {4610HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,4611"%s[%d]: Chip is already in full sleep\n", __func__, __LINE__);4612}46134614#if ATH_SUPPORT_MCI4615if ((AH_PRIVATE(ah)->ah_caps.halMciSupport) &&4616(ahp->ah_mci_bt_state == MCI_BT_CAL_START))4617{4618u_int32_t payload[4] = {0, 0, 0, 0};46194620HALDEBUG(ah, HAL_DEBUG_BT_COEX,4621"(MCI) %s: Stop rx for BT cal.\n", __func__);4622ahp->ah_mci_bt_state = MCI_BT_CAL;46234624/*4625* MCIFIX: disable mci interrupt here. This is to avoid SW_MSG_DONE or4626* RX_MSG bits to trigger MCI_INT and lead to mci_intr reentry.4627*/4628ar9300_mci_disable_interrupt(ah);46294630HALDEBUG(ah, HAL_DEBUG_BT_COEX,4631"(MCI) %s: Send WLAN_CAL_GRANT\n", __func__);4632MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);4633ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE);46344635/* Wait BT calibration to be completed for 25ms */4636HALDEBUG(ah, HAL_DEBUG_BT_COEX,4637"(MCI) %s: BT is calibrating.\n", __func__);4638if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) {4639HALDEBUG(ah, HAL_DEBUG_BT_COEX,4640"(MCI) %s: Got BT_CAL_DONE.\n", __func__);4641}4642else {4643HALDEBUG(ah, HAL_DEBUG_BT_COEX,4644"(MCI) %s: ### BT cal takes too long. Force bt_state to be bt_awake.\n",4645__func__);4646}4647ahp->ah_mci_bt_state = MCI_BT_AWAKE;4648/* MCIFIX: enable mci interrupt here */4649ar9300_mci_enable_interrupt(ah);46504651return AH_TRUE;4652}4653#endif46544655/* Bring out of sleep mode */4656if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) {4657*status = HAL_INV_PMODE;4658return AH_FALSE;4659}46604661/* Check the Rx mitigation config again, it might have changed4662* during attach in ath_vap_attach.4663*/4664if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) {4665ahp->ah_intr_mitigation_rx = AH_TRUE;4666} else {4667ahp->ah_intr_mitigation_rx = AH_FALSE;4668}46694670/*4671* XXX TODO FreeBSD:4672*4673* This is painful because we don't have a non-const channel pointer4674* at this stage.4675*4676* Make sure this gets fixed!4677*/4678#if 04679/* Get the value from the previous NF cal and update history buffer */4680if (curchan && (ahp->ah_chip_full_sleep != AH_TRUE)) {46814682if(ahp->ah_chip_reset_done){4683ahp->ah_chip_reset_done = 0;4684} else {4685/*4686* is_scan controls updating NF for home channel or off channel.4687* Home -> Off, update home channel4688* Off -> Home, update off channel4689* Home -> Home, uppdate home channel4690*/4691if (ap->ah_curchan->channel != chan->channel)4692ar9300_store_new_nf(ah, curchan, !is_scan);4693else4694ar9300_store_new_nf(ah, curchan, is_scan);4695}4696}4697#endif46984699/*4700* Account for the effect of being in either the 2 GHz or 5 GHz band4701* on the nominal, max allowable, and min allowable noise floor values.4702*/4703AH9300(ah)->nfp = IS_CHAN_2GHZ(ichan) ? &ahp->nf_2GHz : &ahp->nf_5GHz;47044705/*4706* XXX FreeBSD For now, don't apply the last IQ correction.4707*4708* This should be done when scorpion is enabled on FreeBSD; just be4709* sure to fix this channel match code so it uses net80211 flags4710* instead.4711*/4712#if 04713if (AR_SREV_SCORPION(ah) && curchan && (chan->channel == curchan->channel) &&4714((chan->channel_flags & (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)) ==4715(curchan->channel_flags &4716(CHANNEL_ALL | CHANNEL_HALF | CHANNEL_QUARTER)))) {4717apply_last_iqcorr = AH_TRUE;4718}4719#endif4720apply_last_iqcorr = AH_FALSE;472147224723#ifndef ATH_NF_PER_CHAN4724/*4725* If there's only one full-size home-channel NF history buffer4726* rather than a full-size NF history buffer per channel, decide4727* whether to (re)initialize the home-channel NF buffer.4728* If this is just a channel change for a scan, or if the channel4729* is not being changed, don't mess up the home channel NF history4730* buffer with NF values from this scanned channel. If we're4731* changing the home channel to a new channel, reset the home-channel4732* NF history buffer with the most accurate NF known for the new channel.4733*/4734if (!is_scan && (!ap->ah_curchan ||4735ap->ah_curchan->ic_freq != chan->ic_freq)) // ||4736// ap->ah_curchan->channel_flags != chan->channel_flags))4737{4738nf_hist_buff_reset = 1;4739ar9300_reset_nf_hist_buff(ah, ichan);4740}4741#endif4742/*4743* In case of4744* - offchan scan, or4745* - same channel and RX IQ Cal already available4746* disable RX IQ Cal.4747*/4748if (is_scan) {4749ahp->ah_skip_rx_iq_cal = AH_TRUE;4750HALDEBUG(ah, HAL_DEBUG_CALIBRATE,4751"Skip RX IQ Cal due to scanning\n");4752} else {4753#if 04754/* XXX FreeBSD: always just do the RX IQ cal */4755/* XXX I think it's just going to speed things up; I don't think it's to avoid chan bugs */4756if (ahp->ah_rx_cal_complete &&4757ahp->ah_rx_cal_chan == ichan->channel &&4758ahp->ah_rx_cal_chan_flag == chan->channel_flags) {4759ahp->ah_skip_rx_iq_cal = AH_TRUE;4760HALDEBUG(ah, HAL_DEBUG_CALIBRATE,4761"Skip RX IQ Cal due to same channel with completed RX IQ Cal\n");4762} else4763#endif4764ahp->ah_skip_rx_iq_cal = AH_FALSE;4765}47664767/* FreeBSD: clear the channel survey data */4768ath_hal_survey_clear(ah);47694770/*4771* Fast channel change (Change synthesizer based on channel freq4772* without resetting chip)4773* Don't do it when4774* - Flag is not set4775* - Chip is just coming out of full sleep4776* - Channel to be set is same as current channel4777* - Channel flags are different, like when moving from 2GHz to 5GHz4778* channels4779* - Merlin: Switching in/out of fast clock enabled channels4780* (not currently coded, since fast clock is enabled4781* across the 5GHz band4782* and we already do a full reset when switching in/out4783* of 5GHz channels)4784*/4785#if 04786if (b_channel_change &&4787(ahp->ah_chip_full_sleep != AH_TRUE) &&4788(AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&4789((chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) &&4790(((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & chan->channel_flags) ==4791((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & AH_PRIVATE(ah)->ah_curchan->channel_flags))))4792{4793if (ar9300_channel_change(ah, chan, ichan, macmode)) {4794chan->channel_flags = ichan->channel_flags;4795chan->priv_flags = ichan->priv_flags;4796AH_PRIVATE(ah)->ah_curchan->ah_channel_time = 0;4797AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar9300_get_tsf64(ah);47984799/*4800* Load the NF from history buffer of the current channel.4801* NF is slow time-variant, so it is OK to use a historical value.4802*/4803ar9300_get_nf_hist_base(ah,4804AH_PRIVATE(ah)->ah_curchan, is_scan, nf_buf);4805ar9300_load_nf(ah, nf_buf);48064807/* start NF calibration, without updating BB NF register*/4808ar9300_start_nf_cal(ah);48094810/*4811* If channel_change completed and DMA was stopped4812* successfully - skip the rest of reset4813*/4814if (AH9300(ah)->ah_dma_stuck != AH_TRUE) {4815ar9300_disable_pll_lock_detect(ah);4816#if ATH_SUPPORT_MCI4817if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready)4818{4819ar9300_mci_2g5g_switch(ah, AH_TRUE);4820}4821#endif4822return HAL_OK;4823}4824}4825}4826#endif /* #if 0 */48274828#if ATH_SUPPORT_MCI4829if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {4830ar9300_mci_disable_interrupt(ah);4831if (ahp->ah_mci_ready && !save_full_sleep) {4832ar9300_mci_mute_bt(ah);4833OS_DELAY(20);4834OS_REG_WRITE(ah, AR_BTCOEX_CTRL, 0);4835}48364837ahp->ah_mci_bt_state = MCI_BT_SLEEP;4838ahp->ah_mci_ready = AH_FALSE;4839}4840#endif48414842AH9300(ah)->ah_dma_stuck = AH_FALSE;4843#ifdef ATH_FORCE_PPM4844/* Preserve force ppm state */4845save_force_val =4846OS_REG_READ(ah, AR_PHY_TIMING2) &4847(AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL);4848#endif4849/*4850* Preserve the antenna on a channel change4851*/4852save_def_antenna = OS_REG_READ(ah, AR_DEF_ANTENNA);4853if (0 == ahp->ah_smartantenna_enable )4854{4855if (save_def_antenna == 0) {4856save_def_antenna = 1;4857}4858}48594860/* Save hardware flag before chip reset clears the register */4861mac_sta_id1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;48624863/* Save led state from pci config register */4864save_led_state = OS_REG_READ(ah, AR_CFG_LED) &4865(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |4866AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW);48674868/* Mark PHY inactive prior to reset, to be undone in ar9300_init_bb () */4869ar9300_mark_phy_inactive(ah);48704871/* Save/restore TSF across a potentially full reset */4872/* XXX TODO: only do this if we do a cold reset */4873tsf = ar9300_get_tsf64(ah);4874if (!ar9300_chip_reset(ah, chan, reset_type)) {4875HALDEBUG(ah, HAL_DEBUG_RESET, "%s: chip reset failed\n", __func__);4876FAIL(HAL_EIO);4877}4878if (tsf != 0)4879ar9300_set_tsf64(ah, tsf);48804881OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);488248834884/* Disable JTAG */4885OS_REG_SET_BIT(ah,4886AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE);48874888/*4889* Note that ar9300_init_chain_masks() is called from within4890* ar9300_process_ini() to ensure the swap bit is set before4891* the pdadc table is written.4892*/4893ecode = ar9300_process_ini(ah, chan, ichan, macmode);4894if (ecode != HAL_OK) {4895goto bad;4896}48974898/*4899* Configuring WMAC PLL values for 25/40 MHz4900*/4901if(AR_SREV_WASP(ah) || AR_SREV_HONEYBEE(ah) || AR_SREV_SCORPION(ah) ) {4902if(clk_25mhz) {4903OS_REG_WRITE(ah, AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); // 32KHz sleep clk4904} else {4905OS_REG_WRITE(ah, AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); // 32KHz sleep clk4906}4907OS_DELAY(100);4908}49094910ahp->ah_immunity_on = AH_FALSE;49114912if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {4913ahp->tx_iq_cal_enable = OS_REG_READ_FIELD(ah,4914AR_PHY_TX_IQCAL_CONTROL_0(ah),4915AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL) ?49161 : 0;4917}4918ahp->tx_cl_cal_enable = (OS_REG_READ(ah, AR_PHY_CL_CAL_CTL) &4919AR_PHY_CL_CAL_ENABLE) ? 1 : 0;49204921/* For devices with full HW RIFS Rx support (Sowl/Howl/Merlin, etc),4922* restore register settings from prior to reset.4923*/4924if ((AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&4925(ar9300_get_capability(ah, HAL_CAP_LDPCWAR, 0, AH_NULL) == HAL_OK))4926{4927/* Re-program RIFS Rx policy after reset */4928ar9300_set_rifs_delay(ah, ahp->ah_rifs_enabled);4929}49304931#if ATH_SUPPORT_MCI4932if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {4933ar9300_mci_reset(ah, AH_FALSE, IS_CHAN_2GHZ(ichan), save_full_sleep);4934}4935#endif49364937/* Initialize Management Frame Protection */4938ar9300_init_mfp(ah);49394940ahp->ah_immunity_vals[0] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,4941AR_PHY_SFCORR_LOW_M1_THRESH_LOW);4942ahp->ah_immunity_vals[1] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,4943AR_PHY_SFCORR_LOW_M2_THRESH_LOW);4944ahp->ah_immunity_vals[2] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,4945AR_PHY_SFCORR_M1_THRESH);4946ahp->ah_immunity_vals[3] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,4947AR_PHY_SFCORR_M2_THRESH);4948ahp->ah_immunity_vals[4] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR,4949AR_PHY_SFCORR_M2COUNT_THR);4950ahp->ah_immunity_vals[5] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW,4951AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);49524953/* Write delta slope for OFDM enabled modes (A, G, Turbo) */4954if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) {4955ar9300_set_delta_slope(ah, chan);4956}49574958ar9300_spur_mitigate(ah, chan);4959if (!ar9300_eeprom_set_board_values(ah, chan)) {4960HALDEBUG(ah, HAL_DEBUG_EEPROM,4961"%s: error setting board options\n", __func__);4962FAIL(HAL_EIO);4963}49644965#ifdef ATH_HAL_WAR_REG16284_APH1284966/* temp work around, will be removed. */4967if (AR_SREV_WASP(ah)) {4968OS_REG_WRITE(ah, 0x16284, 0x1553e000);4969}4970#endif49714972OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);49734974OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));4975OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)4976| mac_sta_id14977| AR_STA_ID1_RTS_USE_DEF4978| (ah->ah_config.ath_hal_6mb_ack ? AR_STA_ID1_ACKCTS_6MB : 0)4979| ahp->ah_sta_id1_defaults4980);4981ar9300_set_operating_mode(ah, opmode);49824983/* Set Venice BSSID mask according to current state */4984OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssid_mask));4985OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssid_mask + 4));49864987/* Restore previous antenna */4988OS_REG_WRITE(ah, AR_DEF_ANTENNA, save_def_antenna);4989#ifdef ATH_FORCE_PPM4990/* Restore force ppm state */4991tmp_reg = OS_REG_READ(ah, AR_PHY_TIMING2) &4992~(AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL);4993OS_REG_WRITE(ah, AR_PHY_TIMING2, tmp_reg | save_force_val);4994#endif49954996/* then our BSSID and assocID */4997OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));4998OS_REG_WRITE(ah, AR_BSS_ID1,4999LE_READ_2(ahp->ah_bssid + 4) |5000((ahp->ah_assoc_id & 0x3fff) << AR_BSS_ID1_AID_S));50015002OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */50035004OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR);50055006/* HW beacon processing */5007/*5008* XXX what happens if I just leave filter_interval=0?5009* it stays disabled?5010*/5011OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_BCN_WEIGHT,5012INIT_RSSI_BEACON_WEIGHT);5013OS_REG_SET_BIT(ah, AR_HWBCNPROC1, AR_HWBCNPROC1_CRC_ENABLE |5014AR_HWBCNPROC1_EXCLUDE_TIM_ELM);5015if (ah->ah_config.ath_hal_beacon_filter_interval) {5016OS_REG_RMW_FIELD(ah, AR_HWBCNPROC2, AR_HWBCNPROC2_FILTER_INTERVAL,5017ah->ah_config.ath_hal_beacon_filter_interval);5018OS_REG_SET_BIT(ah, AR_HWBCNPROC2,5019AR_HWBCNPROC2_FILTER_INTERVAL_ENABLE);5020}502150225023/*5024* Set Channel now modifies bank 6 parameters for FOWL workaround5025* to force rf_pwd_icsyndiv bias current as function of synth5026* frequency.Thus must be called after ar9300_process_ini() to ensure5027* analog register cache is valid.5028*/5029if (!ahp->ah_rf_hal.set_channel(ah, chan)) {5030FAIL(HAL_EIO);5031}503250335034OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);50355036/* Set 1:1 QCU to DCU mapping for all queues */5037for (i = 0; i < AR_NUM_DCU; i++) {5038OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);5039}50405041ahp->ah_intr_txqs = 0;5042for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) {5043ar9300_reset_tx_queue(ah, i);5044}50455046ar9300_init_interrupt_masks(ah, opmode);50475048/* Reset ier reference count to disabled */5049// OS_ATOMIC_SET(&ahp->ah_ier_ref_count, 1);5050if (ath_hal_isrfkillenabled(ah)) {5051ar9300_enable_rf_kill(ah);5052}50535054/* must be called AFTER ini is processed */5055ar9300_ani_init_defaults(ah, macmode);50565057ar9300_init_qos(ah);50585059ar9300_init_user_settings(ah);506050615062AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */50635064OS_MARK(ah, AH_MARK_RESET_DONE, 0);50655066/*5067* disable seq number generation in hw5068*/5069OS_REG_WRITE(ah, AR_STA_ID1,5070OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);50715072ar9300_set_dma(ah);50735074/*5075* program OBS bus to see MAC interrupts5076*/5077#if ATH_SUPPORT_MCI5078if (!AH_PRIVATE(ah)->ah_caps.halMciSupport) {5079OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8);5080}5081#else5082OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8);5083#endif508450855086/* enabling AR_GTTM_IGNORE_IDLE in GTTM register so that5087GTT timer will not increment if the channel idle indicates5088the air is busy or NAV is still counting down */5089OS_REG_WRITE(ah, AR_GTTM, AR_GTTM_IGNORE_IDLE);50905091/*5092* GTT debug mode setting5093*/5094/*5095OS_REG_WRITE(ah, 0x64, 0x00320000);5096OS_REG_WRITE(ah, 0x68, 7);5097OS_REG_WRITE(ah, 0x4080, 0xC);5098*/5099/*5100* Disable general interrupt mitigation by setting MIRT = 0x05101* Rx and tx interrupt mitigation are conditionally enabled below.5102*/5103OS_REG_WRITE(ah, AR_MIRT, 0);5104if (ahp->ah_intr_mitigation_rx) {5105/*5106* Enable Interrupt Mitigation for Rx.5107* If no build-specific limits for the rx interrupt mitigation5108* timer have been specified, use conservative defaults.5109*/5110#ifndef AH_RIMT_VAL_LAST5111#define AH_RIMT_LAST_MICROSEC 5005112#endif5113#ifndef AH_RIMT_VAL_FIRST5114#define AH_RIMT_FIRST_MICROSEC 20005115#endif5116#ifndef HOST_OFFLOAD5117OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, AH_RIMT_LAST_MICROSEC);5118OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, AH_RIMT_FIRST_MICROSEC);5119#else5120/* lower mitigation level to reduce latency for offload arch. */5121OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST,5122(AH_RIMT_LAST_MICROSEC >> 2));5123OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST,5124(AH_RIMT_FIRST_MICROSEC >> 2));5125#endif5126}51275128if (ahp->ah_intr_mitigation_tx) {5129/*5130* Enable Interrupt Mitigation for Tx.5131* If no build-specific limits for the tx interrupt mitigation5132* timer have been specified, use the values preferred for5133* the carrier group's products.5134*/5135#ifndef AH_TIMT_LAST5136#define AH_TIMT_LAST_MICROSEC 3005137#endif5138#ifndef AH_TIMT_FIRST5139#define AH_TIMT_FIRST_MICROSEC 7505140#endif5141OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, AH_TIMT_LAST_MICROSEC);5142OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, AH_TIMT_FIRST_MICROSEC);5143}51445145rx_chainmask = ahp->ah_rx_chainmask;51465147OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);5148OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);51495150ar9300_init_bb(ah, chan);51515152/* BB Step 7: Calibration */5153/*5154* Only kick off calibration not on offchan.5155* If coming back from offchan, restore prevous Cal results5156* since chip reset will clear existings.5157*/5158if (!ahp->ah_skip_rx_iq_cal) {5159int i;5160/* clear existing RX cal data */5161for (i=0; i<AR9300_MAX_CHAINS; i++)5162ahp->ah_rx_cal_corr[i] = 0;51635164ahp->ah_rx_cal_complete = AH_FALSE;5165// ahp->ah_rx_cal_chan = chan->channel;5166// ahp->ah_rx_cal_chan_flag = ichan->channel_flags;5167ahp->ah_rx_cal_chan = 0;5168ahp->ah_rx_cal_chan_flag = 0; /* XXX FreeBSD */5169}5170ar9300_invalidate_saved_cals(ah, ichan);5171cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr);51725173#if ATH_SUPPORT_MCI5174if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) {5175if (IS_CHAN_2GHZ(ichan) &&5176(ahp->ah_mci_bt_state == MCI_BT_SLEEP))5177{5178if (ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||5179ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))5180{5181/*5182* BT is sleeping. Check if BT wakes up duing WLAN5183* calibration. If BT wakes up during WLAN calibration, need5184* to go through all message exchanges again and recal.5185*/5186HALDEBUG(ah, HAL_DEBUG_BT_COEX,5187"(MCI) ### %s: BT wakes up during WLAN calibration.\n",5188__func__);5189OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,5190AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |5191AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);5192HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) send REMOTE_RESET\n");5193ar9300_mci_remote_reset(ah, AH_TRUE);5194ar9300_mci_send_sys_waking(ah, AH_TRUE);5195OS_DELAY(1);5196if (IS_CHAN_2GHZ(ichan)) {5197ar9300_mci_send_lna_transfer(ah, AH_TRUE);5198}5199ahp->ah_mci_bt_state = MCI_BT_AWAKE;52005201/* Redo calibration */5202HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Re-calibrate.\n",5203__func__);5204ar9300_invalidate_saved_cals(ah, ichan);5205cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr);5206}5207}5208ar9300_mci_enable_interrupt(ah);5209}5210#endif52115212if (!cal_ret) {5213HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Init Cal Failed\n", __func__);5214FAIL(HAL_ESELFTEST);5215}52165217ar9300_init_txbf(ah);5218#if 05219/*5220* WAR for owl 1.0 - restore chain mask for 2-chain cfgs after cal5221*/5222rx_chainmask = ahp->ah_rx_chainmask;5223if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {5224OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);5225OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);5226}5227#endif52285229/* Restore previous led state */5230OS_REG_WRITE(ah, AR_CFG_LED, save_led_state | AR_CFG_SCLK_32KHZ);52315232#if ATH_BT_COEX5233if (ahp->ah_bt_coex_config_type != HAL_BT_COEX_CFG_NONE) {5234ar9300_init_bt_coex(ah);52355236#if ATH_SUPPORT_MCI5237if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) {5238/* Check BT state again to make sure it's not changed. */5239ar9300_mci_sync_bt_state(ah);5240ar9300_mci_2g5g_switch(ah, AH_TRUE);52415242if ((ahp->ah_mci_bt_state == MCI_BT_AWAKE) &&5243(ahp->ah_mci_query_bt == AH_TRUE))5244{5245ahp->ah_mci_need_flush_btinfo = AH_TRUE;5246}5247}5248#endif5249}5250#endif52515252/* Start TSF2 for generic timer 8-15. */5253ar9300_start_tsf2(ah);52545255/* MIMO Power save setting */5256if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) == HAL_OK) {5257ar9300_set_sm_power_mode(ah, ahp->ah_sm_power_mode);5258}52595260/*5261* For big endian systems turn on swapping for descriptors5262*/5263#if AH_BYTE_ORDER == AH_BIG_ENDIAN5264if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {5265OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB, 0);5266} else {5267ar9300_init_cfg_reg(ah);5268}5269#endif52705271if ( AR_SREV_OSPREY(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah) ) {5272OS_REG_RMW(ah, AR_CFG_LED, AR_CFG_LED_ASSOC_CTL, AR_CFG_LED_ASSOC_CTL);5273}52745275#if !(defined(ART_BUILD)) && defined(ATH_SUPPORT_LED)5276#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val);5277#define REG_READ(_reg) *((volatile u_int32_t *)(_reg))5278#define ATH_GPIO_OUT_FUNCTION3 0xB80400385279#define ATH_GPIO_OE 0xB80400005280if ( AR_SREV_WASP(ah)) {5281if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {5282REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x33 << 8) );5283REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )));5284}5285else {52865287/* Disable 2G WLAN LED. During ath_open, reset function is called even before channel is set.5288So 2GHz is taken as default and it also blinks. Hence5289to avoid both from blinking, disable 2G led while in 5G mode */52905291REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) | (1 << 13) ));5292REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x33) );5293REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )));5294}52955296}5297else if (AR_SREV_SCORPION(ah)) {5298if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) {5299REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x2F << 8) );5300REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )) | (0x1 << 12)));5301} else if (IS_CHAN_5GHZ((AH_PRIVATE(ah)->ah_curchan))) {5302REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x2F) );5303REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )) | (0x1 << 13)));5304}5305}5306else if (AR_SREV_HONEYBEE(ah)) {5307REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x32) );5308REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) ))));5309}5310#undef REG_READ5311#undef REG_WRITE5312#endif53135314/* XXX FreeBSD What's this? -adrian */5315#if 05316chan->channel_flags = ichan->channel_flags;5317chan->priv_flags = ichan->priv_flags;5318#endif53195320#if FIX_NOISE_FLOOR5321/* XXX FreeBSD is ichan appropariate? It was curchan.. */5322ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf);5323ar9300_load_nf(ah, nf_buf);5324/* XXX TODO: handle NF load failure */5325if (nf_hist_buff_reset == 1)5326{5327nf_hist_buff_reset = 0;5328#ifndef ATH_NF_PER_CHAN5329if (First_NFCal(ah, ichan, is_scan, chan)){5330if (ahp->ah_skip_rx_iq_cal && !is_scan) {5331/* restore RX Cal result if existing */5332ar9300_rx_iq_cal_restore(ah);5333ahp->ah_skip_rx_iq_cal = AH_FALSE;5334}5335}5336#endif /* ATH_NF_PER_CHAN */5337}5338else{5339ar9300_start_nf_cal(ah);5340}5341#endif53425343#ifdef AH_SUPPORT_AR93005344/* BB Panic Watchdog */5345if (ar9300_get_capability(ah, HAL_CAP_BB_PANIC_WATCHDOG, 0, AH_NULL) ==5346HAL_OK)5347{5348ar9300_config_bb_panic_watchdog(ah);5349}5350#endif53515352/* While receiving unsupported rate frame receive state machine5353* gets into a state 0xb and if phy_restart happens when rx5354* state machine is in 0xb state, BB would go hang, if we5355* see 0xb state after first bb panic, make sure that we5356* disable the phy_restart.5357*5358* There may be multiple panics, make sure that we always do5359* this if we see this panic at least once. This is required5360* because reset seems to be writing from INI file.5361*/5362if ((ar9300_get_capability(ah, HAL_CAP_PHYRESTART_CLR_WAR, 0, AH_NULL)5363== HAL_OK) && (((MS((AH9300(ah)->ah_bb_panic_last_status),5364AR_PHY_BB_WD_RX_OFDM_SM)) == 0xb) ||5365AH9300(ah)->ah_phyrestart_disabled) )5366{5367ar9300_disable_phy_restart(ah, 1);5368}5369537053715372ahp->ah_radar1 = MS(OS_REG_READ(ah, AR_PHY_RADAR_1),5373AR_PHY_RADAR_1_CF_BIN_THRESH);5374ahp->ah_dc_offset = MS(OS_REG_READ(ah, AR_PHY_TIMING2),5375AR_PHY_TIMING2_DC_OFFSET);5376ahp->ah_disable_cck = MS(OS_REG_READ(ah, AR_PHY_MODE),5377AR_PHY_MODE_DISABLE_CCK);53785379if (AH9300(ah)->ah_enable_keysearch_always) {5380ar9300_enable_keysearch_always(ah, 1);5381}53825383#if ATH_LOW_POWER_ENABLE5384#define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val)5385#define REG_READ(_reg) *((volatile u_int32_t *)(_reg))5386if (AR_SREV_OSPREY(ah)) {5387REG_WRITE(0xb4000080, REG_READ(0xb4000080) | 3);5388OS_REG_WRITE(ah, AR_RTC_RESET, 1);5389OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL),5390AR_PCIE_PM_CTRL_ENA);5391OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_SPARE), 0xffffffff);5392}5393#undef REG_READ5394#undef REG_WRITE5395#endif /* ATH_LOW_POWER_ENABLE */53965397ar9300_disable_pll_lock_detect(ah);53985399/* H/W Green TX */5400ar9300_control_signals_for_green_tx_mode(ah);5401/* Smart Antenna, only for 5GHz on Scropion */5402if (IEEE80211_IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan)) && AR_SREV_SCORPION(ah)) {5403ahp->ah_smartantenna_enable = 0;5404}54055406ar9300_set_smart_antenna(ah, ahp->ah_smartantenna_enable);54075408if (AR_SREV_APHRODITE(ah) && ahp->ah_lna_div_use_bt_ant_enable)5409OS_REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);54105411if (ahp->ah_skip_rx_iq_cal && !is_scan) {5412/* restore RX Cal result if existing */5413ar9300_rx_iq_cal_restore(ah);5414ahp->ah_skip_rx_iq_cal = AH_FALSE;5415}541654175418return AH_TRUE;5419bad:5420OS_MARK(ah, AH_MARK_RESET_DONE, ecode);5421*status = ecode;54225423if (ahp->ah_skip_rx_iq_cal && !is_scan) {5424/* restore RX Cal result if existing */5425ar9300_rx_iq_cal_restore(ah);5426ahp->ah_skip_rx_iq_cal = AH_FALSE;5427}54285429return AH_FALSE;5430#undef FAIL5431}54325433void5434ar9300_green_ap_ps_on_off( struct ath_hal *ah, u_int16_t on_off)5435{5436/* Set/reset the ps flag */5437AH9300(ah)->green_ap_ps_on = !!on_off;5438}54395440/*5441* This function returns 1, where it is possible to do5442* single-chain power save.5443*/5444u_int16_t5445ar9300_is_single_ant_power_save_possible(struct ath_hal *ah)5446{5447return AH_TRUE;5448}54495450/* To avoid compilation warnings. Functions not used when EMULATION. */5451/*5452* ar9300_find_mag_approx()5453*/5454static int32_t5455ar9300_find_mag_approx(struct ath_hal *ah, int32_t in_re, int32_t in_im)5456{5457int32_t abs_i = abs(in_re);5458int32_t abs_q = abs(in_im);5459int32_t max_abs, min_abs;54605461if (abs_i > abs_q) {5462max_abs = abs_i;5463min_abs = abs_q;5464} else {5465max_abs = abs_q;5466min_abs = abs_i;5467}54685469return (max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4));5470}54715472/*5473* ar9300_solve_iq_cal()5474* solve 4x4 linear equation used in loopback iq cal.5475*/5476static HAL_BOOL5477ar9300_solve_iq_cal(5478struct ath_hal *ah,5479int32_t sin_2phi_1,5480int32_t cos_2phi_1,5481int32_t sin_2phi_2,5482int32_t cos_2phi_2,5483int32_t mag_a0_d0,5484int32_t phs_a0_d0,5485int32_t mag_a1_d0,5486int32_t phs_a1_d0,5487int32_t solved_eq[])5488{5489int32_t f1 = cos_2phi_1 - cos_2phi_2;5490int32_t f3 = sin_2phi_1 - sin_2phi_2;5491int32_t f2;5492int32_t mag_tx, phs_tx, mag_rx, phs_rx;5493const int32_t result_shift = 1 << 15;54945495f2 = (((int64_t)f1 * (int64_t)f1) / result_shift) + (((int64_t)f3 * (int64_t)f3) / result_shift);54965497if (0 == f2) {5498HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d).\n",5499__func__, __LINE__);5500return AH_FALSE;5501}55025503/* magnitude mismatch, tx */5504mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);5505/* phase mismatch, tx */5506phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);55075508mag_tx = (mag_tx / f2);5509phs_tx = (phs_tx / f2);55105511/* magnitude mismatch, rx */5512mag_rx =5513mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / result_shift;5514/* phase mismatch, rx */5515phs_rx =5516phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / result_shift;55175518solved_eq[0] = mag_tx;5519solved_eq[1] = phs_tx;5520solved_eq[2] = mag_rx;5521solved_eq[3] = phs_rx;55225523return AH_TRUE;5524}55255526/*5527* ar9300_calc_iq_corr()5528*/5529static HAL_BOOL5530ar9300_calc_iq_corr(struct ath_hal *ah, int32_t chain_idx,5531const int32_t iq_res[], int32_t iqc_coeff[])5532{5533int32_t i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0;5534int32_t i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1;5535int32_t i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0;5536int32_t i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;5537int32_t mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1;5538int32_t phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1;5539int32_t sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2;5540int32_t mag_tx, phs_tx, mag_rx, phs_rx;5541int32_t solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx;5542int32_t q_q_coff, q_i_coff;5543const int32_t res_scale = 1 << 15;5544const int32_t delpt_shift = 1 << 8;5545int32_t mag1, mag2;55465547i2_m_q2_a0_d0 = iq_res[0] & 0xfff;5548i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;5549iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);55505551if (i2_m_q2_a0_d0 > 0x800) {5552i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);5553}5554if (iq_corr_a0_d0 > 0x800) {5555iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);5556}55575558i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;5559i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);5560iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;55615562if (i2_m_q2_a0_d1 > 0x800) {5563i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);5564}5565if (iq_corr_a0_d1 > 0x800) {5566iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);5567}55685569i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);5570i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;5571iq_corr_a1_d0 = iq_res[4] & 0xfff;55725573if (i2_m_q2_a1_d0 > 0x800) {5574i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);5575}5576if (iq_corr_a1_d0 > 0x800) {5577iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);5578}55795580i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;5581i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);5582iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;55835584if (i2_m_q2_a1_d1 > 0x800) {5585i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);5586}5587if (iq_corr_a1_d1 > 0x800) {5588iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);5589}55905591if ((i2_p_q2_a0_d0 == 0) ||5592(i2_p_q2_a0_d1 == 0) ||5593(i2_p_q2_a1_d0 == 0) ||5594(i2_p_q2_a1_d1 == 0)) {5595HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5596"%s: Divide by 0(%d):\na0_d0=%d\na0_d1=%d\na2_d0=%d\na1_d1=%d\n",5597__func__, __LINE__,5598i2_p_q2_a0_d0, i2_p_q2_a0_d1, i2_p_q2_a1_d0, i2_p_q2_a1_d1);5599return AH_FALSE;5600}56015602if ((i2_p_q2_a0_d0 <= 1024) || (i2_p_q2_a0_d0 > 2047) ||5603(i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||5604(i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||5605(i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||5606(i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||5607(i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||5608(i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||5609(i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||5610(i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||5611(i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {5612return AH_FALSE;5613}56145615mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;5616phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;56175618mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;5619phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;56205621mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;5622phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;56235624mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;5625phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;56265627/* without analog phase shift */5628sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);5629/* without analog phase shift */5630cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);5631/* with analog phase shift */5632sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);5633/* with analog phase shift */5634cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);56355636/* force sin^2 + cos^2 = 1; */5637/* find magnitude by approximation */5638mag1 = ar9300_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);5639mag2 = ar9300_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);56405641if ((mag1 == 0) || (mag2 == 0)) {5642HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5643"%s: Divide by 0(%d): mag1=%d, mag2=%d\n",5644__func__, __LINE__, mag1, mag2);5645return AH_FALSE;5646}56475648/* normalization sin and cos by mag */5649sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);5650cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);5651sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);5652cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);56535654/* calculate IQ mismatch */5655if (AH_FALSE == ar9300_solve_iq_cal(ah,5656sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2, mag_a0_d0,5657phs_a0_d0, mag_a1_d0, phs_a1_d0, solved_eq))5658{5659HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5660"%s: Call to ar9300_solve_iq_cal failed.\n", __func__);5661return AH_FALSE;5662}56635664mag_tx = solved_eq[0];5665phs_tx = solved_eq[1];5666mag_rx = solved_eq[2];5667phs_rx = solved_eq[3];56685669HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5670"%s: chain %d: mag mismatch=%d phase mismatch=%d\n",5671__func__, chain_idx, mag_tx / res_scale, phs_tx / res_scale);56725673if (res_scale == mag_tx) {5674HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5675"%s: Divide by 0(%d): mag_tx=%d, res_scale=%d\n",5676__func__, __LINE__, mag_tx, res_scale);5677return AH_FALSE;5678}56795680/* calculate and quantize Tx IQ correction factor */5681mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);5682phs_corr_tx = -phs_tx;56835684q_q_coff = (mag_corr_tx * 128 / res_scale);5685q_i_coff = (phs_corr_tx * 256 / res_scale);56865687HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5688"%s: tx chain %d: mag corr=%d phase corr=%d\n",5689__func__, chain_idx, q_q_coff, q_i_coff);56905691if (q_i_coff < -63) {5692q_i_coff = -63;5693}5694if (q_i_coff > 63) {5695q_i_coff = 63;5696}5697if (q_q_coff < -63) {5698q_q_coff = -63;5699}5700if (q_q_coff > 63) {5701q_q_coff = 63;5702}57035704iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);57055706HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: tx chain %d: iq corr coeff=%x\n",5707__func__, chain_idx, iqc_coeff[0]);57085709if (-mag_rx == res_scale) {5710HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5711"%s: Divide by 0(%d): mag_rx=%d, res_scale=%d\n",5712__func__, __LINE__, mag_rx, res_scale);5713return AH_FALSE;5714}57155716/* calculate and quantize Rx IQ correction factors */5717mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);5718phs_corr_rx = -phs_rx;57195720q_q_coff = (mag_corr_rx * 128 / res_scale);5721q_i_coff = (phs_corr_rx * 256 / res_scale);57225723HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5724"%s: rx chain %d: mag corr=%d phase corr=%d\n",5725__func__, chain_idx, q_q_coff, q_i_coff);57265727if (q_i_coff < -63) {5728q_i_coff = -63;5729}5730if (q_i_coff > 63) {5731q_i_coff = 63;5732}5733if (q_q_coff < -63) {5734q_q_coff = -63;5735}5736if (q_q_coff > 63) {5737q_q_coff = 63;5738}57395740iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);57415742HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: rx chain %d: iq corr coeff=%x\n",5743__func__, chain_idx, iqc_coeff[1]);57445745return AH_TRUE;5746}57475748#define MAX_MAG_DELTA 11 //maximum magnitude mismatch delta across gains5749#define MAX_PHS_DELTA 10 //maximum phase mismatch delta across gains5750#define ABS(x) ((x) >= 0 ? (x) : (-(x)))57515752u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {5753{ AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,5754AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,5755AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},5756{ AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,5757AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,5758AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},5759{ AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,5760AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,5761AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},5762{ AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,5763AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,5764AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},5765{ AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,5766AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,5767AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},5768{ AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,5769AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,5770AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},5771{ AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,5772AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,5773AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},5774{ AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,5775AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,5776AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},5777};57785779static void5780ar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, u_int32_t num_chains,5781struct coeff_t *coeff, HAL_BOOL is_cal_reusable)5782{5783int nmeasurement, ch_idx, im;5784int32_t magnitude, phase;5785int32_t magnitude_max, phase_max;5786int32_t magnitude_min, phase_min;57875788int32_t magnitude_max_idx, phase_max_idx;5789int32_t magnitude_min_idx, phase_min_idx;57905791int32_t magnitude_avg, phase_avg;5792int32_t outlier_mag_idx = 0;5793int32_t outlier_phs_idx = 0;579457955796if (AR_SREV_POSEIDON(ah)) {5797HALASSERT(num_chains == 0x1);57985799tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;5800tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;5801tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;5802tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;5803tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;5804tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;5805tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;5806tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;5807}58085809for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {5810nmeasurement = OS_REG_READ_FIELD(ah,5811AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0);5812if (nmeasurement > MAX_MEASUREMENT) {5813nmeasurement = MAX_MEASUREMENT;5814}58155816if (!AR_SREV_SCORPION(ah)) {5817/*5818* reset max/min variable to min/max values so that5819* we always start with 1st calibrated gain value5820*/5821magnitude_max = -64;5822phase_max = -64;5823magnitude_min = 63;5824phase_min = 63;5825magnitude_avg = 0;5826phase_avg = 0;5827magnitude_max_idx = 0;5828magnitude_min_idx = 0;5829phase_max_idx = 0;5830phase_min_idx = 0;58315832/* detect outlier only if nmeasurement > 1 */5833if (nmeasurement > 1) {5834/* printf("----------- start outlier detection -----------\n"); */5835/*5836* find max/min and phase/mag mismatch across all calibrated gains5837*/5838for (im = 0; im < nmeasurement; im++) {5839magnitude = coeff->mag_coeff[ch_idx][im][0];5840phase = coeff->phs_coeff[ch_idx][im][0];58415842magnitude_avg = magnitude_avg + magnitude;5843phase_avg = phase_avg + phase;5844if (magnitude > magnitude_max) {5845magnitude_max = magnitude;5846magnitude_max_idx = im;5847}5848if (magnitude < magnitude_min) {5849magnitude_min = magnitude;5850magnitude_min_idx = im;5851}5852if (phase > phase_max) {5853phase_max = phase;5854phase_max_idx = im;5855}5856if (phase < phase_min) {5857phase_min = phase;5858phase_min_idx = im;5859}5860}5861/* find average (exclude max abs value) */5862for (im = 0; im < nmeasurement; im++) {5863magnitude = coeff->mag_coeff[ch_idx][im][0];5864phase = coeff->phs_coeff[ch_idx][im][0];5865if ((ABS(magnitude) < ABS(magnitude_max)) ||5866(ABS(magnitude) < ABS(magnitude_min)))5867{5868magnitude_avg = magnitude_avg + magnitude;5869}5870if ((ABS(phase) < ABS(phase_max)) ||5871(ABS(phase) < ABS(phase_min)))5872{5873phase_avg = phase_avg + phase;5874}5875}5876magnitude_avg = magnitude_avg / (nmeasurement - 1);5877phase_avg = phase_avg / (nmeasurement - 1);58785879/* detect magnitude outlier */5880if (ABS(magnitude_max - magnitude_min) > MAX_MAG_DELTA) {5881if (ABS(magnitude_max - magnitude_avg) >5882ABS(magnitude_min - magnitude_avg))5883{5884/* max is outlier, force to avg */5885outlier_mag_idx = magnitude_max_idx;5886} else {5887/* min is outlier, force to avg */5888outlier_mag_idx = magnitude_min_idx;5889}5890coeff->mag_coeff[ch_idx][outlier_mag_idx][0] = magnitude_avg;5891coeff->phs_coeff[ch_idx][outlier_mag_idx][0] = phase_avg;5892HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5893"[ch%d][outlier mag gain%d]:: "5894"mag_avg = %d (/128), phase_avg = %d (/256)\n",5895ch_idx, outlier_mag_idx, magnitude_avg, phase_avg);5896}5897/* detect phase outlier */5898if (ABS(phase_max - phase_min) > MAX_PHS_DELTA) {5899if (ABS(phase_max-phase_avg) > ABS(phase_min - phase_avg)) {5900/* max is outlier, force to avg */5901outlier_phs_idx = phase_max_idx;5902} else{5903/* min is outlier, force to avg */5904outlier_phs_idx = phase_min_idx;5905}5906coeff->mag_coeff[ch_idx][outlier_phs_idx][0] = magnitude_avg;5907coeff->phs_coeff[ch_idx][outlier_phs_idx][0] = phase_avg;5908HALDEBUG(ah, HAL_DEBUG_CALIBRATE,5909"[ch%d][outlier phs gain%d]:: "5910"mag_avg = %d (/128), phase_avg = %d (/256)\n",5911ch_idx, outlier_phs_idx, magnitude_avg, phase_avg);5912}5913}5914}59155916/*printf("------------ after outlier detection -------------\n");*/5917for (im = 0; im < nmeasurement; im++) {5918magnitude = coeff->mag_coeff[ch_idx][im][0];5919phase = coeff->phs_coeff[ch_idx][im][0];59205921#if 05922printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n",5923ch_idx, im, magnitude, phase);5924#endif59255926coeff->iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7);59275928if ((im % 2) == 0) {5929OS_REG_RMW_FIELD(ah,5930tx_corr_coeff[im][ch_idx],5931AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,5932coeff->iqc_coeff[0]);5933} else {5934OS_REG_RMW_FIELD(ah,5935tx_corr_coeff[im][ch_idx],5936AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,5937coeff->iqc_coeff[0]);5938}5939#if ATH_SUPPORT_CAL_REUSE5940ichan->tx_corr_coeff[im][ch_idx] = coeff->iqc_coeff[0];5941#endif5942}5943#if ATH_SUPPORT_CAL_REUSE5944ichan->num_measures[ch_idx] = nmeasurement;5945#endif5946}59475948OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,5949AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);5950OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,5951AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);59525953#if ATH_SUPPORT_CAL_REUSE5954if (is_cal_reusable) {5955ichan->one_time_txiqcal_done = AH_TRUE;5956HALDEBUG(ah, HAL_DEBUG_FCS_RTT,5957"(FCS) TXIQCAL saved - %d\n", ichan->channel);5958}5959#endif5960}59615962#if ATH_SUPPORT_CAL_REUSE5963static void5964ar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)5965{5966struct ath_hal_9300 *ahp = AH9300(ah);5967int nmeasurement, ch_idx, im;59685969u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {5970{ AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,5971AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,5972AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},5973{ AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,5974AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,5975AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},5976{ AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,5977AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,5978AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},5979{ AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,5980AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,5981AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},5982{ AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,5983AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,5984AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},5985{ AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,5986AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,5987AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},5988{ AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,5989AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,5990AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},5991{ AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,5992AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,5993AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},5994};59955996if (AR_SREV_POSEIDON(ah)) {5997HALASSERT(ahp->ah_tx_cal_chainmask == 0x1);59985999tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;6000tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON;6001tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;6002tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON;6003tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;6004tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON;6005tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;6006tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON;6007}60086009for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {6010if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) {6011continue;6012}6013nmeasurement = ichan->num_measures[ch_idx];60146015for (im = 0; im < nmeasurement; im++) {6016if ((im % 2) == 0) {6017OS_REG_RMW_FIELD(ah,6018tx_corr_coeff[im][ch_idx],6019AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,6020ichan->tx_corr_coeff[im][ch_idx]);6021} else {6022OS_REG_RMW_FIELD(ah,6023tx_corr_coeff[im][ch_idx],6024AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,6025ichan->tx_corr_coeff[im][ch_idx]);6026}6027}6028}60296030OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,6031AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);6032OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,6033AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);6034}6035#endif60366037/*6038* ar9300_tx_iq_cal_hw_run is only needed for osprey/wasp/hornet6039* It is not needed for jupiter/poseidon.6040*/6041HAL_BOOL6042ar9300_tx_iq_cal_hw_run(struct ath_hal *ah)6043{6044int is_tx_gain_forced;60456046is_tx_gain_forced = OS_REG_READ_FIELD(ah,6047AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE);6048if (is_tx_gain_forced) {6049/*printf("Tx gain can not be forced during tx I/Q cal!\n");*/6050OS_REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0);6051}60526053/* enable tx IQ cal */6054OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah),6055AR_PHY_TX_IQCAL_START_DO_CAL, AR_PHY_TX_IQCAL_START_DO_CAL);60566057if (!ath_hal_wait(ah,6058AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 0))6059{6060HALDEBUG(ah, HAL_DEBUG_CALIBRATE,6061"%s: Tx IQ Cal is never completed.\n", __func__);6062return AH_FALSE;6063}6064return AH_TRUE;6065}60666067static void6068ar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan,6069int iqcal_idx, int max_iqcal,HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr)6070{6071int nmeasurement=0, im, ix, iy, temp;6072struct ath_hal_9300 *ahp = AH9300(ah);6073u_int32_t txiqcal_status[AR9300_MAX_CHAINS] = {6074AR_PHY_TX_IQCAL_STATUS_B0(ah),6075AR_PHY_TX_IQCAL_STATUS_B1,6076AR_PHY_TX_IQCAL_STATUS_B2,6077};6078const u_int32_t chan_info_tab[] = {6079AR_PHY_CHAN_INFO_TAB_0,6080AR_PHY_CHAN_INFO_TAB_1,6081AR_PHY_CHAN_INFO_TAB_2,6082};6083int32_t iq_res[6];6084int32_t ch_idx, j;6085u_int32_t num_chains = 0;6086static struct coeff_t coeff;6087txiqcal_status[0] = AR_PHY_TX_IQCAL_STATUS_B0(ah);60886089for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) {6090if (ahp->ah_tx_chainmask & (1 << ch_idx)) {6091num_chains++;6092}6093}60946095if (apply_last_corr) {6096if (coeff.last_cal == AH_TRUE) {6097int32_t magnitude, phase;6098int ch_idx, im;6099u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = {6100{ AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,6101AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,6102AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},6103{ AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,6104AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,6105AR_PHY_TX_IQCAL_CORR_COEFF_01_B2},6106{ AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,6107AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,6108AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},6109{ AR_PHY_TX_IQCAL_CORR_COEFF_23_B0,6110AR_PHY_TX_IQCAL_CORR_COEFF_23_B1,6111AR_PHY_TX_IQCAL_CORR_COEFF_23_B2},6112{ AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,6113AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,6114AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},6115{ AR_PHY_TX_IQCAL_CORR_COEFF_45_B0,6116AR_PHY_TX_IQCAL_CORR_COEFF_45_B1,6117AR_PHY_TX_IQCAL_CORR_COEFF_45_B2},6118{ AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,6119AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,6120AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},6121{ AR_PHY_TX_IQCAL_CORR_COEFF_67_B0,6122AR_PHY_TX_IQCAL_CORR_COEFF_67_B1,6123AR_PHY_TX_IQCAL_CORR_COEFF_67_B2},6124};6125for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {6126for (im = 0; im < coeff.last_nmeasurement; im++) {6127magnitude = coeff.mag_coeff[ch_idx][im][0];6128phase = coeff.phs_coeff[ch_idx][im][0];61296130#if 06131printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n",6132ch_idx, im, magnitude, phase);6133#endif61346135coeff.iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7);6136if ((im % 2) == 0) {6137OS_REG_RMW_FIELD(ah,6138tx_corr_coeff[im][ch_idx],6139AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,6140coeff.iqc_coeff[0]);6141} else {6142OS_REG_RMW_FIELD(ah,6143tx_corr_coeff[im][ch_idx],6144AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,6145coeff.iqc_coeff[0]);6146}6147}6148}6149OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,6150AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);6151}6152return;6153}615461556156for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {6157nmeasurement = OS_REG_READ_FIELD(ah,6158AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0);6159if (nmeasurement > MAX_MEASUREMENT) {6160nmeasurement = MAX_MEASUREMENT;6161}61626163for (im = 0; im < nmeasurement; im++) {6164HALDEBUG(ah, HAL_DEBUG_CALIBRATE,6165"%s: Doing Tx IQ Cal for chain %d.\n", __func__, ch_idx);6166if (OS_REG_READ(ah, txiqcal_status[ch_idx]) &6167AR_PHY_TX_IQCAL_STATUS_FAILED)6168{6169HALDEBUG(ah, HAL_DEBUG_CALIBRATE,6170"%s: Tx IQ Cal failed for chain %d.\n", __func__, ch_idx);6171goto TX_IQ_CAL_FAILED_;6172}61736174for (j = 0; j < 3; j++) {6175u_int32_t idx = 2 * j;6176/* 3 registers for each calibration result */6177u_int32_t offset = 4 * (3 * im + j);61786179OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,6180AR_PHY_CHAN_INFO_TAB_S2_READ, 0);6181/* 32 bits */6182iq_res[idx] = OS_REG_READ(ah, chan_info_tab[ch_idx] + offset);6183OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,6184AR_PHY_CHAN_INFO_TAB_S2_READ, 1);6185/* 16 bits */6186iq_res[idx + 1] = 0xffff &6187OS_REG_READ(ah, chan_info_tab[ch_idx] + offset);61886189HALDEBUG(ah, HAL_DEBUG_CALIBRATE,6190"%s: IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",6191__func__, idx, iq_res[idx], idx + 1, iq_res[idx + 1]);6192}61936194if (AH_FALSE == ar9300_calc_iq_corr(6195ah, ch_idx, iq_res, coeff.iqc_coeff))6196{6197HALDEBUG(ah, HAL_DEBUG_CALIBRATE,6198"%s: Failed in calculation of IQ correction.\n",6199__func__);6200goto TX_IQ_CAL_FAILED_;6201}62026203coeff.phs_coeff[ch_idx][im][iqcal_idx-1] = coeff.iqc_coeff[0] & 0x7f;6204coeff.mag_coeff[ch_idx][im][iqcal_idx-1] = (coeff.iqc_coeff[0] >> 7) & 0x7f;6205if (coeff.mag_coeff[ch_idx][im][iqcal_idx-1] > 63) {6206coeff.mag_coeff[ch_idx][im][iqcal_idx-1] -= 128;6207}6208if (coeff.phs_coeff[ch_idx][im][iqcal_idx-1] > 63) {6209coeff.phs_coeff[ch_idx][im][iqcal_idx-1] -= 128;6210}6211#if 06212ath_hal_printf(ah, "IQCAL::[ch%d][gain%d]:: mag = %d phase = %d \n",6213ch_idx, im, coeff.mag_coeff[ch_idx][im][iqcal_idx-1],6214coeff.phs_coeff[ch_idx][im][iqcal_idx-1]);6215#endif6216}6217}6218//last iteration; calculate mag and phs6219if (iqcal_idx == max_iqcal) {6220if (max_iqcal>1) {6221for (ch_idx = 0; ch_idx < num_chains; ch_idx++) {6222for (im = 0; im < nmeasurement; im++) {6223//sort mag and phs6224for( ix=0;ix<max_iqcal-1;ix++){6225for( iy=ix+1;iy<=max_iqcal-1;iy++){6226if(coeff.mag_coeff[ch_idx][im][iy] <6227coeff.mag_coeff[ch_idx][im][ix]) {6228//swap6229temp=coeff.mag_coeff[ch_idx][im][ix];6230coeff.mag_coeff[ch_idx][im][ix] = coeff.mag_coeff[ch_idx][im][iy];6231coeff.mag_coeff[ch_idx][im][iy] = temp;6232}6233if(coeff.phs_coeff[ch_idx][im][iy] <6234coeff.phs_coeff[ch_idx][im][ix]){6235//swap6236temp=coeff.phs_coeff[ch_idx][im][ix];6237coeff.phs_coeff[ch_idx][im][ix]=coeff.phs_coeff[ch_idx][im][iy];6238coeff.phs_coeff[ch_idx][im][iy]=temp;6239}6240}6241}6242//select median; 3rd entry in the sorted array6243coeff.mag_coeff[ch_idx][im][0] =6244coeff.mag_coeff[ch_idx][im][max_iqcal/2];6245coeff.phs_coeff[ch_idx][im][0] =6246coeff.phs_coeff[ch_idx][im][max_iqcal/2];6247HALDEBUG(ah, HAL_DEBUG_CALIBRATE,6248"IQCAL: Median [ch%d][gain%d]:: mag = %d phase = %d \n",6249ch_idx, im,coeff.mag_coeff[ch_idx][im][0],6250coeff.phs_coeff[ch_idx][im][0]);6251}6252}6253}6254ar9300_tx_iq_cal_outlier_detection(ah,ichan, num_chains, &coeff,is_cal_reusable);6255}625662576258coeff.last_nmeasurement = nmeasurement;6259coeff.last_cal = AH_TRUE;62606261return;62626263TX_IQ_CAL_FAILED_:6264/* no need to print this, it is AGC failure not chip stuck */6265/*ath_hal_printf(ah, "Tx IQ Cal failed(%d)\n", line);*/6266coeff.last_cal = AH_FALSE;6267return;6268}626962706271/*6272* ar9300_disable_phy_restart6273*6274* In some BBpanics, we can disable the phyrestart6275* disable_phy_restart6276* != 0, disable the phy restart in h/w6277* == 0, enable the phy restart in h/w6278*/6279void ar9300_disable_phy_restart(struct ath_hal *ah, int disable_phy_restart)6280{6281u_int32_t val;62826283val = OS_REG_READ(ah, AR_PHY_RESTART);6284if (disable_phy_restart) {6285val &= ~AR_PHY_RESTART_ENA;6286AH9300(ah)->ah_phyrestart_disabled = 1;6287} else {6288val |= AR_PHY_RESTART_ENA;6289AH9300(ah)->ah_phyrestart_disabled = 0;6290}6291OS_REG_WRITE(ah, AR_PHY_RESTART, val);62926293val = OS_REG_READ(ah, AR_PHY_RESTART);6294}62956296HAL_BOOL6297ar9300_interference_is_present(struct ath_hal *ah)6298{6299int i;6300struct ath_hal_private *ahpriv = AH_PRIVATE(ah);6301const struct ieee80211_channel *chan = ahpriv->ah_curchan;6302HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);63036304if (ichan == NULL) {6305ath_hal_printf(ah, "%s: called with ichan=NULL\n", __func__);6306return AH_FALSE;6307}63086309/* This function is called after a stuck beacon, if EACS is enabled.6310* If CW interference is severe, then HW goes into a loop of continuous6311* stuck beacons and resets. On reset the NF cal history is cleared.6312* So the median value of the history cannot be used -6313* hence check if any value (Chain 0/Primary Channel)6314* is outside the bounds.6315*/6316HAL_NFCAL_HIST_FULL *h = AH_HOME_CHAN_NFCAL_HIST(ah, ichan);6317for (i = 0; i < HAL_NF_CAL_HIST_LEN_FULL; i++) {6318if (h->nf_cal_buffer[i][0] >6319AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta)6320{6321return AH_TRUE;6322}63236324}6325return AH_FALSE;6326}63276328#if ATH_SUPPORT_CRDC6329void6330ar9300_crdc_rx_notify(struct ath_hal *ah, struct ath_rx_status *rxs)6331{6332struct ath_hal_private *ahpriv = AH_PRIVATE(ah);6333int rssi_index;63346335if ((!AR_SREV_WASP(ah)) ||6336(!ahpriv->ah_config.ath_hal_crdc_enable)) {6337return;6338}63396340if (rxs->rs_isaggr && rxs->rs_moreaggr) {6341return;6342}63436344if ((rxs->rs_rssi_ctl0 >= HAL_RSSI_BAD) ||6345(rxs->rs_rssi_ctl1 >= HAL_RSSI_BAD)) {6346return;6347}63486349rssi_index = ah->ah_crdc_rssi_ptr % HAL_MAX_CRDC_RSSI_SAMPLE;63506351ah->ah_crdc_rssi_sample[0][rssi_index] = rxs->rs_rssi_ctl0;6352ah->ah_crdc_rssi_sample[1][rssi_index] = rxs->rs_rssi_ctl1;63536354ah->ah_crdc_rssi_ptr++;6355}63566357static int6358ar9300_crdc_avg_rssi(struct ath_hal *ah, int chain)6359{6360int crdc_rssi_sum = 0;6361int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr, i;6362struct ath_hal_private *ahpriv = AH_PRIVATE(ah);6363int crdc_window = ahpriv->ah_config.ath_hal_crdc_window;63646365if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) {6366crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE;6367}63686369for (i = 1; i <= crdc_window; i++) {6370crdc_rssi_sum +=6371ah->ah_crdc_rssi_sample[chain]6372[(crdc_rssi_ptr - i) % HAL_MAX_CRDC_RSSI_SAMPLE];6373}63746375return crdc_rssi_sum / crdc_window;6376}63776378static void6379ar9300_crdc_activate(struct ath_hal *ah, int rssi_diff, int enable)6380{6381int val, orig_val;6382struct ath_hal_private *ahpriv = AH_PRIVATE(ah);6383int crdc_numerator = ahpriv->ah_config.ath_hal_crdc_numerator;6384int crdc_denominator = ahpriv->ah_config.ath_hal_crdc_denominator;6385int c = (rssi_diff * crdc_numerator) / crdc_denominator;63866387val = orig_val = OS_REG_READ(ah, AR_PHY_MULTICHAIN_CTRL);6388val &= 0xffffff00;6389if (enable) {6390val |= 0x1;6391val |= ((c << 1) & 0xff);6392}6393OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_CTRL, val);6394HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "diff: %02d comp: %02d reg: %08x %08x\n",6395rssi_diff, c, orig_val, val);6396}639763986399void ar9300_chain_rssi_diff_compensation(struct ath_hal *ah)6400{6401struct ath_hal_private *ahpriv = AH_PRIVATE(ah);6402int crdc_window = ahpriv->ah_config.ath_hal_crdc_window;6403int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr;6404int crdc_rssi_thresh = ahpriv->ah_config.ath_hal_crdc_rssithresh;6405int crdc_diff_thresh = ahpriv->ah_config.ath_hal_crdc_diffthresh;6406int avg_rssi[2], avg_rssi_diff;64076408if ((!AR_SREV_WASP(ah)) ||6409(!ahpriv->ah_config.ath_hal_crdc_enable)) {6410if (ah->ah_crdc_rssi_ptr) {6411ar9300_crdc_activate(ah, 0, 0);6412ah->ah_crdc_rssi_ptr = 0;6413}6414return;6415}64166417if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) {6418crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE;6419}64206421if (crdc_rssi_ptr < crdc_window) {6422return;6423}64246425avg_rssi[0] = ar9300_crdc_avg_rssi(ah, 0);6426avg_rssi[1] = ar9300_crdc_avg_rssi(ah, 1);6427avg_rssi_diff = avg_rssi[1] - avg_rssi[0];64286429HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "crdc: avg: %02d %02d ",6430avg_rssi[0], avg_rssi[1]);64316432if ((avg_rssi[0] < crdc_rssi_thresh) &&6433(avg_rssi[1] < crdc_rssi_thresh)) {6434ar9300_crdc_activate(ah, 0, 0);6435} else {6436if (ABS(avg_rssi_diff) >= crdc_diff_thresh) {6437ar9300_crdc_activate(ah, avg_rssi_diff, 1);6438} else {6439ar9300_crdc_activate(ah, 0, 1);6440}6441}6442}6443#endif64446445#if ATH_ANT_DIV_COMB6446HAL_BOOL6447ar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, const struct ieee80211_channel *chan)6448{6449u_int32_t value;6450u_int32_t regval;6451struct ath_hal_9300 *ahp = AH9300(ah);6452HAL_CHANNEL_INTERNAL *ichan;6453struct ath_hal_private *ahpriv = AH_PRIVATE(ah);6454HAL_CAPABILITIES *pcap = &ahpriv->ah_caps;64556456HALDEBUG(ah, HAL_DEBUG_RESET | HAL_DEBUG_BT_COEX,6457"%s: called; enable=%d\n", __func__, enable);64586459if (AR_SREV_POSEIDON(ah)) {6460// Make sure this scheme is only used for WB225(Astra)6461ahp->ah_lna_div_use_bt_ant_enable = enable;64626463ichan = ar9300_check_chan(ah, chan);6464if ( ichan == AH_NULL ) {6465HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n",6466__func__, chan->ic_freq, chan->ic_flags);6467return AH_FALSE;6468}64696470if ( enable == TRUE ) {6471pcap->halAntDivCombSupport = TRUE;6472} else {6473pcap->halAntDivCombSupport = pcap->halAntDivCombSupportOrg;6474}64756476#define AR_SWITCH_TABLE_COM2_ALL (0xffffff)6477#define AR_SWITCH_TABLE_COM2_ALL_S (0)6478value = ar9300_ant_ctrl_common2_get(ah, IS_CHAN_2GHZ(ichan));6479if ( enable == TRUE ) {6480value &= ~AR_SWITCH_TABLE_COM2_ALL;6481value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable;6482}6483HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value);6484OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);64856486value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control);6487/* main_lnaconf, alt_lnaconf, main_tb, alt_tb */6488regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);6489regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */6490regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S;6491/* enable_lnadiv */6492regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK);6493regval |= ((value >> 6) & 0x1) <<6494MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT;6495if ( enable == TRUE ) {6496regval |= ANT_DIV_ENABLE;6497}6498OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);64996500/* enable fast_div */6501regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT);6502regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK);6503regval |= ((value >> 7) & 0x1) <<6504BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT;6505if ( enable == TRUE ) {6506regval |= FAST_DIV_ENABLE;6507}6508OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);65096510if ( AR_SREV_POSEIDON_11_OR_LATER(ah) ) {6511if (pcap->halAntDivCombSupport) {6512/* If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning */6513regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);6514/* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */6515regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |6516MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |6517MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK |6518MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK));6519regval |= (HAL_ANT_DIV_COMB_LNA1 <<6520MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);6521regval |= (HAL_ANT_DIV_COMB_LNA2 <<6522MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);6523OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);6524}6525}65266527return AH_TRUE;6528} else if (AR_SREV_APHRODITE(ah)) {6529ahp->ah_lna_div_use_bt_ant_enable = enable;6530if (enable) {6531OS_REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, ANT_DIV_ENABLE);6532OS_REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT));6533OS_REG_SET_BIT(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);6534OS_REG_SET_BIT(ah, AR_PHY_RESTART, RESTART__ENABLE_ANT_FAST_DIV_M2FLAG__MASK);6535OS_REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);6536} else {6537OS_REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, ANT_DIV_ENABLE);6538OS_REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, (1 << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_SW_RX_PROT__SHIFT));6539OS_REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);6540OS_REG_CLR_BIT(ah, AR_PHY_RESTART, RESTART__ENABLE_ANT_FAST_DIV_M2FLAG__MASK);6541OS_REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);65426543regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL);6544regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK |6545MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK |6546MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK |6547MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK));6548regval |= (HAL_ANT_DIV_COMB_LNA1 <<6549MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT);6550regval |= (HAL_ANT_DIV_COMB_LNA2 <<6551MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT);65526553OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);6554}6555return AH_TRUE;6556}6557return AH_TRUE;6558}6559#endif /* ATH_ANT_DIV_COMB */656065616562