| 1 | /* |
| 2 | * Copyright (c) 2008-2009 Sam Leffler, Errno Consulting |
| 3 | * Copyright (c) 2008 Atheros Communications, Inc. |
| 4 | * |
| 5 | * Permission to use, copy, modify, and/or distribute this software for any |
| 6 | * purpose with or without fee is hereby granted, provided that the above |
| 7 | * copyright notice and this permission notice appear in all copies. |
| 8 | * |
| 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 16 | * |
| 17 | * $FreeBSD: src/sys/dev/ath/ath_hal/ar5416/ar9285_attach.c,v 1.5 2010/06/01 15:33:10 rpaulo Exp $ |
| 18 | */ |
| 19 | #include "opt_ah.h" |
| 20 | |
| 21 | #include "ah.h" |
| 22 | #include "ah_internal.h" |
| 23 | #include "ah_devid.h" |
| 24 | |
| 25 | #include "ah_eeprom_v4k.h" /* XXX for tx/rx gain */ |
| 26 | |
| 27 | #include "ar5416/ar9280.h" |
| 28 | #include "ar5416/ar9285.h" |
| 29 | #include "ar5416/ar5416reg.h" |
| 30 | #include "ar5416/ar5416phy.h" |
| 31 | |
| 32 | #include "ar5416/ar9285.ini" |
| 33 | #include "ar5416/ar9285v2.ini" |
| 34 | #include "ar5416/ar9280v2.ini" /* XXX ini for tx/rx gain */ |
| 35 | |
| 36 | static const HAL_PERCAL_DATA ar9280_iq_cal = { /* single sample */ |
| 37 | .calName = "IQ" , .calType = IQ_MISMATCH_CAL, |
| 38 | .calNumSamples = MIN_CAL_SAMPLES, |
| 39 | .calCountMax = PER_MAX_LOG_COUNT, |
| 40 | .calCollect = ar5416IQCalCollect, |
| 41 | .calPostProc = ar5416IQCalibration |
| 42 | }; |
| 43 | static const HAL_PERCAL_DATA ar9280_adc_gain_cal = { /* single sample */ |
| 44 | .calName = "ADC Gain" , .calType = ADC_GAIN_CAL, |
| 45 | .calNumSamples = MIN_CAL_SAMPLES, |
| 46 | .calCountMax = PER_MIN_LOG_COUNT, |
| 47 | .calCollect = ar5416AdcGainCalCollect, |
| 48 | .calPostProc = ar5416AdcGainCalibration |
| 49 | }; |
| 50 | static const HAL_PERCAL_DATA ar9280_adc_dc_cal = { /* single sample */ |
| 51 | .calName = "ADC DC" , .calType = ADC_DC_CAL, |
| 52 | .calNumSamples = MIN_CAL_SAMPLES, |
| 53 | .calCountMax = PER_MIN_LOG_COUNT, |
| 54 | .calCollect = ar5416AdcDcCalCollect, |
| 55 | .calPostProc = ar5416AdcDcCalibration |
| 56 | }; |
| 57 | static const HAL_PERCAL_DATA ar9280_adc_init_dc_cal = { |
| 58 | .calName = "ADC Init DC" , .calType = ADC_DC_INIT_CAL, |
| 59 | .calNumSamples = MIN_CAL_SAMPLES, |
| 60 | .calCountMax = INIT_LOG_COUNT, |
| 61 | .calCollect = ar5416AdcDcCalCollect, |
| 62 | .calPostProc = ar5416AdcDcCalibration |
| 63 | }; |
| 64 | |
| 65 | static void ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore); |
| 66 | static HAL_BOOL ar9285FillCapabilityInfo(struct ath_hal *ah); |
| 67 | static void ar9285WriteIni(struct ath_hal *ah, |
| 68 | HAL_CHANNEL_INTERNAL *chan); |
| 69 | |
| 70 | static void |
| 71 | ar9285AniSetup(struct ath_hal *ah) |
| 72 | { |
| 73 | /* NB: disable ANI for reliable RIFS rx */ |
| 74 | ar5212AniAttach(ah, AH_NULL, AH_NULL, AH_FALSE); |
| 75 | } |
| 76 | |
| 77 | /* |
| 78 | * Attach for an AR9285 part. |
| 79 | */ |
| 80 | static struct ath_hal * |
| 81 | ar9285Attach(uint16_t devid, HAL_SOFTC sc, |
| 82 | HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) |
| 83 | { |
| 84 | struct ath_hal_9285 *ahp9285; |
| 85 | struct ath_hal_5212 *ahp; |
| 86 | struct ath_hal *ah; |
| 87 | uint32_t val; |
| 88 | HAL_STATUS ecode; |
| 89 | HAL_BOOL rfStatus; |
| 90 | |
| 91 | HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n" , |
| 92 | __func__, sc, (void*) st, (void*) sh); |
| 93 | |
| 94 | /* NB: memory is returned zero'd */ |
| 95 | ahp9285 = ath_hal_malloc(sizeof (struct ath_hal_9285)); |
| 96 | if (ahp9285 == AH_NULL) { |
| 97 | HALDEBUG(AH_NULL, HAL_DEBUG_ANY, |
| 98 | "%s: cannot allocate memory for state block\n" , __func__); |
| 99 | *status = HAL_ENOMEM; |
| 100 | return AH_NULL; |
| 101 | } |
| 102 | ahp = AH5212(ahp9285); |
| 103 | ah = &ahp->ah_priv.h; |
| 104 | |
| 105 | ar5416InitState(AH5416(ah), devid, sc, st, sh, status); |
| 106 | |
| 107 | /* XXX override with 9285 specific state */ |
| 108 | /* override 5416 methods for our needs */ |
| 109 | ah->ah_setAntennaSwitch = ar9285SetAntennaSwitch; |
| 110 | ah->ah_configPCIE = ar9285ConfigPCIE; |
| 111 | ah->ah_setTxPower = ar9285SetTransmitPower; |
| 112 | ah->ah_setBoardValues = ar9285SetBoardValues; |
| 113 | |
| 114 | AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; |
| 115 | AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; |
| 116 | AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; |
| 117 | AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; |
| 118 | AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; |
| 119 | |
| 120 | AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; |
| 121 | AH5416(ah)->ah_writeIni = ar9285WriteIni; |
| 122 | AH5416(ah)->ah_rx_chainmask = AR9285_DEFAULT_RXCHAINMASK; |
| 123 | AH5416(ah)->ah_tx_chainmask = AR9285_DEFAULT_TXCHAINMASK; |
| 124 | |
| 125 | ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD >> 1; |
| 126 | |
| 127 | if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { |
| 128 | /* reset chip */ |
| 129 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n" , |
| 130 | __func__); |
| 131 | ecode = HAL_EIO; |
| 132 | goto bad; |
| 133 | } |
| 134 | |
| 135 | if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { |
| 136 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n" , |
| 137 | __func__); |
| 138 | ecode = HAL_EIO; |
| 139 | goto bad; |
| 140 | } |
| 141 | /* Read Revisions from Chips before taking out of reset */ |
| 142 | val = OS_REG_READ(ah, AR_SREV); |
| 143 | HALDEBUG(ah, HAL_DEBUG_ATTACH, |
| 144 | "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n" , |
| 145 | __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), |
| 146 | MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); |
| 147 | /* NB: include chip type to differentiate from pre-Sowl versions */ |
| 148 | AH_PRIVATE(ah)->ah_macVersion = |
| 149 | (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; |
| 150 | AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); |
| 151 | AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; |
| 152 | |
| 153 | /* setup common ini data; rf backends handle remainder */ |
| 154 | if (AR_SREV_KITE_12_OR_LATER(ah)) { |
| 155 | HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes_v2, 6); |
| 156 | HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common_v2, 2); |
| 157 | HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, |
| 158 | ar9285PciePhy_clkreq_always_on_L1_v2, 2); |
| 159 | } else { |
| 160 | HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes, 6); |
| 161 | HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common, 2); |
| 162 | HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, |
| 163 | ar9285PciePhy_clkreq_always_on_L1, 2); |
| 164 | } |
| 165 | ar5416AttachPCIE(ah); |
| 166 | |
| 167 | ecode = ath_hal_v4kEepromAttach(ah); |
| 168 | if (ecode != HAL_OK) |
| 169 | goto bad; |
| 170 | |
| 171 | if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ |
| 172 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n" , |
| 173 | __func__); |
| 174 | ecode = HAL_EIO; |
| 175 | goto bad; |
| 176 | } |
| 177 | |
| 178 | AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); |
| 179 | |
| 180 | if (!ar5212ChipTest(ah)) { |
| 181 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n" , |
| 182 | __func__); |
| 183 | ecode = HAL_ESELFTEST; |
| 184 | goto bad; |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | * Set correct Baseband to analog shift |
| 189 | * setting to access analog chips. |
| 190 | */ |
| 191 | OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); |
| 192 | |
| 193 | /* Read Radio Chip Rev Extract */ |
| 194 | AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); |
| 195 | switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { |
| 196 | case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ |
| 197 | case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ |
| 198 | break; |
| 199 | default: |
| 200 | if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { |
| 201 | AH_PRIVATE(ah)->ah_analog5GhzRev = |
| 202 | AR_RAD5133_SREV_MAJOR; |
| 203 | break; |
| 204 | } |
| 205 | #ifdef AH_DEBUG |
| 206 | HALDEBUG(ah, HAL_DEBUG_ANY, |
| 207 | "%s: 5G Radio Chip Rev 0x%02X is not supported by " |
| 208 | "this driver\n" , __func__, |
| 209 | AH_PRIVATE(ah)->ah_analog5GhzRev); |
| 210 | ecode = HAL_ENOTSUPP; |
| 211 | goto bad; |
| 212 | #endif |
| 213 | } |
| 214 | rfStatus = ar9285RfAttach(ah, &ecode); |
| 215 | if (!rfStatus) { |
| 216 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n" , |
| 217 | __func__, ecode); |
| 218 | goto bad; |
| 219 | } |
| 220 | |
| 221 | HAL_INI_INIT(&ahp9285->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, |
| 222 | 6); |
| 223 | /* setup txgain table */ |
| 224 | switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { |
| 225 | case AR5416_EEP_TXGAIN_HIGH_POWER: |
| 226 | HAL_INI_INIT(&ahp9285->ah_ini_txgain, |
| 227 | ar9285Modes_high_power_tx_gain_v2, 6); |
| 228 | break; |
| 229 | case AR5416_EEP_TXGAIN_ORIG: |
| 230 | HAL_INI_INIT(&ahp9285->ah_ini_txgain, |
| 231 | ar9285Modes_original_tx_gain_v2, 6); |
| 232 | break; |
| 233 | default: |
| 234 | HALASSERT(AH_FALSE); |
| 235 | goto bad; /* XXX ? try to continue */ |
| 236 | } |
| 237 | |
| 238 | /* |
| 239 | * Got everything we need now to setup the capabilities. |
| 240 | */ |
| 241 | if (!ar9285FillCapabilityInfo(ah)) { |
| 242 | ecode = HAL_EEREAD; |
| 243 | goto bad; |
| 244 | } |
| 245 | |
| 246 | ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); |
| 247 | if (ecode != HAL_OK) { |
| 248 | HALDEBUG(ah, HAL_DEBUG_ANY, |
| 249 | "%s: error getting mac address from EEPROM\n" , __func__); |
| 250 | goto bad; |
| 251 | } |
| 252 | /* XXX How about the serial number ? */ |
| 253 | /* Read Reg Domain */ |
| 254 | AH_PRIVATE(ah)->ah_currentRD = |
| 255 | ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); |
| 256 | |
| 257 | /* |
| 258 | * ah_miscMode is populated by ar5416FillCapabilityInfo() |
| 259 | * starting from griffin. Set here to make sure that |
| 260 | * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is |
| 261 | * placed into hardware. |
| 262 | */ |
| 263 | if (ahp->ah_miscMode != 0) |
| 264 | OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); |
| 265 | |
| 266 | ar9285AniSetup(ah); /* Anti Noise Immunity */ |
| 267 | ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); |
| 268 | |
| 269 | HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n" , __func__); |
| 270 | |
| 271 | return ah; |
| 272 | bad: |
| 273 | if (ah != AH_NULL) |
| 274 | ah->ah_detach(ah); |
| 275 | if (status) |
| 276 | *status = ecode; |
| 277 | return AH_NULL; |
| 278 | } |
| 279 | |
| 280 | static void |
| 281 | ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore) |
| 282 | { |
| 283 | if (AH_PRIVATE(ah)->ah_ispcie && !restore) { |
| 284 | ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); |
| 285 | OS_DELAY(1000); |
| 286 | OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); |
| 287 | OS_REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | static void |
| 292 | ar9285WriteIni(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) |
| 293 | { |
| 294 | u_int modesIndex; |
| 295 | int regWrites = 0; |
| 296 | |
| 297 | /* Setup the indices for the next set of register array writes */ |
| 298 | /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ |
| 299 | if (IS_CHAN_HT40(chan)) |
| 300 | modesIndex = 3; |
| 301 | else if (IS_CHAN_108G(chan)) |
| 302 | modesIndex = 5; |
| 303 | else |
| 304 | modesIndex = 4; |
| 305 | |
| 306 | /* Set correct Baseband to analog shift setting to access analog chips. */ |
| 307 | OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); |
| 308 | OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); |
| 309 | regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, |
| 310 | modesIndex, regWrites); |
| 311 | if (AR_SREV_KITE_12_OR_LATER(ah)) { |
| 312 | regWrites = ath_hal_ini_write(ah, &AH9285(ah)->ah_ini_txgain, |
| 313 | modesIndex, regWrites); |
| 314 | } |
| 315 | regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, |
| 316 | 1, regWrites); |
| 317 | |
| 318 | OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); |
| 319 | |
| 320 | if (AR_SREV_MERLIN_10_OR_LATER(ah)) { |
| 321 | uint32_t val; |
| 322 | val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & |
| 323 | (~AR_PCU_MISC_MODE2_HWWAR1); |
| 324 | OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, val); |
| 325 | OS_REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); |
| 326 | } |
| 327 | |
| 328 | } |
| 329 | |
| 330 | /* |
| 331 | * Fill all software cached or static hardware state information. |
| 332 | * Return failure if capabilities are to come from EEPROM and |
| 333 | * cannot be read. |
| 334 | */ |
| 335 | static HAL_BOOL |
| 336 | ar9285FillCapabilityInfo(struct ath_hal *ah) |
| 337 | { |
| 338 | HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; |
| 339 | |
| 340 | if (!ar5416FillCapabilityInfo(ah)) |
| 341 | return AH_FALSE; |
| 342 | pCap->halNumGpioPins = 12; |
| 343 | pCap->halWowSupport = AH_TRUE; |
| 344 | pCap->halWowMatchPatternExact = AH_TRUE; |
| 345 | #if 0 |
| 346 | pCap->halWowMatchPatternDword = AH_TRUE; |
| 347 | #endif |
| 348 | pCap->halCSTSupport = AH_TRUE; |
| 349 | pCap->halRifsRxSupport = AH_TRUE; |
| 350 | pCap->halRifsTxSupport = AH_TRUE; |
| 351 | pCap->halRtsAggrLimit = 64*1024; /* 802.11n max */ |
| 352 | pCap->halExtChanDfsSupport = AH_TRUE; |
| 353 | #if 0 |
| 354 | /* XXX bluetooth */ |
| 355 | pCap->halBtCoexSupport = AH_TRUE; |
| 356 | #endif |
| 357 | pCap->halAutoSleepSupport = AH_FALSE; /* XXX? */ |
| 358 | #if 0 |
| 359 | pCap->hal4kbSplitTransSupport = AH_FALSE; |
| 360 | #endif |
| 361 | pCap->halRxStbcSupport = 1; |
| 362 | pCap->halTxStbcSupport = 1; |
| 363 | |
| 364 | return AH_TRUE; |
| 365 | } |
| 366 | |
| 367 | HAL_BOOL |
| 368 | ar9285SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) |
| 369 | { |
| 370 | #define ANTENNA0_CHAINMASK 0x1 |
| 371 | #define ANTENNA1_CHAINMASK 0x2 |
| 372 | struct ath_hal_5416 *ahp = AH5416(ah); |
| 373 | |
| 374 | /* Antenna selection is done by setting the tx/rx chainmasks approp. */ |
| 375 | switch (settings) { |
| 376 | case HAL_ANT_FIXED_A: |
| 377 | /* Enable first antenna only */ |
| 378 | ahp->ah_tx_chainmask = ANTENNA0_CHAINMASK; |
| 379 | ahp->ah_rx_chainmask = ANTENNA0_CHAINMASK; |
| 380 | break; |
| 381 | case HAL_ANT_FIXED_B: |
| 382 | /* Enable second antenna only, after checking capability */ |
| 383 | if (AH_PRIVATE(ah)->ah_caps.halTxChainMask > ANTENNA1_CHAINMASK) |
| 384 | ahp->ah_tx_chainmask = ANTENNA1_CHAINMASK; |
| 385 | ahp->ah_rx_chainmask = ANTENNA1_CHAINMASK; |
| 386 | break; |
| 387 | case HAL_ANT_VARIABLE: |
| 388 | /* Restore original chainmask settings */ |
| 389 | /* XXX */ |
| 390 | ahp->ah_tx_chainmask = AR9285_DEFAULT_TXCHAINMASK; |
| 391 | ahp->ah_rx_chainmask = AR9285_DEFAULT_RXCHAINMASK; |
| 392 | break; |
| 393 | } |
| 394 | return AH_TRUE; |
| 395 | #undef ANTENNA0_CHAINMASK |
| 396 | #undef ANTENNA1_CHAINMASK |
| 397 | } |
| 398 | |
| 399 | static const char* |
| 400 | ar9285Probe(uint16_t vendorid, uint16_t devid) |
| 401 | { |
| 402 | if (vendorid == ATHEROS_VENDOR_ID && devid == AR9285_DEVID_PCIE) |
| 403 | return "Atheros 9285" ; |
| 404 | return AH_NULL; |
| 405 | } |
| 406 | AH_CHIP(AR9285, ar9285Probe, ar9285Attach); |
| 407 | |