ar9285_cal.c revision 221806
1206376Srpaulo/* 2206376Srpaulo * Copyright (c) 2008-2010 Atheros Communications Inc. 3206376Srpaulo * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd. 4206376Srpaulo * 5206376Srpaulo * Redistribution and use in source and binary forms, with or without 6206376Srpaulo * modification, are permitted provided that the following conditions 7255944Sbdrewery * are met: 8206376Srpaulo * 1. Redistributions of source code must retain the above copyright 9206376Srpaulo * notice, this list of conditions and the following disclaimer. 10206376Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11206376Srpaulo * notice, this list of conditions and the following disclaimer in the 12206376Srpaulo * documentation and/or other materials provided with the distribution. 13206376Srpaulo * 14206376Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15206376Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16206376Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17206376Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18206376Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19206376Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20206376Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21206376Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22206376Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23206376Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24206376Srpaulo * SUCH DAMAGE. 25206376Srpaulo * 26206376Srpaulo * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c 221806 2011-05-12 10:11:24Z adrian $ 27206376Srpaulo */ 28206376Srpaulo#include "opt_ah.h" 29206376Srpaulo#include "ah.h" 30206376Srpaulo#include "ah_internal.h" 31206376Srpaulo 32206376Srpaulo#include "ah_eeprom_v4k.h" 33206376Srpaulo 34206376Srpaulo#include "ar9002/ar9285.h" 35206376Srpaulo#include "ar5416/ar5416reg.h" 36206376Srpaulo#include "ar5416/ar5416phy.h" 37206376Srpaulo#include "ar9002/ar9002phy.h" 38234493Smarcel#include "ar9002/ar9285phy.h" 39245765Sbenno#include "ar9002/ar9285an.h" 40206376Srpaulo 41206376Srpaulo#include "ar9002/ar9285_cal.h" 42206376Srpaulo 43206376Srpaulo#define AR9285_CLCAL_REDO_THRESH 1 44206376Srpaulo#define MAX_PACAL_SKIPCOUNT 8 45212066Sdelphij 46206376Srpaulo#define N(a) (sizeof (a) / sizeof (a[0])) 47206376Srpaulo 48206376Srpaulostatic void 49206376Srpauloar9285_hw_pa_cal(struct ath_hal *ah, HAL_BOOL is_reset) 50206376Srpaulo{ 51206376Srpaulo uint32_t regVal; 52206376Srpaulo int i, offset, offs_6_1, offs_0; 53206376Srpaulo uint32_t ccomp_org, reg_field; 54206376Srpaulo uint32_t regList[][2] = { 55206376Srpaulo { 0x786c, 0 }, 56206376Srpaulo { 0x7854, 0 }, 57206376Srpaulo { 0x7820, 0 }, 58206376Srpaulo { 0x7824, 0 }, 59206376Srpaulo { 0x7868, 0 }, 60206376Srpaulo { 0x783c, 0 }, 61206376Srpaulo { 0x7838, 0 }, 62206376Srpaulo }; 63206376Srpaulo 64206376Srpaulo /* PA CAL is not needed for high power solution */ 65206376Srpaulo if (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL) == 66206376Srpaulo AR5416_EEP_TXGAIN_HIGH_POWER) 67234493Smarcel return; 68206376Srpaulo 69206376Srpaulo HALDEBUG(ah, HAL_DEBUG_PERCAL, "Running PA Calibration\n"); 70234493Smarcel 71234493Smarcel for (i = 0; i < N(regList); i++) 72234493Smarcel regList[i][1] = OS_REG_READ(ah, regList[i][0]); 73234493Smarcel 74234493Smarcel regVal = OS_REG_READ(ah, 0x7834); 75234493Smarcel regVal &= (~(0x1)); 76234493Smarcel 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 152void 153ar9002_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 */ 164static HAL_BOOL 165ar9285_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 203static HAL_BOOL 204ar9285_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 260HAL_BOOL 261ar9285InitCalHardware(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