| 1 | /* |
| 2 | * Copyright (c) 2008 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 | * $Id: ar9160_attach.c,v 1.2 2011/02/20 11:21:04 jmcneill 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 "ar5416/ar5416.h" |
| 26 | #include "ar5416/ar5416reg.h" |
| 27 | #include "ar5416/ar5416phy.h" |
| 28 | |
| 29 | #include "ar5416/ar9160.ini" |
| 30 | |
| 31 | static const HAL_PERCAL_DATA ar9160_iq_cal = { /* multi sample */ |
| 32 | .calName = "IQ" , .calType = IQ_MISMATCH_CAL, |
| 33 | .calNumSamples = MAX_CAL_SAMPLES, |
| 34 | .calCountMax = PER_MIN_LOG_COUNT, |
| 35 | .calCollect = ar5416IQCalCollect, |
| 36 | .calPostProc = ar5416IQCalibration |
| 37 | }; |
| 38 | static const HAL_PERCAL_DATA ar9160_adc_gain_cal = { /* multi sample */ |
| 39 | .calName = "ADC Gain" , .calType = ADC_GAIN_CAL, |
| 40 | .calNumSamples = MAX_CAL_SAMPLES, |
| 41 | .calCountMax = PER_MIN_LOG_COUNT, |
| 42 | .calCollect = ar5416AdcGainCalCollect, |
| 43 | .calPostProc = ar5416AdcGainCalibration |
| 44 | }; |
| 45 | static const HAL_PERCAL_DATA ar9160_adc_dc_cal = { /* multi sample */ |
| 46 | .calName = "ADC DC" , .calType = ADC_DC_CAL, |
| 47 | .calNumSamples = MAX_CAL_SAMPLES, |
| 48 | .calCountMax = PER_MIN_LOG_COUNT, |
| 49 | .calCollect = ar5416AdcDcCalCollect, |
| 50 | .calPostProc = ar5416AdcDcCalibration |
| 51 | }; |
| 52 | static const HAL_PERCAL_DATA ar9160_adc_init_dc_cal = { |
| 53 | .calName = "ADC Init DC" , .calType = ADC_DC_INIT_CAL, |
| 54 | .calNumSamples = MIN_CAL_SAMPLES, |
| 55 | .calCountMax = INIT_LOG_COUNT, |
| 56 | .calCollect = ar5416AdcDcCalCollect, |
| 57 | .calPostProc = ar5416AdcDcCalibration |
| 58 | }; |
| 59 | |
| 60 | struct ath_hal *ar9160Attach(uint16_t devid, HAL_SOFTC sc, |
| 61 | HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status); |
| 62 | static void ar9160Detach(struct ath_hal *); |
| 63 | static HAL_BOOL ar9160FillCapabilityInfo(struct ath_hal *ah); |
| 64 | |
| 65 | static void |
| 66 | ar9160AniSetup(struct ath_hal *ah) |
| 67 | { |
| 68 | static const struct ar5212AniParams aniparams = { |
| 69 | .maxNoiseImmunityLevel = 4, /* levels 0..4 */ |
| 70 | .totalSizeDesired = { -55, -55, -55, -55, -62 }, |
| 71 | .coarseHigh = { -14, -14, -14, -14, -12 }, |
| 72 | .coarseLow = { -64, -64, -64, -64, -70 }, |
| 73 | .firpwr = { -78, -78, -78, -78, -80 }, |
| 74 | .maxSpurImmunityLevel = 2, |
| 75 | .cycPwrThr1 = { 2, 4, 6 }, |
| 76 | .maxFirstepLevel = 2, /* levels 0..2 */ |
| 77 | .firstep = { 0, 4, 8 }, |
| 78 | .ofdmTrigHigh = 500, |
| 79 | .ofdmTrigLow = 200, |
| 80 | .cckTrigHigh = 200, |
| 81 | .cckTrigLow = 100, |
| 82 | .rssiThrHigh = 40, |
| 83 | .rssiThrLow = 7, |
| 84 | .period = 100, |
| 85 | }; |
| 86 | /* NB: ANI is not enabled yet */ |
| 87 | ar5212AniAttach(ah, &aniparams, &aniparams, AH_FALSE); |
| 88 | } |
| 89 | |
| 90 | /* |
| 91 | * Attach for an AR9160 part. |
| 92 | */ |
| 93 | struct ath_hal * |
| 94 | ar9160Attach(uint16_t devid, HAL_SOFTC sc, |
| 95 | HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) |
| 96 | { |
| 97 | struct ath_hal_5416 *ahp5416; |
| 98 | struct ath_hal_5212 *ahp; |
| 99 | struct ath_hal *ah; |
| 100 | uint32_t val; |
| 101 | HAL_STATUS ecode; |
| 102 | HAL_BOOL rfStatus; |
| 103 | |
| 104 | HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n" , |
| 105 | __func__, sc, (void*) st, (void*) sh); |
| 106 | |
| 107 | /* NB: memory is returned zero'd */ |
| 108 | ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416)); |
| 109 | if (ahp5416 == AH_NULL) { |
| 110 | HALDEBUG(AH_NULL, HAL_DEBUG_ANY, |
| 111 | "%s: cannot allocate memory for state block\n" , __func__); |
| 112 | *status = HAL_ENOMEM; |
| 113 | return AH_NULL; |
| 114 | } |
| 115 | ar5416InitState(ahp5416, devid, sc, st, sh, status); |
| 116 | ahp = &ahp5416->ah_5212; |
| 117 | ah = &ahp->ah_priv.h; |
| 118 | |
| 119 | /* XXX override with 9160 specific state */ |
| 120 | /* override 5416 methods for our needs */ |
| 121 | ah->ah_detach = ar9160Detach; |
| 122 | |
| 123 | AH5416(ah)->ah_cal.iqCalData.calData = &ar9160_iq_cal; |
| 124 | AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9160_adc_gain_cal; |
| 125 | AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9160_adc_dc_cal; |
| 126 | AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9160_adc_init_dc_cal; |
| 127 | AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; |
| 128 | |
| 129 | if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { |
| 130 | /* reset chip */ |
| 131 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n" , |
| 132 | __func__); |
| 133 | ecode = HAL_EIO; |
| 134 | goto bad; |
| 135 | } |
| 136 | |
| 137 | if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { |
| 138 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n" , |
| 139 | __func__); |
| 140 | ecode = HAL_EIO; |
| 141 | goto bad; |
| 142 | } |
| 143 | /* Read Revisions from Chips before taking out of reset */ |
| 144 | val = OS_REG_READ(ah, AR_SREV); |
| 145 | HALDEBUG(ah, HAL_DEBUG_ATTACH, |
| 146 | "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n" , |
| 147 | __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), |
| 148 | MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); |
| 149 | /* NB: include chip type to differentiate from pre-Sowl versions */ |
| 150 | AH_PRIVATE(ah)->ah_macVersion = |
| 151 | (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; |
| 152 | AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); |
| 153 | AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; |
| 154 | |
| 155 | /* setup common ini data; rf backends handle remainder */ |
| 156 | HAL_INI_INIT(&ahp->ah_ini_modes, ar9160Modes, 6); |
| 157 | HAL_INI_INIT(&ahp->ah_ini_common, ar9160Common, 2); |
| 158 | |
| 159 | HAL_INI_INIT(&AH5416(ah)->ah_ini_bb_rfgain, ar9160BB_RfGain, 3); |
| 160 | HAL_INI_INIT(&AH5416(ah)->ah_ini_bank0, ar9160Bank0, 2); |
| 161 | HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar9160Bank1, 2); |
| 162 | HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar9160Bank2, 2); |
| 163 | HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar9160Bank3, 3); |
| 164 | HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar9160Bank6, 3); |
| 165 | HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar9160Bank7, 2); |
| 166 | if (AR_SREV_SOWL_11(ah)) |
| 167 | HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac_1_1, 2); |
| 168 | else |
| 169 | HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac, 2); |
| 170 | |
| 171 | HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9160PciePhy, 2); |
| 172 | ar5416AttachPCIE(ah); |
| 173 | |
| 174 | if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ |
| 175 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n" , __func__); |
| 176 | ecode = HAL_EIO; |
| 177 | goto bad; |
| 178 | } |
| 179 | |
| 180 | AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); |
| 181 | |
| 182 | if (!ar5212ChipTest(ah)) { |
| 183 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n" , |
| 184 | __func__); |
| 185 | ecode = HAL_ESELFTEST; |
| 186 | goto bad; |
| 187 | } |
| 188 | |
| 189 | /* |
| 190 | * Set correct Baseband to analog shift |
| 191 | * setting to access analog chips. |
| 192 | */ |
| 193 | OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); |
| 194 | |
| 195 | /* Read Radio Chip Rev Extract */ |
| 196 | AH_PRIVATE(ah)->ah_analog5GhzRev = ar5212GetRadioRev(ah); |
| 197 | switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { |
| 198 | case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ |
| 199 | case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ |
| 200 | break; |
| 201 | default: |
| 202 | if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { |
| 203 | AH_PRIVATE(ah)->ah_analog5GhzRev = |
| 204 | AR_RAD5133_SREV_MAJOR; |
| 205 | break; |
| 206 | } |
| 207 | #ifdef AH_DEBUG |
| 208 | HALDEBUG(ah, HAL_DEBUG_ANY, |
| 209 | "%s: 5G Radio Chip Rev 0x%02X is not supported by " |
| 210 | "this driver\n" , __func__, |
| 211 | AH_PRIVATE(ah)->ah_analog5GhzRev); |
| 212 | ecode = HAL_ENOTSUPP; |
| 213 | goto bad; |
| 214 | #endif |
| 215 | } |
| 216 | HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: Attaching AR2133 radio\n" , |
| 217 | __func__); |
| 218 | rfStatus = ar2133RfAttach(ah, &ecode); |
| 219 | if (!rfStatus) { |
| 220 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n" , |
| 221 | __func__, ecode); |
| 222 | goto bad; |
| 223 | } |
| 224 | |
| 225 | ecode = ath_hal_v14EepromAttach(ah); |
| 226 | if (ecode != HAL_OK) |
| 227 | goto bad; |
| 228 | |
| 229 | /* |
| 230 | * Got everything we need now to setup the capabilities. |
| 231 | */ |
| 232 | if (!ar9160FillCapabilityInfo(ah)) { |
| 233 | ecode = HAL_EEREAD; |
| 234 | goto bad; |
| 235 | } |
| 236 | |
| 237 | ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); |
| 238 | if (ecode != HAL_OK) { |
| 239 | HALDEBUG(ah, HAL_DEBUG_ANY, |
| 240 | "%s: error getting mac address from EEPROM\n" , __func__); |
| 241 | goto bad; |
| 242 | } |
| 243 | /* XXX How about the serial number ? */ |
| 244 | /* Read Reg Domain */ |
| 245 | AH_PRIVATE(ah)->ah_currentRD = |
| 246 | ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); |
| 247 | |
| 248 | /* |
| 249 | * ah_miscMode is populated by ar5416FillCapabilityInfo() |
| 250 | * starting from griffin. Set here to make sure that |
| 251 | * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is |
| 252 | * placed into hardware. |
| 253 | */ |
| 254 | if (ahp->ah_miscMode != 0) |
| 255 | OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); |
| 256 | |
| 257 | ar9160AniSetup(ah); /* Anti Noise Immunity */ |
| 258 | ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); |
| 259 | |
| 260 | HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n" , __func__); |
| 261 | |
| 262 | return ah; |
| 263 | bad: |
| 264 | if (ahp) |
| 265 | ar9160Detach((struct ath_hal *) ahp); |
| 266 | if (status) |
| 267 | *status = ecode; |
| 268 | return AH_NULL; |
| 269 | } |
| 270 | |
| 271 | void |
| 272 | ar9160Detach(struct ath_hal *ah) |
| 273 | { |
| 274 | HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n" , __func__); |
| 275 | |
| 276 | HALASSERT(ah != AH_NULL); |
| 277 | HALASSERT(ah->ah_magic == AR5416_MAGIC); |
| 278 | |
| 279 | ar5416Detach(ah); |
| 280 | } |
| 281 | |
| 282 | /* |
| 283 | * Fill all software cached or static hardware state information. |
| 284 | * Return failure if capabilities are to come from EEPROM and |
| 285 | * cannot be read. |
| 286 | */ |
| 287 | static HAL_BOOL |
| 288 | ar9160FillCapabilityInfo(struct ath_hal *ah) |
| 289 | { |
| 290 | HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; |
| 291 | |
| 292 | if (!ar5416FillCapabilityInfo(ah)) |
| 293 | return AH_FALSE; |
| 294 | pCap->halCSTSupport = AH_TRUE; |
| 295 | pCap->halRifsRxSupport = AH_TRUE; |
| 296 | pCap->halRifsTxSupport = AH_TRUE; |
| 297 | pCap->halRtsAggrLimit = 64*1024; /* 802.11n max */ |
| 298 | pCap->halExtChanDfsSupport = AH_TRUE; |
| 299 | pCap->halAutoSleepSupport = AH_FALSE; /* XXX? */ |
| 300 | return AH_TRUE; |
| 301 | } |
| 302 | |
| 303 | static const char* |
| 304 | ar9160Probe(uint16_t vendorid, uint16_t devid) |
| 305 | { |
| 306 | if (vendorid == ATHEROS_VENDOR_ID && devid == AR9160_DEVID_PCI) |
| 307 | return "Atheros 9160" ; |
| 308 | return AH_NULL; |
| 309 | } |
| 310 | AH_CHIP(AR9160, ar9160Probe, ar9160Attach); |
| 311 | |