1*9999SWang.Lin@Sun.COM /* 2*9999SWang.Lin@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3*9999SWang.Lin@Sun.COM * Use is subject to license terms. 4*9999SWang.Lin@Sun.COM */ 5*9999SWang.Lin@Sun.COM 6*9999SWang.Lin@Sun.COM /* 7*9999SWang.Lin@Sun.COM * Copyright (c) 2008 Atheros Communications Inc. 8*9999SWang.Lin@Sun.COM * 9*9999SWang.Lin@Sun.COM * Permission to use, copy, modify, and/or distribute this software for any 10*9999SWang.Lin@Sun.COM * purpose with or without fee is hereby granted, provided that the above 11*9999SWang.Lin@Sun.COM * copyright notice and this permission notice appear in all copies. 12*9999SWang.Lin@Sun.COM * 13*9999SWang.Lin@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14*9999SWang.Lin@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15*9999SWang.Lin@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16*9999SWang.Lin@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17*9999SWang.Lin@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18*9999SWang.Lin@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19*9999SWang.Lin@Sun.COM * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20*9999SWang.Lin@Sun.COM */ 21*9999SWang.Lin@Sun.COM 22*9999SWang.Lin@Sun.COM #include "arn_core.h" 23*9999SWang.Lin@Sun.COM #include "arn_hw.h" 24*9999SWang.Lin@Sun.COM #include "arn_reg.h" 25*9999SWang.Lin@Sun.COM #include "arn_phy.h" 26*9999SWang.Lin@Sun.COM 27*9999SWang.Lin@Sun.COM static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; 28*9999SWang.Lin@Sun.COM 29*9999SWang.Lin@Sun.COM /* We can tune this as we go by monitoring really low values */ 30*9999SWang.Lin@Sun.COM #define ATH9K_NF_TOO_LOW -60 31*9999SWang.Lin@Sun.COM 32*9999SWang.Lin@Sun.COM /* 33*9999SWang.Lin@Sun.COM * AR5416 may return very high value (like -31 dBm), in those cases the nf 34*9999SWang.Lin@Sun.COM * is incorrect and we should use the static NF value. Later we can try to 35*9999SWang.Lin@Sun.COM * find out why they are reporting these values 36*9999SWang.Lin@Sun.COM */ 37*9999SWang.Lin@Sun.COM 38*9999SWang.Lin@Sun.COM /* ARGSUSED */ 39*9999SWang.Lin@Sun.COM static boolean_t 40*9999SWang.Lin@Sun.COM ath9k_hw_nf_in_range(struct ath_hal *ah, signed short nf) 41*9999SWang.Lin@Sun.COM { 42*9999SWang.Lin@Sun.COM if (nf > ATH9K_NF_TOO_LOW) { 43*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 44*9999SWang.Lin@Sun.COM "%s: noise floor value detected (%d) is " 45*9999SWang.Lin@Sun.COM "lower than what we think is a " 46*9999SWang.Lin@Sun.COM "reasonable value (%d)\n", 47*9999SWang.Lin@Sun.COM __func__, nf, ATH9K_NF_TOO_LOW)); 48*9999SWang.Lin@Sun.COM 49*9999SWang.Lin@Sun.COM return (B_FALSE); 50*9999SWang.Lin@Sun.COM } 51*9999SWang.Lin@Sun.COM return (B_TRUE); 52*9999SWang.Lin@Sun.COM } 53*9999SWang.Lin@Sun.COM 54*9999SWang.Lin@Sun.COM static int16_t 55*9999SWang.Lin@Sun.COM ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) 56*9999SWang.Lin@Sun.COM { 57*9999SWang.Lin@Sun.COM int16_t nfval; 58*9999SWang.Lin@Sun.COM int16_t sort[ATH9K_NF_CAL_HIST_MAX]; 59*9999SWang.Lin@Sun.COM int i, j; 60*9999SWang.Lin@Sun.COM 61*9999SWang.Lin@Sun.COM for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) 62*9999SWang.Lin@Sun.COM sort[i] = nfCalBuffer[i]; 63*9999SWang.Lin@Sun.COM 64*9999SWang.Lin@Sun.COM for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { 65*9999SWang.Lin@Sun.COM for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { 66*9999SWang.Lin@Sun.COM if (sort[j] > sort[j - 1]) { 67*9999SWang.Lin@Sun.COM nfval = sort[j]; 68*9999SWang.Lin@Sun.COM sort[j] = sort[j - 1]; 69*9999SWang.Lin@Sun.COM sort[j - 1] = nfval; 70*9999SWang.Lin@Sun.COM } 71*9999SWang.Lin@Sun.COM } 72*9999SWang.Lin@Sun.COM } 73*9999SWang.Lin@Sun.COM nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; 74*9999SWang.Lin@Sun.COM 75*9999SWang.Lin@Sun.COM return (nfval); 76*9999SWang.Lin@Sun.COM } 77*9999SWang.Lin@Sun.COM 78*9999SWang.Lin@Sun.COM static void 79*9999SWang.Lin@Sun.COM ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, 80*9999SWang.Lin@Sun.COM int16_t *nfarray) 81*9999SWang.Lin@Sun.COM { 82*9999SWang.Lin@Sun.COM int i; 83*9999SWang.Lin@Sun.COM 84*9999SWang.Lin@Sun.COM for (i = 0; i < NUM_NF_READINGS; i++) { 85*9999SWang.Lin@Sun.COM h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; 86*9999SWang.Lin@Sun.COM 87*9999SWang.Lin@Sun.COM if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) 88*9999SWang.Lin@Sun.COM h[i].currIndex = 0; 89*9999SWang.Lin@Sun.COM 90*9999SWang.Lin@Sun.COM if (h[i].invalidNFcount > 0) { 91*9999SWang.Lin@Sun.COM if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || 92*9999SWang.Lin@Sun.COM nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { 93*9999SWang.Lin@Sun.COM h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; 94*9999SWang.Lin@Sun.COM } else { 95*9999SWang.Lin@Sun.COM h[i].invalidNFcount--; 96*9999SWang.Lin@Sun.COM h[i].privNF = nfarray[i]; 97*9999SWang.Lin@Sun.COM } 98*9999SWang.Lin@Sun.COM } else { 99*9999SWang.Lin@Sun.COM h[i].privNF = 100*9999SWang.Lin@Sun.COM ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); 101*9999SWang.Lin@Sun.COM } 102*9999SWang.Lin@Sun.COM } 103*9999SWang.Lin@Sun.COM } 104*9999SWang.Lin@Sun.COM 105*9999SWang.Lin@Sun.COM static void 106*9999SWang.Lin@Sun.COM ath9k_hw_do_getnf(struct ath_hal *ah, 107*9999SWang.Lin@Sun.COM int16_t nfarray[NUM_NF_READINGS]) 108*9999SWang.Lin@Sun.COM { 109*9999SWang.Lin@Sun.COM int16_t nf; 110*9999SWang.Lin@Sun.COM 111*9999SWang.Lin@Sun.COM if (AR_SREV_9280_10_OR_LATER(ah)) 112*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); 113*9999SWang.Lin@Sun.COM else 114*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); 115*9999SWang.Lin@Sun.COM 116*9999SWang.Lin@Sun.COM if (nf & 0x100) 117*9999SWang.Lin@Sun.COM nf = 0 - ((nf ^ 0x1ff) + 1); 118*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 119*9999SWang.Lin@Sun.COM "NF calibrated [ctl] [chain 0] is %d\n", nf)); 120*9999SWang.Lin@Sun.COM nfarray[0] = nf; 121*9999SWang.Lin@Sun.COM 122*9999SWang.Lin@Sun.COM if (AR_SREV_9280_10_OR_LATER(ah)) 123*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), 124*9999SWang.Lin@Sun.COM AR9280_PHY_CH1_MINCCA_PWR); 125*9999SWang.Lin@Sun.COM else 126*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), 127*9999SWang.Lin@Sun.COM AR_PHY_CH1_MINCCA_PWR); 128*9999SWang.Lin@Sun.COM 129*9999SWang.Lin@Sun.COM if (nf & 0x100) 130*9999SWang.Lin@Sun.COM nf = 0 - ((nf ^ 0x1ff) + 1); 131*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 132*9999SWang.Lin@Sun.COM "NF calibrated [ctl] [chain 1] is %d\n", nf)); 133*9999SWang.Lin@Sun.COM nfarray[1] = nf; 134*9999SWang.Lin@Sun.COM 135*9999SWang.Lin@Sun.COM if (!AR_SREV_9280(ah)) { 136*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), 137*9999SWang.Lin@Sun.COM AR_PHY_CH2_MINCCA_PWR); 138*9999SWang.Lin@Sun.COM if (nf & 0x100) 139*9999SWang.Lin@Sun.COM nf = 0 - ((nf ^ 0x1ff) + 1); 140*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 141*9999SWang.Lin@Sun.COM "NF calibrated [ctl] [chain 2] is %d\n", nf)); 142*9999SWang.Lin@Sun.COM nfarray[2] = nf; 143*9999SWang.Lin@Sun.COM } 144*9999SWang.Lin@Sun.COM 145*9999SWang.Lin@Sun.COM if (AR_SREV_9280_10_OR_LATER(ah)) 146*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), 147*9999SWang.Lin@Sun.COM AR9280_PHY_EXT_MINCCA_PWR); 148*9999SWang.Lin@Sun.COM else 149*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), 150*9999SWang.Lin@Sun.COM AR_PHY_EXT_MINCCA_PWR); 151*9999SWang.Lin@Sun.COM 152*9999SWang.Lin@Sun.COM if (nf & 0x100) 153*9999SWang.Lin@Sun.COM nf = 0 - ((nf ^ 0x1ff) + 1); 154*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 155*9999SWang.Lin@Sun.COM "NF calibrated [ext] [chain 0] is %d\n", nf)); 156*9999SWang.Lin@Sun.COM nfarray[3] = nf; 157*9999SWang.Lin@Sun.COM 158*9999SWang.Lin@Sun.COM if (AR_SREV_9280_10_OR_LATER(ah)) 159*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), 160*9999SWang.Lin@Sun.COM AR9280_PHY_CH1_EXT_MINCCA_PWR); 161*9999SWang.Lin@Sun.COM else 162*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), 163*9999SWang.Lin@Sun.COM AR_PHY_CH1_EXT_MINCCA_PWR); 164*9999SWang.Lin@Sun.COM 165*9999SWang.Lin@Sun.COM if (nf & 0x100) 166*9999SWang.Lin@Sun.COM nf = 0 - ((nf ^ 0x1ff) + 1); 167*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 168*9999SWang.Lin@Sun.COM "NF calibrated [ext] [chain 1] is %d\n", nf)); 169*9999SWang.Lin@Sun.COM nfarray[4] = nf; 170*9999SWang.Lin@Sun.COM 171*9999SWang.Lin@Sun.COM if (!AR_SREV_9280(ah)) { 172*9999SWang.Lin@Sun.COM nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), 173*9999SWang.Lin@Sun.COM AR_PHY_CH2_EXT_MINCCA_PWR); 174*9999SWang.Lin@Sun.COM if (nf & 0x100) 175*9999SWang.Lin@Sun.COM nf = 0 - ((nf ^ 0x1ff) + 1); 176*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 177*9999SWang.Lin@Sun.COM "NF calibrated [ext] [chain 2] is %d\n", nf)); 178*9999SWang.Lin@Sun.COM nfarray[5] = nf; 179*9999SWang.Lin@Sun.COM } 180*9999SWang.Lin@Sun.COM } 181*9999SWang.Lin@Sun.COM 182*9999SWang.Lin@Sun.COM static boolean_t 183*9999SWang.Lin@Sun.COM getNoiseFloorThresh(struct ath_hal *ah, 184*9999SWang.Lin@Sun.COM const struct ath9k_channel *chan, 185*9999SWang.Lin@Sun.COM int16_t *nft) 186*9999SWang.Lin@Sun.COM { 187*9999SWang.Lin@Sun.COM switch (chan->chanmode) { 188*9999SWang.Lin@Sun.COM case CHANNEL_A: 189*9999SWang.Lin@Sun.COM case CHANNEL_A_HT20: 190*9999SWang.Lin@Sun.COM case CHANNEL_A_HT40PLUS: 191*9999SWang.Lin@Sun.COM case CHANNEL_A_HT40MINUS: 192*9999SWang.Lin@Sun.COM *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); 193*9999SWang.Lin@Sun.COM break; 194*9999SWang.Lin@Sun.COM case CHANNEL_B: 195*9999SWang.Lin@Sun.COM case CHANNEL_G: 196*9999SWang.Lin@Sun.COM case CHANNEL_G_HT20: 197*9999SWang.Lin@Sun.COM case CHANNEL_G_HT40PLUS: 198*9999SWang.Lin@Sun.COM case CHANNEL_G_HT40MINUS: 199*9999SWang.Lin@Sun.COM *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); 200*9999SWang.Lin@Sun.COM break; 201*9999SWang.Lin@Sun.COM default: 202*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CHANNEL, 203*9999SWang.Lin@Sun.COM "%s: invalid channel flags 0x%x\n", __func__, 204*9999SWang.Lin@Sun.COM chan->channelFlags)); 205*9999SWang.Lin@Sun.COM return (B_FALSE); 206*9999SWang.Lin@Sun.COM } 207*9999SWang.Lin@Sun.COM 208*9999SWang.Lin@Sun.COM return (B_TRUE); 209*9999SWang.Lin@Sun.COM } 210*9999SWang.Lin@Sun.COM 211*9999SWang.Lin@Sun.COM static void 212*9999SWang.Lin@Sun.COM ath9k_hw_setup_calibration(struct ath_hal *ah, 213*9999SWang.Lin@Sun.COM struct hal_cal_list *currCal) 214*9999SWang.Lin@Sun.COM { 215*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), 216*9999SWang.Lin@Sun.COM AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, 217*9999SWang.Lin@Sun.COM currCal->calData->calCountMax); 218*9999SWang.Lin@Sun.COM 219*9999SWang.Lin@Sun.COM switch (currCal->calData->calType) { 220*9999SWang.Lin@Sun.COM case IQ_MISMATCH_CAL: 221*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 222*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 223*9999SWang.Lin@Sun.COM "%s: starting IQ Mismatch Calibration\n", 224*9999SWang.Lin@Sun.COM __func__)); 225*9999SWang.Lin@Sun.COM break; 226*9999SWang.Lin@Sun.COM case ADC_GAIN_CAL: 227*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); 228*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 229*9999SWang.Lin@Sun.COM "%s: starting ADC Gain Calibration\n", __func__)); 230*9999SWang.Lin@Sun.COM break; 231*9999SWang.Lin@Sun.COM case ADC_DC_CAL: 232*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); 233*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 234*9999SWang.Lin@Sun.COM "%s: starting ADC DC Calibration\n", __func__)); 235*9999SWang.Lin@Sun.COM break; 236*9999SWang.Lin@Sun.COM case ADC_DC_INIT_CAL: 237*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); 238*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 239*9999SWang.Lin@Sun.COM "%s: starting Init ADC DC Calibration\n", 240*9999SWang.Lin@Sun.COM __func__)); 241*9999SWang.Lin@Sun.COM break; 242*9999SWang.Lin@Sun.COM } 243*9999SWang.Lin@Sun.COM 244*9999SWang.Lin@Sun.COM REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 245*9999SWang.Lin@Sun.COM AR_PHY_TIMING_CTRL4_DO_CAL); 246*9999SWang.Lin@Sun.COM } 247*9999SWang.Lin@Sun.COM 248*9999SWang.Lin@Sun.COM static void 249*9999SWang.Lin@Sun.COM ath9k_hw_reset_calibration(struct ath_hal *ah, 250*9999SWang.Lin@Sun.COM struct hal_cal_list *currCal) 251*9999SWang.Lin@Sun.COM { 252*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 253*9999SWang.Lin@Sun.COM int i; 254*9999SWang.Lin@Sun.COM 255*9999SWang.Lin@Sun.COM ath9k_hw_setup_calibration(ah, currCal); 256*9999SWang.Lin@Sun.COM 257*9999SWang.Lin@Sun.COM currCal->calState = CAL_RUNNING; 258*9999SWang.Lin@Sun.COM 259*9999SWang.Lin@Sun.COM for (i = 0; i < AR5416_MAX_CHAINS; i++) { 260*9999SWang.Lin@Sun.COM ahp->ah_Meas0.sign[i] = 0; 261*9999SWang.Lin@Sun.COM ahp->ah_Meas1.sign[i] = 0; 262*9999SWang.Lin@Sun.COM ahp->ah_Meas2.sign[i] = 0; 263*9999SWang.Lin@Sun.COM ahp->ah_Meas3.sign[i] = 0; 264*9999SWang.Lin@Sun.COM } 265*9999SWang.Lin@Sun.COM 266*9999SWang.Lin@Sun.COM ahp->ah_CalSamples = 0; 267*9999SWang.Lin@Sun.COM } 268*9999SWang.Lin@Sun.COM 269*9999SWang.Lin@Sun.COM static void 270*9999SWang.Lin@Sun.COM ath9k_hw_per_calibration(struct ath_hal *ah, 271*9999SWang.Lin@Sun.COM struct ath9k_channel *ichan, 272*9999SWang.Lin@Sun.COM uint8_t rxchainmask, 273*9999SWang.Lin@Sun.COM struct hal_cal_list *currCal, 274*9999SWang.Lin@Sun.COM boolean_t *isCalDone) 275*9999SWang.Lin@Sun.COM { 276*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 277*9999SWang.Lin@Sun.COM 278*9999SWang.Lin@Sun.COM *isCalDone = B_FALSE; 279*9999SWang.Lin@Sun.COM 280*9999SWang.Lin@Sun.COM if (currCal->calState == CAL_RUNNING) { 281*9999SWang.Lin@Sun.COM if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & 282*9999SWang.Lin@Sun.COM AR_PHY_TIMING_CTRL4_DO_CAL)) { 283*9999SWang.Lin@Sun.COM 284*9999SWang.Lin@Sun.COM currCal->calData->calCollect(ah); 285*9999SWang.Lin@Sun.COM ahp->ah_CalSamples++; 286*9999SWang.Lin@Sun.COM 287*9999SWang.Lin@Sun.COM if (ahp->ah_CalSamples >= 288*9999SWang.Lin@Sun.COM currCal->calData->calNumSamples) { 289*9999SWang.Lin@Sun.COM int i, numChains = 0; 290*9999SWang.Lin@Sun.COM for (i = 0; i < AR5416_MAX_CHAINS; i++) { 291*9999SWang.Lin@Sun.COM if (rxchainmask & (1 << i)) 292*9999SWang.Lin@Sun.COM numChains++; 293*9999SWang.Lin@Sun.COM } 294*9999SWang.Lin@Sun.COM 295*9999SWang.Lin@Sun.COM currCal->calData->calPostProc(ah, numChains); 296*9999SWang.Lin@Sun.COM ichan->CalValid |= currCal->calData->calType; 297*9999SWang.Lin@Sun.COM currCal->calState = CAL_DONE; 298*9999SWang.Lin@Sun.COM *isCalDone = B_TRUE; 299*9999SWang.Lin@Sun.COM } else { 300*9999SWang.Lin@Sun.COM ath9k_hw_setup_calibration(ah, currCal); 301*9999SWang.Lin@Sun.COM } 302*9999SWang.Lin@Sun.COM } 303*9999SWang.Lin@Sun.COM } else if (!(ichan->CalValid & currCal->calData->calType)) { 304*9999SWang.Lin@Sun.COM ath9k_hw_reset_calibration(ah, currCal); 305*9999SWang.Lin@Sun.COM } 306*9999SWang.Lin@Sun.COM } 307*9999SWang.Lin@Sun.COM 308*9999SWang.Lin@Sun.COM static boolean_t 309*9999SWang.Lin@Sun.COM ath9k_hw_iscal_supported(struct ath_hal *ah, 310*9999SWang.Lin@Sun.COM struct ath9k_channel *chan, 311*9999SWang.Lin@Sun.COM enum hal_cal_types calType) 312*9999SWang.Lin@Sun.COM { 313*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 314*9999SWang.Lin@Sun.COM boolean_t retval = B_FALSE; 315*9999SWang.Lin@Sun.COM 316*9999SWang.Lin@Sun.COM switch (calType & ahp->ah_suppCals) { 317*9999SWang.Lin@Sun.COM case IQ_MISMATCH_CAL: 318*9999SWang.Lin@Sun.COM if (!IS_CHAN_B(chan)) 319*9999SWang.Lin@Sun.COM retval = B_TRUE; 320*9999SWang.Lin@Sun.COM break; 321*9999SWang.Lin@Sun.COM case ADC_GAIN_CAL: 322*9999SWang.Lin@Sun.COM case ADC_DC_CAL: 323*9999SWang.Lin@Sun.COM if (!IS_CHAN_B(chan) && 324*9999SWang.Lin@Sun.COM !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) 325*9999SWang.Lin@Sun.COM retval = B_TRUE; 326*9999SWang.Lin@Sun.COM break; 327*9999SWang.Lin@Sun.COM } 328*9999SWang.Lin@Sun.COM 329*9999SWang.Lin@Sun.COM return (retval); 330*9999SWang.Lin@Sun.COM } 331*9999SWang.Lin@Sun.COM 332*9999SWang.Lin@Sun.COM static void 333*9999SWang.Lin@Sun.COM ath9k_hw_iqcal_collect(struct ath_hal *ah) 334*9999SWang.Lin@Sun.COM { 335*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 336*9999SWang.Lin@Sun.COM int i; 337*9999SWang.Lin@Sun.COM 338*9999SWang.Lin@Sun.COM for (i = 0; i < AR5416_MAX_CHAINS; i++) { 339*9999SWang.Lin@Sun.COM ahp->ah_totalPowerMeasI[i] += 340*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 341*9999SWang.Lin@Sun.COM ahp->ah_totalPowerMeasQ[i] += 342*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 343*9999SWang.Lin@Sun.COM ahp->ah_totalIqCorrMeas[i] += 344*9999SWang.Lin@Sun.COM (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 345*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 346*9999SWang.Lin@Sun.COM "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", 347*9999SWang.Lin@Sun.COM ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], 348*9999SWang.Lin@Sun.COM ahp->ah_totalPowerMeasQ[i], 349*9999SWang.Lin@Sun.COM ahp->ah_totalIqCorrMeas[i])); 350*9999SWang.Lin@Sun.COM } 351*9999SWang.Lin@Sun.COM } 352*9999SWang.Lin@Sun.COM 353*9999SWang.Lin@Sun.COM static void 354*9999SWang.Lin@Sun.COM ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) 355*9999SWang.Lin@Sun.COM { 356*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 357*9999SWang.Lin@Sun.COM int i; 358*9999SWang.Lin@Sun.COM 359*9999SWang.Lin@Sun.COM for (i = 0; i < AR5416_MAX_CHAINS; i++) { 360*9999SWang.Lin@Sun.COM ahp->ah_totalAdcIOddPhase[i] += 361*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 362*9999SWang.Lin@Sun.COM ahp->ah_totalAdcIEvenPhase[i] += 363*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 364*9999SWang.Lin@Sun.COM ahp->ah_totalAdcQOddPhase[i] += 365*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 366*9999SWang.Lin@Sun.COM ahp->ah_totalAdcQEvenPhase[i] += 367*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 368*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 369*9999SWang.Lin@Sun.COM "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " 370*9999SWang.Lin@Sun.COM "oddq=0x%08x; evenq=0x%08x;\n", 371*9999SWang.Lin@Sun.COM ahp->ah_CalSamples, i, 372*9999SWang.Lin@Sun.COM ahp->ah_totalAdcIOddPhase[i], 373*9999SWang.Lin@Sun.COM ahp->ah_totalAdcIEvenPhase[i], 374*9999SWang.Lin@Sun.COM ahp->ah_totalAdcQOddPhase[i], 375*9999SWang.Lin@Sun.COM ahp->ah_totalAdcQEvenPhase[i])); 376*9999SWang.Lin@Sun.COM } 377*9999SWang.Lin@Sun.COM } 378*9999SWang.Lin@Sun.COM 379*9999SWang.Lin@Sun.COM static void 380*9999SWang.Lin@Sun.COM ath9k_hw_adc_dccal_collect(struct ath_hal *ah) 381*9999SWang.Lin@Sun.COM { 382*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 383*9999SWang.Lin@Sun.COM int i; 384*9999SWang.Lin@Sun.COM 385*9999SWang.Lin@Sun.COM for (i = 0; i < AR5416_MAX_CHAINS; i++) { 386*9999SWang.Lin@Sun.COM ahp->ah_totalAdcDcOffsetIOddPhase[i] += 387*9999SWang.Lin@Sun.COM (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 388*9999SWang.Lin@Sun.COM ahp->ah_totalAdcDcOffsetIEvenPhase[i] += 389*9999SWang.Lin@Sun.COM (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 390*9999SWang.Lin@Sun.COM ahp->ah_totalAdcDcOffsetQOddPhase[i] += 391*9999SWang.Lin@Sun.COM (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 392*9999SWang.Lin@Sun.COM ahp->ah_totalAdcDcOffsetQEvenPhase[i] += 393*9999SWang.Lin@Sun.COM (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 394*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 395*9999SWang.Lin@Sun.COM "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " 396*9999SWang.Lin@Sun.COM "oddq=0x%08x; evenq=0x%08x;\n", 397*9999SWang.Lin@Sun.COM ahp->ah_CalSamples, i, 398*9999SWang.Lin@Sun.COM ahp->ah_totalAdcDcOffsetIOddPhase[i], 399*9999SWang.Lin@Sun.COM ahp->ah_totalAdcDcOffsetIEvenPhase[i], 400*9999SWang.Lin@Sun.COM ahp->ah_totalAdcDcOffsetQOddPhase[i], 401*9999SWang.Lin@Sun.COM ahp->ah_totalAdcDcOffsetQEvenPhase[i])); 402*9999SWang.Lin@Sun.COM } 403*9999SWang.Lin@Sun.COM } 404*9999SWang.Lin@Sun.COM 405*9999SWang.Lin@Sun.COM static void 406*9999SWang.Lin@Sun.COM ath9k_hw_iqcalibrate(struct ath_hal *ah, uint8_t numChains) 407*9999SWang.Lin@Sun.COM { 408*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 409*9999SWang.Lin@Sun.COM uint32_t powerMeasQ, powerMeasI, iqCorrMeas; 410*9999SWang.Lin@Sun.COM uint32_t qCoffDenom, iCoffDenom; 411*9999SWang.Lin@Sun.COM int32_t qCoff, iCoff; 412*9999SWang.Lin@Sun.COM int iqCorrNeg, i; 413*9999SWang.Lin@Sun.COM 414*9999SWang.Lin@Sun.COM for (i = 0; i < numChains; i++) { 415*9999SWang.Lin@Sun.COM powerMeasI = ahp->ah_totalPowerMeasI[i]; 416*9999SWang.Lin@Sun.COM powerMeasQ = ahp->ah_totalPowerMeasQ[i]; 417*9999SWang.Lin@Sun.COM iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; 418*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 419*9999SWang.Lin@Sun.COM "Starting IQ Cal and Correction for Chain %d\n", 420*9999SWang.Lin@Sun.COM i)); 421*9999SWang.Lin@Sun.COM 422*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 423*9999SWang.Lin@Sun.COM "Orignal: Chn %diq_corr_meas = 0x%08x\n", 424*9999SWang.Lin@Sun.COM i, ahp->ah_totalIqCorrMeas[i])); 425*9999SWang.Lin@Sun.COM 426*9999SWang.Lin@Sun.COM iqCorrNeg = 0; 427*9999SWang.Lin@Sun.COM 428*9999SWang.Lin@Sun.COM if (iqCorrMeas > 0x80000000) { 429*9999SWang.Lin@Sun.COM iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; 430*9999SWang.Lin@Sun.COM iqCorrNeg = 1; 431*9999SWang.Lin@Sun.COM } 432*9999SWang.Lin@Sun.COM 433*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 434*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI)); 435*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 436*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ)); 437*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", 438*9999SWang.Lin@Sun.COM iqCorrNeg)); 439*9999SWang.Lin@Sun.COM 440*9999SWang.Lin@Sun.COM iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; 441*9999SWang.Lin@Sun.COM qCoffDenom = powerMeasQ / 64; 442*9999SWang.Lin@Sun.COM 443*9999SWang.Lin@Sun.COM if (powerMeasQ != 0) { 444*9999SWang.Lin@Sun.COM iCoff = iqCorrMeas / iCoffDenom; 445*9999SWang.Lin@Sun.COM qCoff = powerMeasI / qCoffDenom - 64; 446*9999SWang.Lin@Sun.COM 447*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 448*9999SWang.Lin@Sun.COM "Chn %d iCoff = 0x%08x\n", i, iCoff)); 449*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 450*9999SWang.Lin@Sun.COM "Chn %d qCoff = 0x%08x\n", i, qCoff)); 451*9999SWang.Lin@Sun.COM 452*9999SWang.Lin@Sun.COM iCoff = iCoff & 0x3f; 453*9999SWang.Lin@Sun.COM 454*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 455*9999SWang.Lin@Sun.COM "New: Chn %d iCoff = 0x%08x\n", i, iCoff)); 456*9999SWang.Lin@Sun.COM 457*9999SWang.Lin@Sun.COM if (iqCorrNeg == 0x0) 458*9999SWang.Lin@Sun.COM iCoff = 0x40 - iCoff; 459*9999SWang.Lin@Sun.COM 460*9999SWang.Lin@Sun.COM if (qCoff > 15) 461*9999SWang.Lin@Sun.COM qCoff = 15; 462*9999SWang.Lin@Sun.COM else if (qCoff <= -16) 463*9999SWang.Lin@Sun.COM qCoff = 16; 464*9999SWang.Lin@Sun.COM 465*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 466*9999SWang.Lin@Sun.COM "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", 467*9999SWang.Lin@Sun.COM i, iCoff, qCoff)); 468*9999SWang.Lin@Sun.COM 469*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 470*9999SWang.Lin@Sun.COM AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, 471*9999SWang.Lin@Sun.COM iCoff); 472*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 473*9999SWang.Lin@Sun.COM AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, 474*9999SWang.Lin@Sun.COM qCoff); 475*9999SWang.Lin@Sun.COM 476*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 477*9999SWang.Lin@Sun.COM "IQ Cal and Correction done for Chain %d\n", 478*9999SWang.Lin@Sun.COM i)); 479*9999SWang.Lin@Sun.COM } 480*9999SWang.Lin@Sun.COM } 481*9999SWang.Lin@Sun.COM 482*9999SWang.Lin@Sun.COM REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 483*9999SWang.Lin@Sun.COM AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); 484*9999SWang.Lin@Sun.COM } 485*9999SWang.Lin@Sun.COM 486*9999SWang.Lin@Sun.COM static void 487*9999SWang.Lin@Sun.COM ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, uint8_t numChains) 488*9999SWang.Lin@Sun.COM { 489*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 490*9999SWang.Lin@Sun.COM uint32_t iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, 491*9999SWang.Lin@Sun.COM qEvenMeasOffset; 492*9999SWang.Lin@Sun.COM uint32_t qGainMismatch, iGainMismatch, val, i; 493*9999SWang.Lin@Sun.COM 494*9999SWang.Lin@Sun.COM for (i = 0; i < numChains; i++) { 495*9999SWang.Lin@Sun.COM iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; 496*9999SWang.Lin@Sun.COM iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; 497*9999SWang.Lin@Sun.COM qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; 498*9999SWang.Lin@Sun.COM qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; 499*9999SWang.Lin@Sun.COM 500*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 501*9999SWang.Lin@Sun.COM "Starting ADC Gain Cal for Chain %d\n", i)); 502*9999SWang.Lin@Sun.COM 503*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 504*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_odd_i = 0x%08x\n", i, 505*9999SWang.Lin@Sun.COM iOddMeasOffset)); 506*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 507*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_even_i = 0x%08x\n", i, 508*9999SWang.Lin@Sun.COM iEvenMeasOffset)); 509*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 510*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_odd_q = 0x%08x\n", i, 511*9999SWang.Lin@Sun.COM qOddMeasOffset)); 512*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 513*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_even_q = 0x%08x\n", i, 514*9999SWang.Lin@Sun.COM qEvenMeasOffset)); 515*9999SWang.Lin@Sun.COM 516*9999SWang.Lin@Sun.COM if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { 517*9999SWang.Lin@Sun.COM iGainMismatch = 518*9999SWang.Lin@Sun.COM ((iEvenMeasOffset * 32) / 519*9999SWang.Lin@Sun.COM iOddMeasOffset) & 0x3f; 520*9999SWang.Lin@Sun.COM qGainMismatch = 521*9999SWang.Lin@Sun.COM ((qOddMeasOffset * 32) / 522*9999SWang.Lin@Sun.COM qEvenMeasOffset) & 0x3f; 523*9999SWang.Lin@Sun.COM 524*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 525*9999SWang.Lin@Sun.COM "Chn %d gain_mismatch_i = 0x%08x\n", i, 526*9999SWang.Lin@Sun.COM iGainMismatch)); 527*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 528*9999SWang.Lin@Sun.COM "Chn %d gain_mismatch_q = 0x%08x\n", i, 529*9999SWang.Lin@Sun.COM qGainMismatch)); 530*9999SWang.Lin@Sun.COM 531*9999SWang.Lin@Sun.COM val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 532*9999SWang.Lin@Sun.COM val &= 0xfffff000; 533*9999SWang.Lin@Sun.COM val |= (qGainMismatch) | (iGainMismatch << 6); 534*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 535*9999SWang.Lin@Sun.COM 536*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 537*9999SWang.Lin@Sun.COM "ADC Gain Cal done for Chain %d\n", i)); 538*9999SWang.Lin@Sun.COM } 539*9999SWang.Lin@Sun.COM } 540*9999SWang.Lin@Sun.COM 541*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 542*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 543*9999SWang.Lin@Sun.COM AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); 544*9999SWang.Lin@Sun.COM } 545*9999SWang.Lin@Sun.COM 546*9999SWang.Lin@Sun.COM static void 547*9999SWang.Lin@Sun.COM ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, uint8_t numChains) 548*9999SWang.Lin@Sun.COM { 549*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 550*9999SWang.Lin@Sun.COM uint32_t iOddMeasOffset, iEvenMeasOffset, val, i; 551*9999SWang.Lin@Sun.COM int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; 552*9999SWang.Lin@Sun.COM const struct hal_percal_data *calData = 553*9999SWang.Lin@Sun.COM ahp->ah_cal_list_curr->calData; 554*9999SWang.Lin@Sun.COM uint32_t numSamples = 555*9999SWang.Lin@Sun.COM (1 << (calData->calCountMax + 5)) * calData->calNumSamples; 556*9999SWang.Lin@Sun.COM 557*9999SWang.Lin@Sun.COM for (i = 0; i < numChains; i++) { 558*9999SWang.Lin@Sun.COM iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; 559*9999SWang.Lin@Sun.COM iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; 560*9999SWang.Lin@Sun.COM qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; 561*9999SWang.Lin@Sun.COM qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; 562*9999SWang.Lin@Sun.COM 563*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 564*9999SWang.Lin@Sun.COM "Starting ADC DC Offset Cal for Chain %d\n", i)); 565*9999SWang.Lin@Sun.COM 566*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 567*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_odd_i = %d\n", i, 568*9999SWang.Lin@Sun.COM iOddMeasOffset)); 569*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 570*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_even_i = %d\n", i, 571*9999SWang.Lin@Sun.COM iEvenMeasOffset)); 572*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 573*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_odd_q = %d\n", i, 574*9999SWang.Lin@Sun.COM qOddMeasOffset)); 575*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 576*9999SWang.Lin@Sun.COM "Chn %d pwr_meas_even_q = %d\n", i, 577*9999SWang.Lin@Sun.COM qEvenMeasOffset)); 578*9999SWang.Lin@Sun.COM 579*9999SWang.Lin@Sun.COM iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / 580*9999SWang.Lin@Sun.COM numSamples) & 0x1ff; 581*9999SWang.Lin@Sun.COM qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / 582*9999SWang.Lin@Sun.COM numSamples) & 0x1ff; 583*9999SWang.Lin@Sun.COM 584*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 585*9999SWang.Lin@Sun.COM "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, 586*9999SWang.Lin@Sun.COM iDcMismatch)); 587*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 588*9999SWang.Lin@Sun.COM "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, 589*9999SWang.Lin@Sun.COM qDcMismatch)); 590*9999SWang.Lin@Sun.COM 591*9999SWang.Lin@Sun.COM val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 592*9999SWang.Lin@Sun.COM val &= 0xc0000fff; 593*9999SWang.Lin@Sun.COM val |= (qDcMismatch << 12) | (iDcMismatch << 21); 594*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 595*9999SWang.Lin@Sun.COM 596*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 597*9999SWang.Lin@Sun.COM "ADC DC Offset Cal done for Chain %d\n", i)); 598*9999SWang.Lin@Sun.COM } 599*9999SWang.Lin@Sun.COM 600*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 601*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 602*9999SWang.Lin@Sun.COM AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); 603*9999SWang.Lin@Sun.COM } 604*9999SWang.Lin@Sun.COM 605*9999SWang.Lin@Sun.COM void 606*9999SWang.Lin@Sun.COM ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, 607*9999SWang.Lin@Sun.COM boolean_t *isCalDone) 608*9999SWang.Lin@Sun.COM { 609*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 610*9999SWang.Lin@Sun.COM struct ath9k_channel *ichan = 611*9999SWang.Lin@Sun.COM ath9k_regd_check_channel(ah, chan); 612*9999SWang.Lin@Sun.COM struct hal_cal_list *currCal = ahp->ah_cal_list_curr; 613*9999SWang.Lin@Sun.COM 614*9999SWang.Lin@Sun.COM *isCalDone = B_TRUE; 615*9999SWang.Lin@Sun.COM 616*9999SWang.Lin@Sun.COM if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) 617*9999SWang.Lin@Sun.COM return; 618*9999SWang.Lin@Sun.COM 619*9999SWang.Lin@Sun.COM if (currCal == NULL) 620*9999SWang.Lin@Sun.COM return; 621*9999SWang.Lin@Sun.COM 622*9999SWang.Lin@Sun.COM if (ichan == NULL) { 623*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 624*9999SWang.Lin@Sun.COM "%s: invalid channel %u/0x%x; no mapping\n", 625*9999SWang.Lin@Sun.COM __func__, chan->channel, chan->channelFlags)); 626*9999SWang.Lin@Sun.COM return; 627*9999SWang.Lin@Sun.COM } 628*9999SWang.Lin@Sun.COM 629*9999SWang.Lin@Sun.COM 630*9999SWang.Lin@Sun.COM if (currCal->calState != CAL_DONE) { 631*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 632*9999SWang.Lin@Sun.COM "%s: Calibration state incorrect, %d\n", 633*9999SWang.Lin@Sun.COM __func__, currCal->calState)); 634*9999SWang.Lin@Sun.COM return; 635*9999SWang.Lin@Sun.COM } 636*9999SWang.Lin@Sun.COM 637*9999SWang.Lin@Sun.COM 638*9999SWang.Lin@Sun.COM if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) 639*9999SWang.Lin@Sun.COM return; 640*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 641*9999SWang.Lin@Sun.COM "%s: Resetting Cal %d state for channel %u/0x%x\n", 642*9999SWang.Lin@Sun.COM __func__, currCal->calData->calType, chan->channel, 643*9999SWang.Lin@Sun.COM chan->channelFlags)); 644*9999SWang.Lin@Sun.COM 645*9999SWang.Lin@Sun.COM ichan->CalValid &= ~currCal->calData->calType; 646*9999SWang.Lin@Sun.COM currCal->calState = CAL_WAITING; 647*9999SWang.Lin@Sun.COM 648*9999SWang.Lin@Sun.COM *isCalDone = B_FALSE; 649*9999SWang.Lin@Sun.COM } 650*9999SWang.Lin@Sun.COM 651*9999SWang.Lin@Sun.COM void 652*9999SWang.Lin@Sun.COM ath9k_hw_start_nfcal(struct ath_hal *ah) 653*9999SWang.Lin@Sun.COM { 654*9999SWang.Lin@Sun.COM REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 655*9999SWang.Lin@Sun.COM AR_PHY_AGC_CONTROL_ENABLE_NF); 656*9999SWang.Lin@Sun.COM REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 657*9999SWang.Lin@Sun.COM AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 658*9999SWang.Lin@Sun.COM REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 659*9999SWang.Lin@Sun.COM } 660*9999SWang.Lin@Sun.COM 661*9999SWang.Lin@Sun.COM /* ARGSUSED */ 662*9999SWang.Lin@Sun.COM void 663*9999SWang.Lin@Sun.COM ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) 664*9999SWang.Lin@Sun.COM { 665*9999SWang.Lin@Sun.COM struct ath9k_nfcal_hist *h; 666*9999SWang.Lin@Sun.COM int i, j; 667*9999SWang.Lin@Sun.COM int32_t val; 668*9999SWang.Lin@Sun.COM const uint32_t ar5416_cca_regs[6] = { 669*9999SWang.Lin@Sun.COM AR_PHY_CCA, 670*9999SWang.Lin@Sun.COM AR_PHY_CH1_CCA, 671*9999SWang.Lin@Sun.COM AR_PHY_CH2_CCA, 672*9999SWang.Lin@Sun.COM AR_PHY_EXT_CCA, 673*9999SWang.Lin@Sun.COM AR_PHY_CH1_EXT_CCA, 674*9999SWang.Lin@Sun.COM AR_PHY_CH2_EXT_CCA 675*9999SWang.Lin@Sun.COM }; 676*9999SWang.Lin@Sun.COM uint8_t chainmask; 677*9999SWang.Lin@Sun.COM 678*9999SWang.Lin@Sun.COM if (AR_SREV_9280(ah)) 679*9999SWang.Lin@Sun.COM chainmask = 0x1B; 680*9999SWang.Lin@Sun.COM else 681*9999SWang.Lin@Sun.COM chainmask = 0x3F; 682*9999SWang.Lin@Sun.COM 683*9999SWang.Lin@Sun.COM #ifdef ARN_NF_PER_CHAN 684*9999SWang.Lin@Sun.COM h = chan->nfCalHist; 685*9999SWang.Lin@Sun.COM #else 686*9999SWang.Lin@Sun.COM h = ah->nfCalHist; 687*9999SWang.Lin@Sun.COM #endif 688*9999SWang.Lin@Sun.COM 689*9999SWang.Lin@Sun.COM for (i = 0; i < NUM_NF_READINGS; i++) { 690*9999SWang.Lin@Sun.COM if (chainmask & (1 << i)) { 691*9999SWang.Lin@Sun.COM val = REG_READ(ah, ar5416_cca_regs[i]); 692*9999SWang.Lin@Sun.COM val &= 0xFFFFFE00; 693*9999SWang.Lin@Sun.COM val |= (((uint32_t)(h[i].privNF) << 1) & 0x1ff); 694*9999SWang.Lin@Sun.COM REG_WRITE(ah, ar5416_cca_regs[i], val); 695*9999SWang.Lin@Sun.COM } 696*9999SWang.Lin@Sun.COM } 697*9999SWang.Lin@Sun.COM 698*9999SWang.Lin@Sun.COM REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 699*9999SWang.Lin@Sun.COM AR_PHY_AGC_CONTROL_ENABLE_NF); 700*9999SWang.Lin@Sun.COM REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 701*9999SWang.Lin@Sun.COM AR_PHY_AGC_CONTROL_NO_UPDATE_NF); 702*9999SWang.Lin@Sun.COM REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 703*9999SWang.Lin@Sun.COM 704*9999SWang.Lin@Sun.COM for (j = 0; j < 1000; j++) { 705*9999SWang.Lin@Sun.COM if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & 706*9999SWang.Lin@Sun.COM AR_PHY_AGC_CONTROL_NF) == 0) 707*9999SWang.Lin@Sun.COM break; 708*9999SWang.Lin@Sun.COM drv_usecwait(10); 709*9999SWang.Lin@Sun.COM } 710*9999SWang.Lin@Sun.COM 711*9999SWang.Lin@Sun.COM for (i = 0; i < NUM_NF_READINGS; i++) { 712*9999SWang.Lin@Sun.COM if (chainmask & (1 << i)) { 713*9999SWang.Lin@Sun.COM val = REG_READ(ah, ar5416_cca_regs[i]); 714*9999SWang.Lin@Sun.COM val &= 0xFFFFFE00; 715*9999SWang.Lin@Sun.COM val |= (((uint32_t)(-50) << 1) & 0x1ff); 716*9999SWang.Lin@Sun.COM REG_WRITE(ah, ar5416_cca_regs[i], val); 717*9999SWang.Lin@Sun.COM } 718*9999SWang.Lin@Sun.COM } 719*9999SWang.Lin@Sun.COM } 720*9999SWang.Lin@Sun.COM 721*9999SWang.Lin@Sun.COM int16_t 722*9999SWang.Lin@Sun.COM ath9k_hw_getnf(struct ath_hal *ah, struct ath9k_channel *chan) 723*9999SWang.Lin@Sun.COM { 724*9999SWang.Lin@Sun.COM int16_t nf, nfThresh; 725*9999SWang.Lin@Sun.COM int16_t nfarray[NUM_NF_READINGS] = { 0 }; 726*9999SWang.Lin@Sun.COM struct ath9k_nfcal_hist *h; 727*9999SWang.Lin@Sun.COM /* LINTED E_FUNC_SET_NOT_USED */ 728*9999SWang.Lin@Sun.COM uint8_t chainmask; 729*9999SWang.Lin@Sun.COM 730*9999SWang.Lin@Sun.COM if (AR_SREV_9280(ah)) 731*9999SWang.Lin@Sun.COM chainmask = 0x1B; 732*9999SWang.Lin@Sun.COM else 733*9999SWang.Lin@Sun.COM chainmask = 0x3F; 734*9999SWang.Lin@Sun.COM 735*9999SWang.Lin@Sun.COM chan->channelFlags &= (~CHANNEL_CW_INT); 736*9999SWang.Lin@Sun.COM if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 737*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, "arn: " 738*9999SWang.Lin@Sun.COM "%s: NF did not complete in calibration window\n", 739*9999SWang.Lin@Sun.COM __func__)); 740*9999SWang.Lin@Sun.COM nf = 0; 741*9999SWang.Lin@Sun.COM chan->rawNoiseFloor = nf; 742*9999SWang.Lin@Sun.COM return (chan->rawNoiseFloor); 743*9999SWang.Lin@Sun.COM } else { 744*9999SWang.Lin@Sun.COM ath9k_hw_do_getnf(ah, nfarray); 745*9999SWang.Lin@Sun.COM nf = nfarray[0]; 746*9999SWang.Lin@Sun.COM if (getNoiseFloorThresh(ah, chan, &nfThresh) && 747*9999SWang.Lin@Sun.COM nf > nfThresh) { 748*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, "arn: " 749*9999SWang.Lin@Sun.COM "%s: noise floor failed detected; " 750*9999SWang.Lin@Sun.COM "detected %d, threshold %d\n", __func__, 751*9999SWang.Lin@Sun.COM nf, nfThresh)); 752*9999SWang.Lin@Sun.COM chan->channelFlags |= CHANNEL_CW_INT; 753*9999SWang.Lin@Sun.COM } 754*9999SWang.Lin@Sun.COM } 755*9999SWang.Lin@Sun.COM 756*9999SWang.Lin@Sun.COM #ifdef ARN_NF_PER_CHAN 757*9999SWang.Lin@Sun.COM h = chan->nfCalHist; 758*9999SWang.Lin@Sun.COM #else 759*9999SWang.Lin@Sun.COM h = ah->nfCalHist; 760*9999SWang.Lin@Sun.COM #endif 761*9999SWang.Lin@Sun.COM 762*9999SWang.Lin@Sun.COM ath9k_hw_update_nfcal_hist_buffer(h, nfarray); 763*9999SWang.Lin@Sun.COM chan->rawNoiseFloor = h[0].privNF; 764*9999SWang.Lin@Sun.COM 765*9999SWang.Lin@Sun.COM return (chan->rawNoiseFloor); 766*9999SWang.Lin@Sun.COM } 767*9999SWang.Lin@Sun.COM 768*9999SWang.Lin@Sun.COM void 769*9999SWang.Lin@Sun.COM ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) 770*9999SWang.Lin@Sun.COM { 771*9999SWang.Lin@Sun.COM int i, j; 772*9999SWang.Lin@Sun.COM 773*9999SWang.Lin@Sun.COM for (i = 0; i < NUM_NF_READINGS; i++) { 774*9999SWang.Lin@Sun.COM ah->nfCalHist[i].currIndex = 0; 775*9999SWang.Lin@Sun.COM ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; 776*9999SWang.Lin@Sun.COM ah->nfCalHist[i].invalidNFcount = 777*9999SWang.Lin@Sun.COM AR_PHY_CCA_FILTERWINDOW_LENGTH; 778*9999SWang.Lin@Sun.COM for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { 779*9999SWang.Lin@Sun.COM ah->nfCalHist[i].nfCalBuffer[j] = 780*9999SWang.Lin@Sun.COM AR_PHY_CCA_MAX_GOOD_VALUE; 781*9999SWang.Lin@Sun.COM } 782*9999SWang.Lin@Sun.COM } 783*9999SWang.Lin@Sun.COM } 784*9999SWang.Lin@Sun.COM 785*9999SWang.Lin@Sun.COM signed short 786*9999SWang.Lin@Sun.COM ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) 787*9999SWang.Lin@Sun.COM { 788*9999SWang.Lin@Sun.COM struct ath9k_channel *ichan; 789*9999SWang.Lin@Sun.COM signed short nf; 790*9999SWang.Lin@Sun.COM 791*9999SWang.Lin@Sun.COM ichan = ath9k_regd_check_channel(ah, chan); 792*9999SWang.Lin@Sun.COM if (ichan == NULL) { 793*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 794*9999SWang.Lin@Sun.COM "%s: invalid channel %u/0x%x; no mapping\n", 795*9999SWang.Lin@Sun.COM __func__, chan->channel, chan->channelFlags)); 796*9999SWang.Lin@Sun.COM return (ATH_DEFAULT_NOISE_FLOOR); 797*9999SWang.Lin@Sun.COM } 798*9999SWang.Lin@Sun.COM if (ichan->rawNoiseFloor == 0) { 799*9999SWang.Lin@Sun.COM enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); 800*9999SWang.Lin@Sun.COM nf = NOISE_FLOOR[mode]; 801*9999SWang.Lin@Sun.COM } else 802*9999SWang.Lin@Sun.COM nf = ichan->rawNoiseFloor; 803*9999SWang.Lin@Sun.COM 804*9999SWang.Lin@Sun.COM if (!ath9k_hw_nf_in_range(ah, nf)) 805*9999SWang.Lin@Sun.COM nf = ATH_DEFAULT_NOISE_FLOOR; 806*9999SWang.Lin@Sun.COM 807*9999SWang.Lin@Sun.COM return (nf); 808*9999SWang.Lin@Sun.COM } 809*9999SWang.Lin@Sun.COM 810*9999SWang.Lin@Sun.COM boolean_t 811*9999SWang.Lin@Sun.COM ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, 812*9999SWang.Lin@Sun.COM uint8_t rxchainmask, boolean_t longcal, 813*9999SWang.Lin@Sun.COM boolean_t *isCalDone) 814*9999SWang.Lin@Sun.COM { 815*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 816*9999SWang.Lin@Sun.COM struct hal_cal_list *currCal = ahp->ah_cal_list_curr; 817*9999SWang.Lin@Sun.COM struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); 818*9999SWang.Lin@Sun.COM 819*9999SWang.Lin@Sun.COM *isCalDone = B_TRUE; 820*9999SWang.Lin@Sun.COM 821*9999SWang.Lin@Sun.COM if (ichan == NULL) { 822*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CHANNEL, 823*9999SWang.Lin@Sun.COM "%s: invalid channel %u/0x%x; no mapping\n", 824*9999SWang.Lin@Sun.COM __func__, chan->channel, chan->channelFlags)); 825*9999SWang.Lin@Sun.COM return (B_FALSE); 826*9999SWang.Lin@Sun.COM } 827*9999SWang.Lin@Sun.COM 828*9999SWang.Lin@Sun.COM if (currCal && 829*9999SWang.Lin@Sun.COM (currCal->calState == CAL_RUNNING || 830*9999SWang.Lin@Sun.COM currCal->calState == CAL_WAITING)) { 831*9999SWang.Lin@Sun.COM ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, 832*9999SWang.Lin@Sun.COM isCalDone); 833*9999SWang.Lin@Sun.COM if (*isCalDone) { 834*9999SWang.Lin@Sun.COM ahp->ah_cal_list_curr = currCal = currCal->calNext; 835*9999SWang.Lin@Sun.COM 836*9999SWang.Lin@Sun.COM if (currCal->calState == CAL_WAITING) { 837*9999SWang.Lin@Sun.COM *isCalDone = B_FALSE; 838*9999SWang.Lin@Sun.COM ath9k_hw_reset_calibration(ah, currCal); 839*9999SWang.Lin@Sun.COM } 840*9999SWang.Lin@Sun.COM } 841*9999SWang.Lin@Sun.COM } 842*9999SWang.Lin@Sun.COM 843*9999SWang.Lin@Sun.COM if (longcal) { 844*9999SWang.Lin@Sun.COM (void) ath9k_hw_getnf(ah, ichan); 845*9999SWang.Lin@Sun.COM ath9k_hw_loadnf(ah, ah->ah_curchan); 846*9999SWang.Lin@Sun.COM ath9k_hw_start_nfcal(ah); 847*9999SWang.Lin@Sun.COM 848*9999SWang.Lin@Sun.COM if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { 849*9999SWang.Lin@Sun.COM chan->channelFlags |= CHANNEL_CW_INT; 850*9999SWang.Lin@Sun.COM ichan->channelFlags &= ~CHANNEL_CW_INT; 851*9999SWang.Lin@Sun.COM } 852*9999SWang.Lin@Sun.COM } 853*9999SWang.Lin@Sun.COM 854*9999SWang.Lin@Sun.COM return (B_TRUE); 855*9999SWang.Lin@Sun.COM } 856*9999SWang.Lin@Sun.COM 857*9999SWang.Lin@Sun.COM /* AR9285 */ 858*9999SWang.Lin@Sun.COM static inline void 859*9999SWang.Lin@Sun.COM ath9k_hw_9285_pa_cal(struct ath_hal *ah) 860*9999SWang.Lin@Sun.COM { 861*9999SWang.Lin@Sun.COM 862*9999SWang.Lin@Sun.COM uint32_t regVal; 863*9999SWang.Lin@Sun.COM int i, offset, offs_6_1, offs_0; 864*9999SWang.Lin@Sun.COM uint32_t ccomp_org, reg_field; 865*9999SWang.Lin@Sun.COM uint32_t regList[][2] = { 866*9999SWang.Lin@Sun.COM { 0x786c, 0 }, 867*9999SWang.Lin@Sun.COM { 0x7854, 0 }, 868*9999SWang.Lin@Sun.COM { 0x7820, 0 }, 869*9999SWang.Lin@Sun.COM { 0x7824, 0 }, 870*9999SWang.Lin@Sun.COM { 0x7868, 0 }, 871*9999SWang.Lin@Sun.COM { 0x783c, 0 }, 872*9999SWang.Lin@Sun.COM { 0x7838, 0 }, 873*9999SWang.Lin@Sun.COM }; 874*9999SWang.Lin@Sun.COM 875*9999SWang.Lin@Sun.COM if (AR_SREV_9285_11(ah)) { 876*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); 877*9999SWang.Lin@Sun.COM drv_usecwait(10); 878*9999SWang.Lin@Sun.COM } 879*9999SWang.Lin@Sun.COM 880*9999SWang.Lin@Sun.COM for (i = 0; i < ARRAY_SIZE(regList); i++) 881*9999SWang.Lin@Sun.COM regList[i][1] = REG_READ(ah, regList[i][0]); 882*9999SWang.Lin@Sun.COM 883*9999SWang.Lin@Sun.COM regVal = REG_READ(ah, 0x7834); 884*9999SWang.Lin@Sun.COM regVal &= (~(0x1)); 885*9999SWang.Lin@Sun.COM REG_WRITE(ah, 0x7834, regVal); 886*9999SWang.Lin@Sun.COM regVal = REG_READ(ah, 0x9808); 887*9999SWang.Lin@Sun.COM regVal |= (0x1 << 27); 888*9999SWang.Lin@Sun.COM REG_WRITE(ah, 0x9808, regVal); 889*9999SWang.Lin@Sun.COM 890*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); 891*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); 892*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); 893*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); 894*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); 895*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); 896*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); 897*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); 898*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); 899*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); 900*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 901*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 902*9999SWang.Lin@Sun.COM ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); 903*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); 904*9999SWang.Lin@Sun.COM 905*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 906*9999SWang.Lin@Sun.COM drv_usecwait(30); 907*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); 908*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); 909*9999SWang.Lin@Sun.COM 910*9999SWang.Lin@Sun.COM for (i = 6; i > 0; i--) { 911*9999SWang.Lin@Sun.COM regVal = REG_READ(ah, 0x7834); 912*9999SWang.Lin@Sun.COM regVal |= (1 << (19 + i)); 913*9999SWang.Lin@Sun.COM REG_WRITE(ah, 0x7834, regVal); 914*9999SWang.Lin@Sun.COM drv_usecwait(1); 915*9999SWang.Lin@Sun.COM regVal = REG_READ(ah, 0x7834); 916*9999SWang.Lin@Sun.COM regVal &= (~(0x1 << (19 + i))); 917*9999SWang.Lin@Sun.COM reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); 918*9999SWang.Lin@Sun.COM regVal |= (reg_field << (19 + i)); 919*9999SWang.Lin@Sun.COM REG_WRITE(ah, 0x7834, regVal); 920*9999SWang.Lin@Sun.COM } 921*9999SWang.Lin@Sun.COM 922*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); 923*9999SWang.Lin@Sun.COM drv_usecwait(1); 924*9999SWang.Lin@Sun.COM reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); 925*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); 926*9999SWang.Lin@Sun.COM offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); 927*9999SWang.Lin@Sun.COM offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); 928*9999SWang.Lin@Sun.COM 929*9999SWang.Lin@Sun.COM offset = (offs_6_1<<1) | offs_0; 930*9999SWang.Lin@Sun.COM offset = offset - 0; 931*9999SWang.Lin@Sun.COM offs_6_1 = offset>>1; 932*9999SWang.Lin@Sun.COM offs_0 = offset & 1; 933*9999SWang.Lin@Sun.COM 934*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); 935*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); 936*9999SWang.Lin@Sun.COM 937*9999SWang.Lin@Sun.COM regVal = REG_READ(ah, 0x7834); 938*9999SWang.Lin@Sun.COM regVal |= 0x1; 939*9999SWang.Lin@Sun.COM REG_WRITE(ah, 0x7834, regVal); 940*9999SWang.Lin@Sun.COM regVal = REG_READ(ah, 0x9808); 941*9999SWang.Lin@Sun.COM regVal &= (~(0x1 << 27)); 942*9999SWang.Lin@Sun.COM REG_WRITE(ah, 0x9808, regVal); 943*9999SWang.Lin@Sun.COM 944*9999SWang.Lin@Sun.COM for (i = 0; i < ARRAY_SIZE(regList); i++) 945*9999SWang.Lin@Sun.COM REG_WRITE(ah, regList[i][0], regList[i][1]); 946*9999SWang.Lin@Sun.COM 947*9999SWang.Lin@Sun.COM REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); 948*9999SWang.Lin@Sun.COM 949*9999SWang.Lin@Sun.COM if (AR_SREV_9285_11(ah)) 950*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); 951*9999SWang.Lin@Sun.COM 952*9999SWang.Lin@Sun.COM } 953*9999SWang.Lin@Sun.COM 954*9999SWang.Lin@Sun.COM boolean_t 955*9999SWang.Lin@Sun.COM ath9k_hw_init_cal(struct ath_hal *ah, 956*9999SWang.Lin@Sun.COM struct ath9k_channel *chan) 957*9999SWang.Lin@Sun.COM { 958*9999SWang.Lin@Sun.COM struct ath_hal_5416 *ahp = AH5416(ah); 959*9999SWang.Lin@Sun.COM struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); 960*9999SWang.Lin@Sun.COM 961*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_AGC_CONTROL, 962*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_AGC_CONTROL) | 963*9999SWang.Lin@Sun.COM AR_PHY_AGC_CONTROL_CAL); 964*9999SWang.Lin@Sun.COM 965*9999SWang.Lin@Sun.COM if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { 966*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 967*9999SWang.Lin@Sun.COM "%s: offset calibration failed to complete in 1ms; " 968*9999SWang.Lin@Sun.COM "noisy environment?\n", __func__)); 969*9999SWang.Lin@Sun.COM return (B_FALSE); 970*9999SWang.Lin@Sun.COM } 971*9999SWang.Lin@Sun.COM 972*9999SWang.Lin@Sun.COM if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) 973*9999SWang.Lin@Sun.COM ath9k_hw_9285_pa_cal(ah); 974*9999SWang.Lin@Sun.COM 975*9999SWang.Lin@Sun.COM REG_WRITE(ah, AR_PHY_AGC_CONTROL, 976*9999SWang.Lin@Sun.COM REG_READ(ah, AR_PHY_AGC_CONTROL) | 977*9999SWang.Lin@Sun.COM AR_PHY_AGC_CONTROL_NF); 978*9999SWang.Lin@Sun.COM 979*9999SWang.Lin@Sun.COM ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; 980*9999SWang.Lin@Sun.COM 981*9999SWang.Lin@Sun.COM if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { 982*9999SWang.Lin@Sun.COM if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { 983*9999SWang.Lin@Sun.COM /* LINTED: E_CONSTANT_CONDITION */ 984*9999SWang.Lin@Sun.COM INIT_CAL(&ahp->ah_adcGainCalData); 985*9999SWang.Lin@Sun.COM /* LINTED: E_CONSTANT_CONDITION */ 986*9999SWang.Lin@Sun.COM INSERT_CAL(ahp, &ahp->ah_adcGainCalData); 987*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 988*9999SWang.Lin@Sun.COM "%s: enabling ADC Gain Calibration.\n", 989*9999SWang.Lin@Sun.COM __func__)); 990*9999SWang.Lin@Sun.COM } 991*9999SWang.Lin@Sun.COM if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { 992*9999SWang.Lin@Sun.COM /* LINTED: E_CONSTANT_CONDITION */ 993*9999SWang.Lin@Sun.COM INIT_CAL(&ahp->ah_adcDcCalData); 994*9999SWang.Lin@Sun.COM /* LINTED: E_CONSTANT_CONDITION */ 995*9999SWang.Lin@Sun.COM INSERT_CAL(ahp, &ahp->ah_adcDcCalData); 996*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 997*9999SWang.Lin@Sun.COM "%s: enabling ADC DC Calibration.\n", 998*9999SWang.Lin@Sun.COM __func__)); 999*9999SWang.Lin@Sun.COM } 1000*9999SWang.Lin@Sun.COM if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { 1001*9999SWang.Lin@Sun.COM /* LINTED: E_CONSTANT_CONDITION */ 1002*9999SWang.Lin@Sun.COM INIT_CAL(&ahp->ah_iqCalData); 1003*9999SWang.Lin@Sun.COM /* LINTED: E_CONSTANT_CONDITION */ 1004*9999SWang.Lin@Sun.COM INSERT_CAL(ahp, &ahp->ah_iqCalData); 1005*9999SWang.Lin@Sun.COM ARN_DBG((ARN_DBG_CALIBRATE, 1006*9999SWang.Lin@Sun.COM "%s: enabling IQ Calibration.\n", 1007*9999SWang.Lin@Sun.COM __func__)); 1008*9999SWang.Lin@Sun.COM } 1009*9999SWang.Lin@Sun.COM 1010*9999SWang.Lin@Sun.COM ahp->ah_cal_list_curr = ahp->ah_cal_list; 1011*9999SWang.Lin@Sun.COM 1012*9999SWang.Lin@Sun.COM if (ahp->ah_cal_list_curr) 1013*9999SWang.Lin@Sun.COM ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr); 1014*9999SWang.Lin@Sun.COM } 1015*9999SWang.Lin@Sun.COM 1016*9999SWang.Lin@Sun.COM ichan->CalValid = 0; 1017*9999SWang.Lin@Sun.COM 1018*9999SWang.Lin@Sun.COM return (B_TRUE); 1019*9999SWang.Lin@Sun.COM } 1020*9999SWang.Lin@Sun.COM 1021*9999SWang.Lin@Sun.COM const struct hal_percal_data iq_cal_multi_sample = { 1022*9999SWang.Lin@Sun.COM IQ_MISMATCH_CAL, 1023*9999SWang.Lin@Sun.COM MAX_CAL_SAMPLES, 1024*9999SWang.Lin@Sun.COM PER_MIN_LOG_COUNT, 1025*9999SWang.Lin@Sun.COM ath9k_hw_iqcal_collect, 1026*9999SWang.Lin@Sun.COM ath9k_hw_iqcalibrate 1027*9999SWang.Lin@Sun.COM }; 1028*9999SWang.Lin@Sun.COM const struct hal_percal_data iq_cal_single_sample = { 1029*9999SWang.Lin@Sun.COM IQ_MISMATCH_CAL, 1030*9999SWang.Lin@Sun.COM MIN_CAL_SAMPLES, 1031*9999SWang.Lin@Sun.COM PER_MAX_LOG_COUNT, 1032*9999SWang.Lin@Sun.COM ath9k_hw_iqcal_collect, 1033*9999SWang.Lin@Sun.COM ath9k_hw_iqcalibrate 1034*9999SWang.Lin@Sun.COM }; 1035*9999SWang.Lin@Sun.COM const struct hal_percal_data adc_gain_cal_multi_sample = { 1036*9999SWang.Lin@Sun.COM ADC_GAIN_CAL, 1037*9999SWang.Lin@Sun.COM MAX_CAL_SAMPLES, 1038*9999SWang.Lin@Sun.COM PER_MIN_LOG_COUNT, 1039*9999SWang.Lin@Sun.COM ath9k_hw_adc_gaincal_collect, 1040*9999SWang.Lin@Sun.COM ath9k_hw_adc_gaincal_calibrate 1041*9999SWang.Lin@Sun.COM }; 1042*9999SWang.Lin@Sun.COM const struct hal_percal_data adc_gain_cal_single_sample = { 1043*9999SWang.Lin@Sun.COM ADC_GAIN_CAL, 1044*9999SWang.Lin@Sun.COM MIN_CAL_SAMPLES, 1045*9999SWang.Lin@Sun.COM PER_MAX_LOG_COUNT, 1046*9999SWang.Lin@Sun.COM ath9k_hw_adc_gaincal_collect, 1047*9999SWang.Lin@Sun.COM ath9k_hw_adc_gaincal_calibrate 1048*9999SWang.Lin@Sun.COM }; 1049*9999SWang.Lin@Sun.COM const struct hal_percal_data adc_dc_cal_multi_sample = { 1050*9999SWang.Lin@Sun.COM ADC_DC_CAL, 1051*9999SWang.Lin@Sun.COM MAX_CAL_SAMPLES, 1052*9999SWang.Lin@Sun.COM PER_MIN_LOG_COUNT, 1053*9999SWang.Lin@Sun.COM ath9k_hw_adc_dccal_collect, 1054*9999SWang.Lin@Sun.COM ath9k_hw_adc_dccal_calibrate 1055*9999SWang.Lin@Sun.COM }; 1056*9999SWang.Lin@Sun.COM const struct hal_percal_data adc_dc_cal_single_sample = { 1057*9999SWang.Lin@Sun.COM ADC_DC_CAL, 1058*9999SWang.Lin@Sun.COM MIN_CAL_SAMPLES, 1059*9999SWang.Lin@Sun.COM PER_MAX_LOG_COUNT, 1060*9999SWang.Lin@Sun.COM ath9k_hw_adc_dccal_collect, 1061*9999SWang.Lin@Sun.COM ath9k_hw_adc_dccal_calibrate 1062*9999SWang.Lin@Sun.COM }; 1063*9999SWang.Lin@Sun.COM const struct hal_percal_data adc_init_dc_cal = { 1064*9999SWang.Lin@Sun.COM ADC_DC_INIT_CAL, 1065*9999SWang.Lin@Sun.COM MIN_CAL_SAMPLES, 1066*9999SWang.Lin@Sun.COM INIT_LOG_COUNT, 1067*9999SWang.Lin@Sun.COM ath9k_hw_adc_dccal_collect, 1068*9999SWang.Lin@Sun.COM ath9k_hw_adc_dccal_calibrate 1069*9999SWang.Lin@Sun.COM }; 1070