static void ar9285WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); if (AR_SREV_KITE_12_OR_LATER(ah)) { regWrites = ath_hal_ini_write(ah, &AH9285(ah)->ah_ini_txgain, modesIndex, regWrites); } regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); }
/* * Fill all software cached or static hardware state information. * Return failure if capabilities are to come from EEPROM and * cannot be read. */ static HAL_BOOL ar9285FillCapabilityInfo(struct ath_hal *ah) { HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; if (!ar5416FillCapabilityInfo(ah)) return AH_FALSE; pCap->halNumGpioPins = 12; pCap->halWowSupport = AH_TRUE; pCap->halWowMatchPatternExact = AH_TRUE; #if 0 pCap->halWowMatchPatternDword = AH_TRUE; #endif /* AR9285 has 2 antennas but is a 1x1 stream device */ pCap->halTxStreams = 1; pCap->halRxStreams = 1; if (ar9285_check_div_comb(ah)) pCap->halAntDivCombSupport = AH_TRUE; pCap->halCSTSupport = AH_TRUE; pCap->halRifsRxSupport = AH_TRUE; pCap->halRifsTxSupport = AH_TRUE; pCap->halRtsAggrLimit = 64*1024; /* 802.11n max */ pCap->halExtChanDfsSupport = AH_TRUE; pCap->halUseCombinedRadarRssi = AH_TRUE; #if 1 /* XXX bluetooth */ pCap->halBtCoexSupport = AH_TRUE; #endif pCap->halAutoSleepSupport = AH_FALSE; /* XXX? */ pCap->hal4kbSplitTransSupport = AH_FALSE; /* Disable this so Block-ACK works correctly */ pCap->halHasRxSelfLinkedTail = AH_FALSE; pCap->halMbssidAggrSupport = AH_TRUE; pCap->hal4AddrAggrSupport = AH_TRUE; pCap->halSpectralScanSupport = AH_TRUE; pCap->halRxUsingLnaMixing = AH_TRUE; if (AR_SREV_KITE_12_OR_LATER(ah)) pCap->halPSPollBroken = AH_FALSE; /* Only RX STBC supported */ pCap->halRxStbcSupport = 1; pCap->halTxStbcSupport = 0; return AH_TRUE; }
static void ar9285WriteIni(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) { u_int modesIndex, freqIndex; int regWrites = 0; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ freqIndex = 2; if (IS_CHAN_HT40(chan)) modesIndex = 3; else if (IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); if (AR_SREV_KITE_12_OR_LATER(ah)) { regWrites = ath_hal_ini_write(ah, &AH9285(ah)->ah_ini_txgain, modesIndex, regWrites); } regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); if (AR_SREV_MERLIN_10_OR_LATER(ah)) { uint32_t val; val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_PCU_MISC_MODE2_HWWAR1); OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, val); OS_REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } }
static void ar9285AniSetup(struct ath_hal *ah) { /* * These are the parameters from the AR5416 ANI code; * they likely need quite a bit of adjustment for the * AR9285. */ static const struct ar5212AniParams aniparams = { .maxNoiseImmunityLevel = 4, /* levels 0..4 */ .totalSizeDesired = { -55, -55, -55, -55, -62 }, .coarseHigh = { -14, -14, -14, -14, -12 }, .coarseLow = { -64, -64, -64, -64, -70 }, .firpwr = { -78, -78, -78, -78, -80 }, .maxSpurImmunityLevel = 7, .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }, .maxFirstepLevel = 2, /* levels 0..2 */ .firstep = { 0, 4, 8 }, .ofdmTrigHigh = 500, .ofdmTrigLow = 200, .cckTrigHigh = 200, .cckTrigLow = 100, .rssiThrHigh = 40, .rssiThrLow = 7, .period = 100, }; /* NB: disable ANI noise immmunity for reliable RIFS rx */ AH5416(ah)->ah_ani_function &= ~(1 << HAL_ANI_NOISE_IMMUNITY_LEVEL); ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } static const char * ar9285_lna_conf[] = { "LNA1-LNA2", "LNA2", "LNA1", "LNA1+LNA2", }; static void ar9285_eeprom_print_diversity_settings(struct ath_hal *ah) { const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; const MODAL_EEP4K_HEADER *pModal = &ee->ee_base.modalHeader; ath_hal_printf(ah, "[ath] AR9285 Main LNA config: %s\n", ar9285_lna_conf[(pModal->antdiv_ctl2 >> 2) & 0x3]); ath_hal_printf(ah, "[ath] AR9285 Alt LNA config: %s\n", ar9285_lna_conf[pModal->antdiv_ctl2 & 0x3]); ath_hal_printf(ah, "[ath] LNA diversity %s, Diversity %s\n", ((pModal->antdiv_ctl1 & 0x1) ? "enabled" : "disabled"), ((pModal->antdiv_ctl1 & 0x8) ? "enabled" : "disabled")); } /* * Attach for an AR9285 part. */ static struct ath_hal * ar9285Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status) { struct ath_hal_9285 *ahp9285; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9285 = ath_hal_malloc(sizeof (struct ath_hal_9285)); if (ahp9285 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9285); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* * Use the "local" EEPROM data given to us by the higher layers. * This is a private copy out of system flash. The Linux ath9k * commit for the initial AR9130 support mentions MMIO flash * access is "unreliable." -adrian */ if (eepromdata != AH_NULL) { AH_PRIVATE(ah)->ah_eepromRead = ath_hal_EepromDataRead; AH_PRIVATE(ah)->ah_eepromWrite = NULL; ah->ah_eepromdata = eepromdata; } /* override with 9285 specific state */ AH5416(ah)->ah_initPLL = ar9280InitPLL; AH5416(ah)->ah_btCoexSetDiversity = ar9285BTCoexAntennaDiversity; ah->ah_setAntennaSwitch = ar9285SetAntennaSwitch; ah->ah_configPCIE = ar9285ConfigPCIE; ah->ah_disablePCIE = ar9285DisablePCIE; ah->ah_setTxPower = ar9285SetTransmitPower; ah->ah_setBoardValues = ar9285SetBoardValues; ah->ah_btCoexSetParameter = ar9285BTCoexSetParameter; ah->ah_divLnaConfGet = ar9285_antdiv_comb_conf_get; ah->ah_divLnaConfSet = ar9285_antdiv_comb_conf_set; AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9285WriteIni; AH5416(ah)->ah_rx_chainmask = AR9285_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9285_DEFAULT_TXCHAINMASK; ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD >> 1; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* setup common ini data; rf backends handle remainder */ if (AR_SREV_KITE_12_OR_LATER(ah)) { HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes_v2, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common_v2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9285PciePhy_clkreq_always_on_L1_v2, 2); } else { HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9285PciePhy_clkreq_always_on_L1, 2); } ar5416AttachPCIE(ah); /* Attach methods that require MAC version/revision info */ if (AR_SREV_KITE_12_OR_LATER(ah)) AH5416(ah)->ah_cal_initcal = ar9285InitCalHardware; if (AR_SREV_KITE_11_OR_LATER(ah)) AH5416(ah)->ah_cal_pacal = ar9002_hw_pa_cal; ecode = ath_hal_v4kEepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9285RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } HAL_INI_INIT(&ahp9285->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, 6); if (AR_SREV_9285E_20(ah)) ath_hal_printf(ah, "[ath] AR9285E_20 detected; using XE TX gain tables\n"); /* setup txgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_TXGAIN_HIGH_POWER: if (AR_SREV_9285E_20(ah)) HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_XE2_0_high_power, 6); else HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_high_power_tx_gain_v2, 6); break; case AR5416_EEP_TXGAIN_ORIG: if (AR_SREV_9285E_20(ah)) HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_XE2_0_normal_power, 6); else HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_original_tx_gain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } /* * Got everything we need now to setup the capabilities. */ if (!ar9285FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } /* * Print out the EEPROM antenna configuration mapping. * Some devices have a hard-coded LNA configuration profile; * others enable diversity. */ ar9285_eeprom_print_diversity_settings(ah); /* Print out whether the EEPROM settings enable AR9285 diversity */ if (ar9285_check_div_comb(ah)) { ath_hal_printf(ah, "[ath] Enabling diversity for Kite\n"); } /* Disable 11n for the AR2427 */ if (devid == AR2427_DEVID_PCIE) AH_PRIVATE(ah)->ah_caps.halHTSupport = AH_FALSE; ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); /* * For Kite and later chipsets, the following bits are not * programmed in EEPROM and so are set as enabled always. */ AH_PRIVATE(ah)->ah_currentRDext = AR9285_RDEXT_DEFAULT; /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); ar9285AniSetup(ah); /* Anti Noise Immunity */ /* Setup noise floor min/max/nominal values */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9285_2GHZ; /* XXX no 5ghz values? */ ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; } static void ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off) { uint32_t val; /* * This workaround needs some integration work with the HAL * config parameters and the if_ath_pci.c glue. * Specifically, read the value of the PCI register 0x70c * (4 byte PCI config space register) and store it in ath_hal_war70c. * Then if it's non-zero, the below WAR would override register * 0x570c upon suspend/resume. */ #if 0 if (AR_SREV_9285E_20(ah)) { val = AH_PRIVATE(ah)->ah_config.ath_hal_war70c; if (val) { val &= 0xffff00ff; val |= 0x6f00; OS_REG_WRITE(ah, 0x570c, val); } } #endif if (AH_PRIVATE(ah)->ah_ispcie && !restore) { ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); OS_DELAY(1000); } /* * Set PCIe workaround bits * * NOTE: * * In Merlin and Kite, bit 14 in WA register (disable L1) should only * be set when device enters D3 and be cleared when device comes back * to D0. */ if (power_off) { /* Power-off */ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); val = OS_REG_READ(ah, AR_WA); /* * Disable bit 6 and 7 before entering D3 to prevent * system hang. */ val &= ~(AR_WA_BIT6 | AR_WA_BIT7); /* * See above: set AR_WA_D3_L1_DISABLE when entering D3 state. * * XXX The reference HAL does it this way - it only sets * AR_WA_D3_L1_DISABLE if it's set in AR9280_WA_DEFAULT, * which it (currently) isn't. So the following statement * is currently a NOP. */ if (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE) val |= AR_WA_D3_L1_DISABLE; if (AR_SREV_9285E_20(ah)) val |= AR_WA_BIT23; OS_REG_WRITE(ah, AR_WA, val); } else { /* Power-on */ val = AR9285_WA_DEFAULT; /* * See note above: make sure L1_DISABLE is not set. */ val &= (~AR_WA_D3_L1_DISABLE); /* Software workaroud for ASPM system hang. */ val |= (AR_WA_BIT6 | AR_WA_BIT7); if (AR_SREV_9285E_20(ah)) val |= AR_WA_BIT23; OS_REG_WRITE(ah, AR_WA, val); /* set bit 19 to allow forcing of pcie core into L1 state */ OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); } }
/* * Attach for an AR9285 part. */ static struct ath_hal * ar9285Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) { struct ath_hal_9285 *ahp9285; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9285 = ath_hal_malloc(sizeof (struct ath_hal_9285)); if (ahp9285 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9285); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* XXX override with 9285 specific state */ /* override 5416 methods for our needs */ ah->ah_setAntennaSwitch = ar9285SetAntennaSwitch; ah->ah_configPCIE = ar9285ConfigPCIE; ah->ah_setTxPower = ar9285SetTransmitPower; ah->ah_setBoardValues = ar9285SetBoardValues; AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9285WriteIni; AH5416(ah)->ah_rx_chainmask = AR9285_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9285_DEFAULT_TXCHAINMASK; ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD >> 1; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* setup common ini data; rf backends handle remainder */ if (AR_SREV_KITE_12_OR_LATER(ah)) { HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes_v2, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common_v2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9285PciePhy_clkreq_always_on_L1_v2, 2); } else { HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9285PciePhy_clkreq_always_on_L1, 2); } ar5416AttachPCIE(ah); ecode = ath_hal_v4kEepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9285RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } HAL_INI_INIT(&ahp9285->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, 6); /* setup txgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_TXGAIN_HIGH_POWER: HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_high_power_tx_gain_v2, 6); break; case AR5416_EEP_TXGAIN_ORIG: HAL_INI_INIT(&ahp9285->ah_ini_txgain, ar9285Modes_original_tx_gain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } /* * Got everything we need now to setup the capabilities. */ if (!ar9285FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); ar9285AniSetup(ah); /* Anti Noise Immunity */ ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; }
HAL_BOOL ar5416WowEnable(struct ath_hal *ah, u_int32_t pattern_enable, u_int32_t timeoutInSeconds, int clearbssid) { uint32_t init_val, val, rval=0; const int ka_delay = 4; /* Delay of 4 millisec between two KeepAlive's */ uint32_t wow_event_mask; /* * ah_wow_event_mask is a mask to the AR_WOW_PATTERN_REG register to indicate * which WOW events that we have enabled. The WOW Events are from the * pattern_enable in this function and pattern_count of ar5416WowApplyPattern() */ wow_event_mask = AH_PRIVATE(ah)->ah_wow_event_mask; /* * Untie Power-On-Reset from the PCI-E Reset. When we are in WOW sleep, * we do not want the Reset from the PCI-E to disturb our hw state. */ if (AR_SREV_MERLIN_20_OR_LATER(ah) && (AH_PRIVATE(ah)->ah_is_pci_express == AH_TRUE)) { /* * We need to untie the internal POR (power-on-reset) to the external * PCI-E reset. We also need to tie the PCI-E Phy reset to the PCI-E reset. */ u_int32_t wa_reg_val; if (AR_SREV_KITE(ah) || AR_SREV_KIWI(ah)) wa_reg_val = AR9285_WA_DEFAULT; else wa_reg_val = AR9280_WA_DEFAULT; /* * In Merlin and Kite, bit 14 in WA register (disable L1) should only * be set when device enters D3 and be cleared when device comes back to D0. */ if (AH_PRIVATE(ah)->ah_config.ath_hal_pcie_waen & AR_WA_D3_L1_DISABLE) wa_reg_val = wa_reg_val | AR_WA_D3_L1_DISABLE; wa_reg_val = wa_reg_val & ~(AR_WA_UNTIE_RESET_EN); wa_reg_val = wa_reg_val | AR_WA_RESET_EN | AR_WA_POR_SHORT; OS_REG_WRITE(ah, AR_WA, wa_reg_val); if (!AR_SREV_KITE(ah) || AR_SREV_KITE_12_OR_LATER(ah)) { /* s * For WOW sleep, we reprogram the SerDes so that the PLL and CHK REQ * are both enabled. This uses more power but the Maverick team reported * that otherwise, WOW sleep is unable and chip may disappears. */ ar928xConfigSerDes_WowSleep(ah); } } /* * Set the power states appropriately and enable pme. */ val = OS_REG_READ(ah, AR_PCIE_PM_CTRL); val |= AR_PMCTRL_HOST_PME_EN | \ AR_PMCTRL_PWR_PM_CTRL_ENA | AR_PMCTRL_AUX_PWR_DET; val &= ~AR_PMCTRL_WOW_PME_CLR; OS_REG_WRITE(ah, AR_PCIE_PM_CTRL, val); /* * Setup for for: * - beacon misses * - magic pattern * - keep alive timeout * - pattern matching */ /* * Program some default values for keep-alives, beacon misses, etc. */ init_val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); val = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF) | init_val; OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, val); rval = OS_REG_READ(ah, AR_WOW_PATTERN_REG); init_val = OS_REG_READ(ah, AR_WOW_COUNT_REG); val = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | \ AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | \ AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); OS_REG_WRITE(ah, AR_WOW_COUNT_REG, val); rval = OS_REG_READ(ah, AR_WOW_COUNT_REG); init_val = OS_REG_READ(ah, AR_WOW_BCN_TIMO_REG); if (pattern_enable & AH_WOW_BEACON_MISS) { val = AR_WOW_BEACON_TIMO; } else { /* We are not using the beacon miss. Program a large value. */ val = AR_WOW_BEACON_TIMO_MAX; } OS_REG_WRITE(ah, AR_WOW_BCN_TIMO_REG, val); rval = OS_REG_READ(ah, AR_WOW_BCN_TIMO_REG); init_val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_TIMO_REG); /* * Keep Alive Timo in ms, except Merlin - see EV 62708 */ if (pattern_enable == 0 || AR_SREV_MERLIN(ah)) { val = AR_WOW_KEEP_ALIVE_NEVER; } else { val = AH_PRIVATE(ah)->ah_config.ath_hal_keep_alive_timeout * 32; } OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO_REG, val); rval = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_TIMO_REG); init_val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_DELAY_REG); /* * Keep Alive delay in us. Based on 'power on clock' , therefore in uSec */ val = ka_delay * 1000; OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY_REG, val); rval = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_DELAY_REG); /* * Create KeepAlive Pattern to respond to beacons. */ ar5416WowCreateKeepAlivePattern(ah); /* * Configure Mac Wow Registers. */ val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_REG); /* * Send keep alive timeouts anyway. */ val &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS; if (pattern_enable & AH_WOW_LINK_CHANGE) { val &= ~ AR_WOW_KEEP_ALIVE_FAIL_DIS; wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; } else { val |= AR_WOW_KEEP_ALIVE_FAIL_DIS; } OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_REG, val); val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_REG); val = OS_REG_READ(ah, AR_WOW_BCN_EN_REG); /* * We are relying on a bmiss failure. Ensure we have enough * threshold to prevent false positives. */ OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, AR_WOW_BMISSTHRESHOLD); /* * Beacon miss & user pattern events are broken in Owl. * Enable only for Merlin. * The workaround is done at the ath_dev layer using the * sc->sc_wow_bmiss_intr field. * XXX: we need to cleanup this workaround before the next chip that * fixes this issue. */ if (!AR_SREV_MERLIN_10_OR_LATER(ah)) pattern_enable &= ~AH_WOW_BEACON_MISS; if (pattern_enable & AH_WOW_BEACON_MISS) { val |= AR_WOW_BEACON_FAIL_EN; wow_event_mask |= AR_WOW_BEACON_FAIL; } else { val &= ~AR_WOW_BEACON_FAIL_EN; } OS_REG_WRITE(ah, AR_WOW_BCN_EN_REG, val); val = OS_REG_READ(ah, AR_WOW_BCN_EN_REG); /* * Enable the magic packet registers. */ val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { val |= AR_WOW_MAGIC_EN; wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; } else { val &= ~AR_WOW_MAGIC_EN; } val |= AR_WOW_MAC_INTR_EN; OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, val); val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); /* For Kite and later version of the chips * enable wow pattern match for packets less than * 256 bytes for all patterns. */ if (AR_SREV_KITE_10_OR_LATER(ah)) { OS_REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B_REG, AR_WOW_PATTERN_SUPPORTED); } /* * Set the power states appropriately and enable pme. */ val = OS_REG_READ(ah, AR_PCIE_PM_CTRL); val |= AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA; OS_REG_WRITE(ah, AR_PCIE_PM_CTRL, val); if (timeoutInSeconds) { /* The clearbssid parameter is set only for the case where the wake needs to be on a timeout. The timeout mechanism, at this time, is specific to Maverick. For a manuf test, the system is put into sleep with a timer. On timer expiry, the chip interrupts(timer) and wakes the system. Clearbssid is specified as TRUE since we do not want a spurious beacon miss. If specified as true, we clear the bssid regs. */ // Setup the timer. OS_REG_WRITE(ah, AR_NEXT_NDP_TIMER, OS_REG_READ(ah, AR_TSF_L32) + timeoutInSeconds * 1000000 ); // convert Timeout to uSecs. OS_REG_WRITE(ah, AR_NDP_PERIOD, 30 * 1000000); // timer_period = 30 seconds always. OS_REG_WRITE(ah, AR_TIMER_MODE, OS_REG_READ(ah, AR_TIMER_MODE) | AR_NDP_TIMER_EN); // Enable the timer interrupt OS_REG_WRITE(ah, AR_IMR_S5, OS_REG_READ(ah, AR_IMR_S5) | AR_IMR_S5_GENTIMER7); OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_GENTMR); if (clearbssid) { // If the bssid regs are set and all we want is a wake on timer, we run into an issue // with the wake coming in too early. OS_REG_WRITE(ah, AR_BSS_ID0, 0); OS_REG_WRITE(ah, AR_BSS_ID1, 0); } } /* * enable seq number generation in hw */ OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); ar5416SetPowerModeWowSleep(ah); AH_PRIVATE(ah)->ah_wow_event_mask = wow_event_mask; return (AH_TRUE); }