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