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 #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 #include "ar9002/ar9285an.h" 40 41 #include "ar9002/ar9285_cal.h" 42 43 #define AR9285_CLCAL_REDO_THRESH 1 44 #define MAX_PACAL_SKIPCOUNT 8 45 46 #define N(a) (sizeof (a) / sizeof (a[0])) 47 48 static void 49 ar9285_hw_pa_cal(struct ath_hal *ah, HAL_BOOL is_reset) 50 { 51 uint32_t regVal; 52 int i, offset, offs_6_1, offs_0; 53 uint32_t ccomp_org, reg_field; 54 uint32_t regList[][2] = { 55 { 0x786c, 0 }, 56 { 0x7854, 0 }, 57 { 0x7820, 0 }, 58 { 0x7824, 0 }, 59 { 0x7868, 0 }, 60 { 0x783c, 0 }, 61 { 0x7838, 0 }, 62 }; 63 64 /* PA CAL is not needed for high power solution */ 65 if (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL) == 66 AR5416_EEP_TXGAIN_HIGH_POWER) 67 return; 68 69 HALDEBUG(ah, HAL_DEBUG_PERCAL, "Running PA Calibration\n"); 70 71 for (i = 0; i < N(regList); i++) 72 regList[i][1] = OS_REG_READ(ah, regList[i][0]); 73 74 regVal = OS_REG_READ(ah, 0x7834); 75 regVal &= (~(0x1)); 76 OS_REG_WRITE(ah, 0x7834, regVal); 77 regVal = OS_REG_READ(ah, 0x9808); 78 regVal |= (0x1 << 27); 79 OS_REG_WRITE(ah, 0x9808, regVal); 80 81 OS_REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); 82 OS_REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); 83 OS_REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); 84 OS_REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); 85 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); 86 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); 87 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); 88 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); 89 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); 90 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); 91 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 92 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 93 ccomp_org = MS(OS_REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); 94 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); 95 96 OS_REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 97 OS_DELAY(30); 98 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); 99 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); 100 101 for (i = 6; i > 0; i--) { 102 regVal = OS_REG_READ(ah, 0x7834); 103 regVal |= (1 << (19 + i)); 104 OS_REG_WRITE(ah, 0x7834, regVal); 105 OS_DELAY(1); 106 regVal = OS_REG_READ(ah, 0x7834); 107 regVal &= (~(0x1 << (19 + i))); 108 reg_field = MS(OS_REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); 109 regVal |= (reg_field << (19 + i)); 110 OS_REG_WRITE(ah, 0x7834, regVal); 111 } 112 113 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); 114 OS_DELAY(1); 115 reg_field = MS(OS_REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); 116 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); 117 offs_6_1 = MS(OS_REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); 118 offs_0 = MS(OS_REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); 119 120 offset = (offs_6_1<<1) | offs_0; 121 offset = offset - 0; 122 offs_6_1 = offset>>1; 123 offs_0 = offset & 1; 124 125 if ((!is_reset) && (AH9285(ah)->pacal_info.prev_offset == offset)) { 126 if (AH9285(ah)->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) 127 AH9285(ah)->pacal_info.max_skipcount = 128 2 * AH9285(ah)->pacal_info.max_skipcount; 129 AH9285(ah)->pacal_info.skipcount = AH9285(ah)->pacal_info.max_skipcount; 130 } else { 131 AH9285(ah)->pacal_info.max_skipcount = 1; 132 AH9285(ah)->pacal_info.skipcount = 0; 133 AH9285(ah)->pacal_info.prev_offset = offset; 134 } 135 136 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); 137 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); 138 139 regVal = OS_REG_READ(ah, 0x7834); 140 regVal |= 0x1; 141 OS_REG_WRITE(ah, 0x7834, regVal); 142 regVal = OS_REG_READ(ah, 0x9808); 143 regVal &= (~(0x1 << 27)); 144 OS_REG_WRITE(ah, 0x9808, regVal); 145 146 for (i = 0; i < N(regList); i++) 147 OS_REG_WRITE(ah, regList[i][0], regList[i][1]); 148 149 OS_REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); 150 } 151 152 void 153 ar9002_hw_pa_cal(struct ath_hal *ah, HAL_BOOL is_reset) 154 { 155 if (AR_SREV_KITE_11_OR_LATER(ah)) { 156 if (is_reset || !AH9285(ah)->pacal_info.skipcount) 157 ar9285_hw_pa_cal(ah, is_reset); 158 else 159 AH9285(ah)->pacal_info.skipcount--; 160 } 161 } 162 163 /* Carrier leakage Calibration fix */ 164 static HAL_BOOL 165 ar9285_hw_cl_cal(struct ath_hal *ah, const struct ieee80211_channel *chan) 166 { 167 OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 168 if (IEEE80211_IS_CHAN_HT20(chan)) { 169 OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 170 OS_REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 171 OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 172 AR_PHY_AGC_CONTROL_FLTR_CAL); 173 OS_REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 174 OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 175 if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, 176 AR_PHY_AGC_CONTROL_CAL, 0)) { 177 HALDEBUG(ah, HAL_DEBUG_PERCAL, 178 "offset calibration failed to complete in 1ms; noisy environment?\n"); 179 return AH_FALSE; 180 } 181 OS_REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 182 OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 183 OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 184 } 185 OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 186 OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 187 OS_REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 188 OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 189 if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 190 0)) { 191 HALDEBUG(ah, HAL_DEBUG_PERCAL, 192 "offset calibration failed to complete in 1ms; noisy environment?\n"); 193 return AH_FALSE; 194 } 195 196 OS_REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 197 OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 198 OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 199 200 return AH_TRUE; 201 } 202 203 static HAL_BOOL 204 ar9285_hw_clc(struct ath_hal *ah, const struct ieee80211_channel *chan) 205 { 206 int i; 207 uint32_t txgain_max; 208 uint32_t clc_gain, gain_mask = 0, clc_num = 0; 209 uint32_t reg_clc_I0, reg_clc_Q0; 210 uint32_t i0_num = 0; 211 uint32_t q0_num = 0; 212 uint32_t total_num = 0; 213 uint32_t reg_rf2g5_org; 214 HAL_BOOL retv = AH_TRUE; 215 216 if (!(ar9285_hw_cl_cal(ah, chan))) 217 return AH_FALSE; 218 219 txgain_max = MS(OS_REG_READ(ah, AR_PHY_TX_PWRCTRL7), 220 AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); 221 222 for (i = 0; i < (txgain_max+1); i++) { 223 clc_gain = (OS_REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) & 224 AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S; 225 if (!(gain_mask & (1 << clc_gain))) { 226 gain_mask |= (1 << clc_gain); 227 clc_num++; 228 } 229 } 230 231 for (i = 0; i < clc_num; i++) { 232 reg_clc_I0 = (OS_REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 233 & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S; 234 reg_clc_Q0 = (OS_REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 235 & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S; 236 if (reg_clc_I0 == 0) 237 i0_num++; 238 239 if (reg_clc_Q0 == 0) 240 q0_num++; 241 } 242 total_num = i0_num + q0_num; 243 if (total_num > AR9285_CLCAL_REDO_THRESH) { 244 reg_rf2g5_org = OS_REG_READ(ah, AR9285_RF2G5); 245 if (AR_SREV_9285E_20(ah)) { 246 OS_REG_WRITE(ah, AR9285_RF2G5, 247 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 248 AR9285_RF2G5_IC50TX_XE_SET); 249 } else { 250 OS_REG_WRITE(ah, AR9285_RF2G5, 251 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 252 AR9285_RF2G5_IC50TX_SET); 253 } 254 retv = ar9285_hw_cl_cal(ah, chan); 255 OS_REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org); 256 } 257 return retv; 258 } 259 260 HAL_BOOL 261 ar9285InitCalHardware(struct ath_hal *ah, 262 const struct ieee80211_channel *chan) 263 { 264 if (AR_SREV_KITE(ah) && AR_SREV_KITE_10_OR_LATER(ah) && 265 (! ar9285_hw_clc(ah, chan))) 266 return AH_FALSE; 267 268 return AH_TRUE; 269 } 270