1 /* 2 * Copyright (c) 2008-2010 Atheros Communications Inc. 3 * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 #include "opt_ah.h" 29 #include "ah.h" 30 #include "ah_internal.h" 31 32 #include "ah_eeprom_v4k.h" 33 34 #include "ar9002/ar9285.h" 35 #include "ar5416/ar5416reg.h" 36 #include "ar5416/ar5416phy.h" 37 #include "ar9002/ar9002phy.h" 38 #include "ar9002/ar9285phy.h" 39 40 #include "ar9002/ar9285_cal.h" 41 42 #define AR9285_CLCAL_REDO_THRESH 1 43 #define MAX_PACAL_SKIPCOUNT 8 44 45 #define N(a) (sizeof (a) / sizeof (a[0])) 46 47 static void 48 ar9285_hw_pa_cal(struct ath_hal *ah, HAL_BOOL is_reset) 49 { 50 uint32_t regVal; 51 int i, offset, offs_6_1, offs_0; 52 uint32_t ccomp_org, reg_field; 53 uint32_t regList[][2] = { 54 { 0x786c, 0 }, 55 { 0x7854, 0 }, 56 { 0x7820, 0 }, 57 { 0x7824, 0 }, 58 { 0x7868, 0 }, 59 { 0x783c, 0 }, 60 { 0x7838, 0 }, 61 }; 62 63 HALDEBUG(ah, HAL_DEBUG_PERCAL, "Running PA Calibration\n"); 64 65 /* PA CAL is not needed for high power solution */ 66 if (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL) == 67 AR5416_EEP_TXGAIN_HIGH_POWER) 68 return; 69 70 for (i = 0; i < N(regList); i++) 71 regList[i][1] = OS_REG_READ(ah, regList[i][0]); 72 73 regVal = OS_REG_READ(ah, 0x7834); 74 regVal &= (~(0x1)); 75 OS_REG_WRITE(ah, 0x7834, regVal); 76 regVal = OS_REG_READ(ah, 0x9808); 77 regVal |= (0x1 << 27); 78 OS_REG_WRITE(ah, 0x9808, regVal); 79 80 OS_REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); 81 OS_REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); 82 OS_REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); 83 OS_REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); 84 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); 85 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); 86 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); 87 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); 88 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); 89 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); 90 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 91 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 92 ccomp_org = MS(OS_REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); 93 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); 94 95 OS_REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 96 OS_DELAY(30); 97 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); 98 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); 99 100 for (i = 6; i > 0; i--) { 101 regVal = OS_REG_READ(ah, 0x7834); 102 regVal |= (1 << (19 + i)); 103 OS_REG_WRITE(ah, 0x7834, regVal); 104 OS_DELAY(1); 105 regVal = OS_REG_READ(ah, 0x7834); 106 regVal &= (~(0x1 << (19 + i))); 107 reg_field = MS(OS_REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); 108 regVal |= (reg_field << (19 + i)); 109 OS_REG_WRITE(ah, 0x7834, regVal); 110 } 111 112 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); 113 OS_DELAY(1); 114 reg_field = MS(OS_REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); 115 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); 116 offs_6_1 = MS(OS_REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); 117 offs_0 = MS(OS_REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); 118 119 offset = (offs_6_1<<1) | offs_0; 120 offset = offset - 0; 121 offs_6_1 = offset>>1; 122 offs_0 = offset & 1; 123 124 if ((!is_reset) && (AH9285(ah)->pacal_info.prev_offset == offset)) { 125 if (AH9285(ah)->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) 126 AH9285(ah)->pacal_info.max_skipcount = 127 2 * AH9285(ah)->pacal_info.max_skipcount; 128 AH9285(ah)->pacal_info.skipcount = AH9285(ah)->pacal_info.max_skipcount; 129 } else { 130 AH9285(ah)->pacal_info.max_skipcount = 1; 131 AH9285(ah)->pacal_info.skipcount = 0; 132 AH9285(ah)->pacal_info.prev_offset = offset; 133 } 134 135 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); 136 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); 137 138 regVal = OS_REG_READ(ah, 0x7834); 139 regVal |= 0x1; 140 OS_REG_WRITE(ah, 0x7834, regVal); 141 regVal = OS_REG_READ(ah, 0x9808); 142 regVal &= (~(0x1 << 27)); 143 OS_REG_WRITE(ah, 0x9808, regVal); 144 145 for (i = 0; i < N(regList); i++) 146 OS_REG_WRITE(ah, regList[i][0], regList[i][1]); 147 148 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); 149 } 150 151 void 152 ar9002_hw_pa_cal(struct ath_hal *ah, HAL_BOOL is_reset) 153 { 154 if (AR_SREV_KITE_12_OR_LATER(ah)) { 155 if (is_reset || !AH9285(ah)->pacal_info.skipcount) 156 ar9285_hw_pa_cal(ah, is_reset); 157 else 158 AH9285(ah)->pacal_info.skipcount--; 159 } 160 } 161 162 /* Carrier leakage Calibration fix */ 163 static HAL_BOOL 164 ar9285_hw_cl_cal(struct ath_hal *ah, const struct ieee80211_channel *chan) 165 { 166 OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 167 if (IEEE80211_IS_CHAN_HT20(chan)) { 168 OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 169 OS_REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 170 OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 171 AR_PHY_AGC_CONTROL_FLTR_CAL); 172 OS_REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 173 OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 174 if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, 175 AR_PHY_AGC_CONTROL_CAL, 0)) { 176 HALDEBUG(ah, HAL_DEBUG_PERCAL, 177 "offset calibration failed to complete in 1ms; noisy environment?\n"); 178 return AH_FALSE; 179 } 180 OS_REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 181 OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 182 OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 183 } 184 OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 185 OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 186 OS_REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 187 OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 188 if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 189 0)) { 190 HALDEBUG(ah, HAL_DEBUG_PERCAL, 191 "offset calibration failed to complete in 1ms; noisy environment?\n"); 192 return AH_FALSE; 193 } 194 195 OS_REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 196 OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 197 OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 198 199 return AH_TRUE; 200 } 201 202 static HAL_BOOL 203 ar9285_hw_clc(struct ath_hal *ah, const struct ieee80211_channel *chan) 204 { 205 int i; 206 uint32_t txgain_max; 207 uint32_t clc_gain, gain_mask = 0, clc_num = 0; 208 uint32_t reg_clc_I0, reg_clc_Q0; 209 uint32_t i0_num = 0; 210 uint32_t q0_num = 0; 211 uint32_t total_num = 0; 212 uint32_t reg_rf2g5_org; 213 HAL_BOOL retv = AH_TRUE; 214 215 if (!(ar9285_hw_cl_cal(ah, chan))) 216 return AH_FALSE; 217 218 txgain_max = MS(OS_REG_READ(ah, AR_PHY_TX_PWRCTRL7), 219 AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); 220 221 for (i = 0; i < (txgain_max+1); i++) { 222 clc_gain = (OS_REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) & 223 AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S; 224 if (!(gain_mask & (1 << clc_gain))) { 225 gain_mask |= (1 << clc_gain); 226 clc_num++; 227 } 228 } 229 230 for (i = 0; i < clc_num; i++) { 231 reg_clc_I0 = (OS_REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 232 & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S; 233 reg_clc_Q0 = (OS_REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 234 & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S; 235 if (reg_clc_I0 == 0) 236 i0_num++; 237 238 if (reg_clc_Q0 == 0) 239 q0_num++; 240 } 241 total_num = i0_num + q0_num; 242 if (total_num > AR9285_CLCAL_REDO_THRESH) { 243 reg_rf2g5_org = OS_REG_READ(ah, AR9285_RF2G5); 244 if (AR_SREV_9285E_20(ah)) { 245 OS_REG_WRITE(ah, AR9285_RF2G5, 246 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 247 AR9285_RF2G5_IC50TX_XE_SET); 248 } else { 249 OS_REG_WRITE(ah, AR9285_RF2G5, 250 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 251 AR9285_RF2G5_IC50TX_SET); 252 } 253 retv = ar9285_hw_cl_cal(ah, chan); 254 OS_REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org); 255 } 256 return retv; 257 } 258 259 HAL_BOOL 260 ar9285InitCalHardware(struct ath_hal *ah, 261 const struct ieee80211_channel *chan) 262 { 263 if (! ar9285_hw_clc(ah, chan)) 264 return AH_FALSE; 265 266 ar9285_hw_pa_cal(ah, AH_TRUE); 267 268 return AH_TRUE; 269 } 270