void ar9300_disable_weak_signal(struct ath_hal *ah) { /* set firpwr to max (signed) */ OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, 0x7f); OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR_SIGN_BIT); /* set firstep to max */ OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, 0x3f); /* set relpwr to max (signed) */ OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELPWR, 0x1f); OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELPWR_SIGN_BIT); /* set relstep to max (signed) */ OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELSTEP, 0x1f); OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT); /* set firpwr_low to max (signed) */ OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRPWR, 0x7f); OS_REG_CLR_BIT( ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRPWR_SIGN_BIT); /* set firstep_low to max */ OS_REG_RMW_FIELD( ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, 0x3f); /* set relstep_low to max (signed) */ OS_REG_RMW_FIELD( ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_RELSTEP, 0x1f); OS_REG_CLR_BIT( ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_RELSTEP_SIGN_BIT); }
void ar5416DisableWeakSignal(struct ath_hal *ah) { // set firpwr to max (signed) OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, 0x7f); OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR_SIGN_BIT); // set firstep to max OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, 0x3f); // set relpwr to max (signed) OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELPWR, 0x1f); OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELPWR_SIGN_BIT); // set relstep to max (signed) OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELSTEP, 0x1f); OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT); // set firpwr_low to max (signed) OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRPWR, 0x7f); OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRPWR_SIGN_BIT); // set firstep_low to max OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP, 0x3f); // set relstep_low to max (signed) OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_RELSTEP, 0x1f); OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_RELSTEP_SIGN_BIT); }
/* * Notify Power Mgt is disabled in self-generated frames. * If requested, force chip to sleep. */ static void ar5416SetPowerModeSleep(struct ath_hal *ah, int setChip) { OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (setChip) { /* Clear the RTC force wake bit to allow the mac to sleep */ OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); /* Shutdown chip. Active low */ OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); } }
/* * Notify Power Mgt is enabled in self-generated frames. * If requested, force chip awake. * * Returns A_OK if chip is awake or successfully forced awake. * * WARNING WARNING WARNING * There is a problem with the chip where sometimes it will not wake up. */ static HAL_BOOL ar5211SetPowerModeAwake(struct ath_hal *ah, int setChip) { #define POWER_UP_TIME 2000 uint32_t val; int i; if (setChip) { OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE); OS_DELAY(10); /* Give chip the chance to awake */ for (i = POWER_UP_TIME / 200; i != 0; i--) { val = OS_REG_READ(ah, AR_PCICFG); if ((val & AR_PCICFG_SPWR_DN) == 0) break; OS_DELAY(200); OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE); } if (i == 0) { #ifdef AH_DEBUG ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", __func__, POWER_UP_TIME/20); #endif return AH_FALSE; } } OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); return AH_TRUE; #undef POWER_UP_TIME }
/* * Configure GPIO Output lines */ HAL_BOOL ar5416GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) { HALASSERT(gpio < AR_NUM_GPIO); OS_REG_CLR_BIT(ah, AR_GPIO_INTR_OUT, AR_GPIO_BIT(gpio)); return AH_TRUE; }
/* * Notify Power Management is enabled in self-generating * fames. If request, set power mode of chip to * auto/normal. Duration in units of 128us (1/8 TU). */ static void ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) { OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (setChip) OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); }
/* * Notify Power Mgt is disabled in self-generated frames. * If requested, force chip to sleep. */ static void ar5416SetPowerModeSleep(struct ath_hal *ah, int set_chip) { OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (set_chip) { /* Clear the RTC force wake bit to allow the mac to go to sleep */ OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); if(!AR_SREV_HOWL(ah)) /*HOWL hangs in this case --AJP*/ OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); /* Shutdown chip. Active low */ if(!AR_SREV_K2(ah) && !AR_SREV_OWL(ah)) OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); } }
HAL_BOOL ar5416AbortTxDma(struct ath_hal *ah) { a_int32_t i, q; /* * set txd on all queues */ OS_REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M); /* * set tx abort bits */ OS_REG_SET_BIT(ah, AR_PCU_MISC, (AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF)); OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); OS_REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); /* * wait on all tx queues */ for (q = 0; q < AR_NUM_QCU; q++) { for (i = 0; i < AR5416_ABORT_LOOPS; i++) { if (!ar5416NumTxPending(ah, q)) break; OS_DELAY(AR5416_ABORT_WAIT); } if (i == AR5416_ABORT_LOOPS) { return AH_FALSE; } } /* * clear tx abort bits */ OS_REG_CLR_BIT(ah, AR_PCU_MISC, (AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF)); OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); OS_REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); /* * clear txd */ OS_REG_WRITE(ah, AR_Q_TXD, 0); return AH_TRUE; }
/* * Start Transmit at the PCU engine (unpause receive) */ void ar9300StartPcuReceive(struct ath_hal *ah, HAL_BOOL is_scanning) { ar9300EnableMIBCounters(ah); ar9300AniReset(ah, is_scanning); /* Clear RX_DIS and RX_ABORT after enabling phy errors in aniReset */ OS_REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); }
/* * Notify Power Mgt is enabled in self-generated frames. * If requested, force chip awake. * * Returns A_OK if chip is awake or successfully forced awake. * * WARNING WARNING WARNING * There is a problem with the chip where sometimes it will not wake up. */ static HAL_BOOL ar5212SetPowerModeAwake(struct ath_hal *ah, int setChip) { #define AR_SCR_MASK \ (AR_SCR_SLDUR|AR_SCR_SLE|AR_SCR_SLDTP|AR_SCR_SLDWP|\ AR_SCR_SLEPOL|AR_SCR_MIBIE|AR_SCR_UNKNOWN) #define POWER_UP_TIME 2000 uint32_t scr, val; int i; if (setChip) { /* * Be careful setting the AWAKE mode. When we are called * with the chip powered down the read returns 0xffffffff * which when blindly written back with OS_REG_RMW_FIELD * enables the MIB interrupt for the sleep performance * counters. This can result in an interrupt storm when * ANI is in operation as noone knows to turn off the MIB * interrupt cause. */ scr = OS_REG_READ(ah, AR_SCR); if (scr & ~AR_SCR_MASK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bogus SCR 0x%x, PCICFG 0x%x\n", __func__, scr, OS_REG_READ(ah, AR_PCICFG)); scr = 0; } scr = (scr &~ AR_SCR_SLE) | AR_SCR_SLE_WAKE; OS_REG_WRITE(ah, AR_SCR, scr); OS_DELAY(10); /* Give chip the chance to awake */ for (i = POWER_UP_TIME / 50; i != 0; i--) { val = OS_REG_READ(ah, AR_PCICFG); if ((val & AR_PCICFG_SPWR_DN) == 0) break; OS_DELAY(50); OS_REG_WRITE(ah, AR_SCR, scr); } if (i == 0) { #ifdef AH_DEBUG ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", __func__, POWER_UP_TIME/50); #endif return AH_FALSE; } } OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); return AH_TRUE; #undef POWER_UP_TIME #undef AR_SCR_MASK }
/* * Set the RX abort bit. */ HAL_BOOL ar9300SetRxAbort(struct ath_hal *ah, HAL_BOOL set) { if (set) { /* Set the ForceRXAbort bit */ OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); if ( AH_PRIVATE(ah)->ah_reset_reason == HAL_RESET_BBPANIC ){ /* depending upon the BB panic status, rx state may not return to 0, * so skipping the wait for BB panic reset */ OS_REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); return AH_FALSE; } else { HAL_BOOL okay; okay = ath_hal_wait( ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0, AH_WAIT_TIMEOUT); /* Wait for Rx state to return to 0 */ if (!okay) { u_int32_t reg; /* abort: chip rx failed to go idle in 10 ms */ OS_REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); reg = OS_REG_READ(ah, AR_OBS_BUS_1); HDPRINTF(ah, HAL_DBG_RX, "%s: rx failed to go idle in 10 ms RXSM=0x%x\n", __func__, reg); return AH_FALSE; // Indicate failure } } } else { OS_REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); } return AH_TRUE; // Function completed successfully }
HAL_STATUS ar5416RetrieveCaptureData(struct ath_hal *ah, u_int16_t chain_mask, int disable_dc_filter, void *sample_buf, u_int32_t* num_samples) { u_int32_t val, i, ch; int descr_address, num_chains; ADC_SAMPLE* sample; int32_t i_sum[AR5416_MAX_CHAINS] = {0}; int32_t q_sum[AR5416_MAX_CHAINS] = {0}; num_chains = mask2chains[chain_mask]; if (*num_samples < (MAX_ADC_SAMPLES * num_chains)) { /* supplied buffer is too small - update to inform caller of required size */ *num_samples = MAX_ADC_SAMPLES * num_chains; return HAL_ENOMEM; } /* Make sure we are reading TXBUF */ OS_REG_CLR_BIT(ah, AR_RXFIFO_CFG, AR_RXFIFO_CFG_REG_RD_ENA); sample = (ADC_SAMPLE*)sample_buf; descr_address = RXTX_DESC_BUFFER_ADDRESS; for (i=0; i < MAX_ADC_SAMPLES; i++, descr_address+=4, sample+=num_chains) { val = OS_REG_READ(ah, descr_address); /* Get bits [27:18] from TXBUF - chain#0 I */ i_sum[0] += sample[0].i = convert_to_signed((val >> 18) & 0x1ff); /* Get bits [17:9] from TXBUF - chain#0 Q */ q_sum[0] += sample[0].q = convert_to_signed((val >> 9) & 0x1ff); if (num_chains >= 2) { /* Get bits [8:0] from TXBUF - chain#1 I */ i_sum[1] += sample[1].i = convert_to_signed(val & 0x1ff); } } if (num_chains >= 2) { /* Make sure we are reading RXBUF */ OS_REG_SET_BIT(ah, AR_RXFIFO_CFG, AR_RXFIFO_CFG_REG_RD_ENA); sample = (ADC_SAMPLE*)sample_buf; descr_address = RXTX_DESC_BUFFER_ADDRESS; for (i=0; i < MAX_ADC_SAMPLES; i++, descr_address+=4, sample+=num_chains) { val = OS_REG_READ(ah, descr_address); /* Get bits [27:18] from RXBUF - chain #1 Q */ q_sum[1] += sample[1].q = convert_to_signed((val >> 18) & 0x1ff); if (num_chains >= 3) { /* Get bits [17:9] from RXBUF - chain #2 I */ i_sum[2] += sample[2].i = convert_to_signed((val >> 9) & 0x1ff); /* Get bits [8:0] from RXBUF - chain#2 Q */ q_sum[2] += sample[2].q = convert_to_signed(val & 0x1ff); } }
/* * Notify Power Mgt is enabled in self-generated frames. * If requested, force chip awake. * * Returns A_OK if chip is awake or successfully forced awake. * * WARNING WARNING WARNING * There is a problem with the chip where sometimes it will not wake up. */ static HAL_BOOL ar5416SetPowerModeAwake(struct ath_hal *ah, int setChip) { #define POWER_UP_TIME 200000 uint32_t val; int i = 0; if (setChip) { /* * Do a Power-On-Reset if OWL is shutdown * the NetBSD driver power-cycles the Cardbus slot * as part of the reset procedure. */ if ((OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_PM_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) goto bad; AH5416(ah)->ah_initPLL(ah, AH_NULL); } if (AR_SREV_HOWL(ah)) OS_REG_SET_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); if (AR_SREV_HOWL(ah)) OS_DELAY(10000); else OS_DELAY(50); /* Give chip the chance to awake */ for (i = POWER_UP_TIME / 50; i != 0; i--) { val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; if (val == AR_RTC_STATUS_ON) break; OS_DELAY(50); OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); } bad: if (i == 0) { #ifdef AH_DEBUG ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", __func__, POWER_UP_TIME/1000); #endif return AH_FALSE; } } OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); return AH_TRUE; #undef POWER_UP_TIME }
/* * AGC calibration for the AR5416, AR9130, AR9160, AR9280. */ HAL_BOOL ar5416InitCalHardware(struct ath_hal *ah, const struct ieee80211_channel *chan) { if (AR_SREV_MERLIN_10_OR_LATER(ah)) { /* Disable ADC */ OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); /* Enable Rx Filter Cal */ OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); } /* Calibrate the AGC */ OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); /* Poll for offset calibration complete */ if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset calibration did not complete in 1ms; " "noisy environment?\n", __func__); return AH_FALSE; } if (AR_SREV_MERLIN_10_OR_LATER(ah)) { /* Enable ADC */ OS_REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); /* Disable Rx Filter Cal */ OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); } return AH_TRUE; }
/* * Notify Power Mgt is enabled in self-generated frames. * If requested, force chip awake. * * Returns A_OK if chip is awake or successfully forced awake. * * WARNING WARNING WARNING * There is a problem with the chip where sometimes it will not wake up. */ HAL_BOOL ar5416SetPowerModeAwake(struct ath_hal *ah, int set_chip) { #define POWER_UP_TIME 10000 u_int32_t val; int i; if (set_chip) { /* Do a Power-On-Reset if OWL is shutdown */ if ((OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { if (ar5416SetResetReg(ah, HAL_RESET_POWER_ON) != AH_TRUE) { HALASSERT(0); return AH_FALSE; } ar5416InitPLL(ah, AH_NULL); } if(AR_SREV_HOWL(ah)) /* HOWL needs this bit to set to wake up -was cleared in ar5416SetPowerModeSleep() */ OS_REG_SET_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); if (AR_SREV_HOWL(ah)) { OS_DELAY(10000); /* Give chip the chance to awake */ } else { OS_DELAY(50); } for (i = POWER_UP_TIME / 50; i > 0; i--) { val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; if (val == AR_RTC_STATUS_ON) break; OS_DELAY(50); OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); } if (i == 0) { HDPRINTF(ah, HAL_DBG_POWER_MGMT, "%s: Failed to wakeup in %uus\n", __func__, POWER_UP_TIME/20); return AH_FALSE; } } OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); return AH_TRUE; #undef POWER_UP_TIME }
/* * Start receive at the PCU engine */ void ar5416StartPcuReceive(struct ath_hal *ah) { struct ath_hal_private *ahp = AH_PRIVATE(ah); HALDEBUG(ah, HAL_DEBUG_RX, "%s: Start PCU Receive \n", __func__); ar5212EnableMibCounters(ah); /* NB: restore current settings */ ar5416AniReset(ah, ahp->ah_curchan, ahp->ah_opmode, AH_TRUE); /* * NB: must do after enabling phy errors to avoid rx * frames w/ corrupted descriptor status. */ OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT); }
/* * Notify Power Management is enabled in self-generating * frames. If request, set power mode of chip to * auto/normal. Duration in units of 128us (1/8 TU). */ static void ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int set_chip) { OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (set_chip) { HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; if (! pCap->hal_auto_sleep_support) { /* Set WakeOnInterrupt bit; clear ForceWake bit */ OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); } else { /* Clear the RTC force wake bit to allow the mac to go to sleep */ OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); } } }
static void ar9300_setup_test_addac_mode(struct ath_hal *ah) { #if AH_BYTE_ORDER == AH_BIG_ENDIAN /* byteswap Rx/Tx buffer to ensure correct layout */ HDPRINTF(ah, HAL_DBG_RF_PARAM, "%s: big endian - set AR_CFG_SWTB/AR_CFG_SWRB\n", __func__); OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB, 0); #else /* Rx/Tx buffer should not be byteswaped */ if (OS_REG_READ(ah, AR_CFG) & (AR_CFG_SWTB | AR_CFG_SWRB)) { HDPRINTF(ah, HAL_DBG_UNMASKABLE, "%s: **WARNING: little endian but AR_CFG_SWTB/AR_CFG_SWRB set!\n", __func__); } #endif OS_REG_WRITE(ah, AR_PHY_TEST, 0); OS_REG_WRITE(ah, AR_PHY_TEST_CTL_STATUS, 0); /* cf_bbb_obs_sel=4'b0001 */ OS_REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 0x1); /* cf_rx_obs_sel=5'b00000, this is the 5th bit */ OS_REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); /* cf_tx_obs_sel=3'b111 */ OS_REG_RMW_FIELD( ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_TX_OBS_SEL, 0x7); /* cf_tx_obs_mux_sel=2'b11 */ OS_REG_RMW_FIELD( ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_TX_OBS_MUX_SEL, 0x3); /* enable TSTADC */ OS_REG_SET_BIT(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_TSTDAC_EN); /* cf_rx_obs_sel=5'b00000, these are the first 4 bits */ OS_REG_RMW_FIELD( ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0x0); /* tstdac_out_sel=2'b01 */ OS_REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_CHAIN_SEL, 0x1); }
/* * Select to pass PLCP headr or EVM data. */ HAL_BOOL ar9300SetRxSelEvm(struct ath_hal *ah, HAL_BOOL selEvm, HAL_BOOL justQuery) { struct ath_hal_9300 *ahp = AH9300(ah); HAL_BOOL old_value = ahp->ah_getPlcpHdr == 0; if (justQuery) { return old_value; } if (selEvm) { OS_REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM); } else { OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM); } ahp->ah_getPlcpHdr = !selEvm; return old_value; }
/* Carrier leakage Calibration fix */ static HAL_BOOL ar9285_hw_cl_cal(struct ath_hal *ah, const struct ieee80211_channel *chan) { OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); if (IEEE80211_IS_CHAN_HT20(chan)) { OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); OS_REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); OS_REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_PERCAL, "offset calibration failed to complete in 1ms; noisy environment?\n"); return AH_FALSE; } OS_REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); } OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); OS_REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_PERCAL, "offset calibration failed to complete in 1ms; noisy environment?\n"); return AH_FALSE; } OS_REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); return AH_TRUE; }
/* * This is like Merlin but without ADC disable */ HAL_BOOL ar9287InitCalHardware(struct ath_hal *ah, const struct ieee80211_channel *chan) { OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); /* Calibrate the AGC */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); /* Poll for offset calibration complete */ if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: offset calibration failed to complete in 1ms; " "noisy environment?\n", __func__); return AH_FALSE; } OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); return AH_TRUE; }
/* * Places the device in and out of reset and then places sane * values in the registers based on EEPROM config, initialization * vectors (as determined by the mode), and station configuration * * bChannelChange is used to preserve DMA/PCU registers across * a HW Reset during channel change. */ HAL_BOOL ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_BOOL bChannelChange, HAL_RESET_TYPE resetType, HAL_STATUS *status) { #define N(a) (sizeof (a) / sizeof (a[0])) #define FAIL(_code) do { ecode = _code; goto bad; } while (0) struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *ichan; const HAL_EEPROM *ee; uint32_t saveFrameSeqCount, saveDefAntenna; uint32_t macStaId1, synthDelay, txFrm2TxDStart; uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; int16_t cckOfdmPwrDelta = 0; u_int modesIndex, freqIndex; HAL_STATUS ecode; int i, regWrites = 0; uint32_t testReg; uint32_t saveLedState = 0; HALASSERT(ah->ah_magic == AR5212_MAGIC); ee = AH_PRIVATE(ah)->ah_eeprom; OS_MARK(ah, AH_MARK_RESET, bChannelChange); /* * Map public channel to private. */ ichan = ath_hal_checkchannel(ah, chan); if (ichan == AH_NULL) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); FAIL(HAL_EINVAL); } switch (opmode) { case HAL_M_STA: case HAL_M_IBSS: case HAL_M_HOSTAP: case HAL_M_MONITOR: break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", __func__, opmode); FAIL(HAL_EINVAL); break; } HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3); /* Preserve certain DMA hardware registers on a channel change */ if (bChannelChange) { /* * On Venice, the TSF is almost preserved across a reset; * it requires the doubling writes to the RESET_TSF * bit in the AR_BEACON register; it also has the quirk * of the TSF going back in time on the station (station * latches onto the last beacon's tsf during a reset 50% * of the times); the latter is not a problem for adhoc * stations since as long as the TSF is behind, it will * get resynchronized on receiving the next beacon; the * TSF going backwards in time could be a problem for the * sleep operation (supported on infrastructure stations * only) - the best and most general fix for this situation * is to resynchronize the various sleep/beacon timers on * the receipt of the next beacon i.e. when the TSF itself * gets resynchronized to the AP's TSF - power save is * needed to be temporarily disabled until that time * * Need to save the sequence number to restore it after * the reset! */ saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM); } else saveFrameSeqCount = 0; /* NB: silence compiler */ /* If the channel change is across the same mode - perform a fast channel change */ if ((IS_2413(ah) || IS_5413(ah))) { /* * Channel change can only be used when: * -channel change requested - so it's not the initial reset. * -it's not a change to the current channel - often called when switching modes * on a channel * -the modes of the previous and requested channel are the same - some ugly code for XR */ if (bChannelChange && AH_PRIVATE(ah)->ah_curchan != AH_NULL && (chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) && ((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) == (AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) { if (ar5212ChannelChange(ah, chan)) /* If ChannelChange completed - skip the rest of reset */ return AH_TRUE; } } /* * Preserve the antenna on a channel change */ saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) /* XXX magic constants */ saveDefAntenna = 1; /* Save hardware flag before chip reset clears the register */ macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT); /* Save led state from pci config register */ if (!IS_5315(ah)) saveLedState = OS_REG_READ(ah, AR5312_PCICFG) & (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | AR_PCICFG_LEDSLOW); ar5312RestoreClock(ah, opmode); /* move to refclk operation */ /* * Adjust gain parameters before reset if * there's an outstanding gain updated. */ (void) ar5212GetRfgain(ah); if (!ar5312ChipReset(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } /* Setup the indices for the next set of register array writes */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 : IEEE80211_IS_CHAN_G(chan) ? 4 : 3; } else { freqIndex = 1; modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1; } OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0); regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange, regWrites); ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) ar5212SetIFSTiming(ah, chan); /* Overwrite INI values for revised chipsets */ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { /* ADC_CTL */ OS_REG_WRITE(ah, AR_PHY_ADC_CTL, SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) | SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) | AR_PHY_ADC_CTL_OFF_PWDDAC | AR_PHY_ADC_CTL_OFF_PWDADC); /* TX_PWR_ADJ */ if (chan->channel == 2484) { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta); } else { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta); } if (IEEE80211_IS_CHAN_G(chan)) { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) | SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX)); } else { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0); } /* Add barker RSSI thresh enable as disabled */ OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_EN_RSSI_THR); OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_RSSI_THR, 2); /* Set the mute mask to the correct default */ OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) { /* Clear reg to alllow RX_CLEAR line debug */ OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) { #ifdef notyet /* Enable burst prefetch for the data queues */ OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... ); /* Enable double-buffering */ OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS); #endif } if (IS_5312_2_X(ah)) { /* ADC_CTRL */ OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA, SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) | SM(4, AR_PHY_SIGMA_DELTA_FILT2) | SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) | SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP)); if (IEEE80211_IS_CHAN_2GHZ(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F); /* CCK Short parameter adjustment in 11B mode */ if (IEEE80211_IS_CHAN_B(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12); /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); /* Increase 11A AGC Settling */ if (IEEE80211_IS_CHAN_A(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32); } else { /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); } /* Setup the transmit power values. */ if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } /* Write the analog registers */ if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n", __func__); FAIL(HAL_EIO); } /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ if (IEEE80211_IS_CHAN_OFDM(chan)) { if (IS_5413(ah) || AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3) ar5212SetSpurMitigation(ah, chan); ar5212SetDeltaSlope(ah, chan); } /* Setup board specific options for EEPROM version 3 */ if (!ar5212SetBoardValues(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error setting board options\n", __func__); FAIL(HAL_EIO); } /* Restore certain DMA hardware registers on a channel change */ if (bChannelChange) OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | macStaId1 | AR_STA_ID1_RTS_USE_DEF | ahp->ah_staId1Defaults ); ar5212SetOperatingMode(ah, opmode); /* Set Venice BSSID mask according to current state */ OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); /* Restore previous led state */ if (!IS_5315(ah)) OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState); /* Restore previous antenna */ OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); /* then our BSSID */ OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); /* Restore bmiss rssi & count thresholds */ OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ if (!ar5212SetChannel(ah, chan)) FAIL(HAL_EIO); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); ar5212SetRateDurationTable(ah, chan); /* Set Tx frame start to tx data start delay */ if (IS_RAD5112_ANY(ah) && (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { txFrm2TxDStart = IEEE80211_IS_CHAN_HALF(chan) ? TX_FRAME_D_START_HALF_RATE: TX_FRAME_D_START_QUARTER_RATE; OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL, AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart); } /* * Setup fast diversity. * Fast diversity can be enabled or disabled via regadd.txt. * Default is enabled. * For reference, * Disable: reg val * 0x00009860 0x00009d18 (if 11a / 11g, else no change) * 0x00009970 0x192bb514 * 0x0000a208 0xd03e4648 * * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change) * 0x00009970 0x192fb514 * 0x0000a208 0xd03e6788 */ /* XXX Setup pre PHY ENABLE EAR additions */ /* flush SCAL reg */ if (IS_5312_2_X(ah)) { (void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL); } /* * Wait for the frequency synth to settle (synth goes on * via AR_PHY_ACTIVE_EN). Read the phy active delay register. * Value is in 100ns increments. */ synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IEEE80211_IS_CHAN_B(chan)) { synthDelay = (4 * synthDelay) / 22; } else { synthDelay /= 10; } /* Activate the PHY (includes baseband activate and synthesizer on) */ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); /* * There is an issue if the AP starts the calibration before * the base band timeout completes. This could result in the * rx_clear false triggering. As a workaround we add delay an * extra BASE_ACTIVATE_DELAY usecs to ensure this condition * does not happen. */ if (IEEE80211_IS_CHAN_HALF(chan)) { OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); } else { OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); } /* * The udelay method is not reliable with notebooks. * Need to check to see if the baseband is ready */ testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL); /* Selects the Tx hold */ OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD); i = 0; while ((i++ < 20) && (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200); OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg); /* Calibrate the AGC and start a NF calculation */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL | AR_PHY_AGC_CONTROL_NF); if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) { /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, INIT_IQCAL_LOG_COUNT_MAX); OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_IQCAL); ahp->ah_bIQCalibration = IQ_CAL_RUNNING; } else ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; /* Setup compression registers */ ar5212SetCompRegs(ah); /* Set 1:1 QCU to DCU mapping for all queues */ for (i = 0; i < AR_NUM_DCU; i++) OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); ahp->ah_intrTxqs = 0; for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) ar5212ResetTxQueue(ah, i); /* * Setup interrupt handling. Note that ar5212ResetTxQueue * manipulates the secondary IMR's as queues are enabled * and disabled. This is done with RMW ops to insure the * settings we make here are preserved. */ ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_HIUERR ; if (opmode == HAL_M_HOSTAP) ahp->ah_maskReg |= AR_IMR_MIB; OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); /* Enable bus errors that are OR'd to set the HIUERR bit */ OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); if (AH_PRIVATE(ah)->ah_rfkillEnabled) ar5212EnableRfKill(ah); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset calibration failed to complete in 1ms;" " noisy environment?\n", __func__); } /* * Set clocks back to 32kHz if they had been using refClk, then * use an external 32kHz crystal when sleeping, if one exists. */ ar5312SetupClock(ah, opmode); /* * Writing to AR_BEACON will start timers. Hence it should * be the last register to be written. Do not reset tsf, do * not enable beacons at this point, but preserve other values * like beaconInterval. */ OS_REG_WRITE(ah, AR_BEACON, (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); /* XXX Setup post reset EAR additions */ /* QoS support */ if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE || (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) { OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */ OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */ } /* Turn on NOACK Support for QoS packets */ OS_REG_WRITE(ah, AR_NOACK, SM(2, AR_NOACK_2BIT_VALUE) | SM(5, AR_NOACK_BIT_OFFSET) | SM(0, AR_NOACK_BYTE_OFFSET)); /* Restore user-specified settings */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); if (ahp->ah_slottime != (u_int) -1) ar5212SetSlotTime(ah, ahp->ah_slottime); if (ahp->ah_acktimeout != (u_int) -1) ar5212SetAckTimeout(ah, ahp->ah_acktimeout); if (ahp->ah_ctstimeout != (u_int) -1) ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout); if (ahp->ah_sifstime != (u_int) -1) ar5212SetSifsTime(ah, ahp->ah_sifstime); if (AH_PRIVATE(ah)->ah_diagreg != 0) OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan)) chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); OS_MARK(ah, AH_MARK_RESET_DONE, 0); return AH_TRUE; bad: OS_MARK(ah, AH_MARK_RESET_DONE, ecode); if (status != AH_NULL) *status = ecode; return AH_FALSE; #undef FAIL #undef N }
/* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param, HAL_BOOL inISR) { #define N(a) (sizeof(a)/sizeof(a[0])) typedef int TABLE[]; struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState = ahp->ah_curani; switch (cmd & ahp->ah_ani_function) { case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; if (level >= N(ahp->ah_totalSizeDesired)) { HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n", __func__, level, (unsigned) N(ahp->ah_totalSizeDesired)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, ahp->ah_totalSizeDesired[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, ahp->ah_coarseLow[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, ahp->ah_coarseHigh[level]); OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, ahp->ah_firpwr[level]); if (level > aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { const TABLE m1ThreshLow = { 127, 50 }; const TABLE m2ThreshLow = { 127, 40 }; const TABLE m1Thresh = { 127, 0x4d }; const TABLE m2Thresh = { 127, 0x40 }; const TABLE m2CountThr = { 31, 16 }; const TABLE m2CountThrLow = { 63, 48 }; u_int on = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]); if (on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (!on != aniState->ofdmWeakSigDetectOff) { if (on) ahp->ah_stats.ast_ani_ofdmon++; else ahp->ah_stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; } break; } case HAL_ANI_CCK_WEAK_SIGNAL_THR: { const TABLE weakSigThrCck = { 8, 6 }; u_int high = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); if (high != aniState->cckWeakSigThreshold) { if (high) ahp->ah_stats.ast_ani_cckhigh++; else ahp->ah_stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = high; } break; } case HAL_ANI_FIRSTEP_LEVEL: { const TABLE firstep = { 0, 4, 8 }; u_int level = param; if (level >= N(firstep)) { HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n", __func__, level, (unsigned) N(firstep)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, firstep[level]); if (level > aniState->firstepLevel) ahp->ah_stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) ahp->ah_stats.ast_ani_stepdown++; aniState->firstepLevel = level; break; } case HAL_ANI_SPUR_IMMUNITY_LEVEL: { const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }; u_int level = param; if (level >= N(cycpwrThr1)) { HDPRINTF(ah, HAL_DBG_ANI, "%s: level out of range (%u > %u)\n", __func__, level, (unsigned) N(cycpwrThr1)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]); if (level > aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurdown++; aniState->spurImmunityLevel = level; break; } case HAL_ANI_PRESENT: break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_MODE: if (param == 0) { ahp->ah_procPhyErr &= ~HAL_PROCESS_ANI; /* Turn off HW counters if we have them */ ar5416AniDetach(ah); ar5416SetRxFilter(ah, ar5416GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { /* normal/auto mode */ ahp->ah_procPhyErr |= HAL_PROCESS_ANI; if (ahp->ah_hasHwPhyCounters) { ar5416SetRxFilter(ah, ar5416GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { ar5416SetRxFilter(ah, ar5416GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); } } break; case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: HDPRINTF(ah, HAL_DBG_ANI, "%s: invalid cmd %u\n", __func__, cmd); return AH_FALSE; } HDPRINTF(ah, HAL_DBG_ANI, "%s: ANI parameters:\n", __func__); HDPRINTF(ah, HAL_DBG_ANI, "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n", aniState->noiseImmunityLevel, aniState->spurImmunityLevel, !aniState->ofdmWeakSigDetectOff); HDPRINTF(ah, HAL_DBG_ANI, "cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n", aniState->cckWeakSigThreshold, aniState->firstepLevel, aniState->listenTime); HDPRINTF(ah, HAL_DBG_ANI, "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", aniState->cycleCount, aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); #ifndef REMOVE_PKT_LOG /* do pktlog */ { struct log_ani log_data; /* Populate the ani log record */ log_data.phyStatsDisable = DO_ANI(ah); log_data.noiseImmunLvl = aniState->noiseImmunityLevel; log_data.spurImmunLvl = aniState->spurImmunityLevel; log_data.ofdmWeakDet = aniState->ofdmWeakSigDetectOff; log_data.ofdmWeakDet = aniState->ofdmWeakSigDetectOff; log_data.cckWeakThr = aniState->cckWeakSigThreshold; log_data.firLvl = aniState->firstepLevel; log_data.listenTime = aniState->listenTime; log_data.cycleCount = aniState->cycleCount; log_data.ofdmPhyErrCount = aniState->ofdmPhyErrCount; log_data.cckPhyErrCount = aniState->cckPhyErrCount; log_data.rssi = 0; /* Was for legacy single antenna rssi */ /* For HT chips, 2x2 */ /* Log 6 u_int16_t RSSIs as first in the int32_t 'misc' array */ /* ToDo: Update pktRssi for valid packets? */ /* ToDo: Update PhyErr RSSIs in aniState variable - need Rx Descriptor / PhyErr*/ /* ToDo: Add parsing support in owldump, if needed */ log_data.misc[0] = aniState->pktRssi[0]; log_data.misc[1] = aniState->pktRssi[1]; log_data.misc[2] = aniState->ofdmErrRssi[0]; log_data.misc[3] = aniState->ofdmErrRssi[1]; log_data.misc[4] = aniState->cckErrRssi[0]; log_data.misc[5] = aniState->cckErrRssi[1]; if (inISR) ath_hal_log_ani(ah->ah_sc, &log_data, 1); // set interrupt context flag else ath_hal_log_ani(ah->ah_sc, &log_data, 0); // clear interrupt context flag } #endif return AH_TRUE; #undef N }
/* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) { typedef int TABLE[]; struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; const struct ar5212AniParams *params = aniState->params; OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd); switch (cmd) { case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; if (level >= params->maxNoiseImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: immunity level out of range (%u > %u)\n", __func__, level, params->maxNoiseImmunityLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]); OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]); if (level > aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { static const TABLE m1ThreshLow = { 127, 50 }; static const TABLE m2ThreshLow = { 127, 40 }; static const TABLE m1Thresh = { 127, 0x4d }; static const TABLE m2Thresh = { 127, 0x40 }; static const TABLE m2CountThr = { 31, 16 }; static const TABLE m2CountThrLow = { 63, 48 }; u_int on = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]); if (on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (on) ahp->ah_stats.ast_ani_ofdmon++; else ahp->ah_stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; break; } case HAL_ANI_CCK_WEAK_SIGNAL_THR: { static const TABLE weakSigThrCck = { 8, 6 }; u_int high = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); if (high) ahp->ah_stats.ast_ani_cckhigh++; else ahp->ah_stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = high; break; } case HAL_ANI_FIRSTEP_LEVEL: { u_int level = param; if (level >= params->maxFirstepLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: firstep level out of range (%u > %u)\n", __func__, level, params->maxFirstepLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]); if (level > aniState->firstepLevel) ahp->ah_stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) ahp->ah_stats.ast_ani_stepdown++; aniState->firstepLevel = level; break; } case HAL_ANI_SPUR_IMMUNITY_LEVEL: { u_int level = param; if (level >= params->maxSpurImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: spur immunity level out of range (%u > %u)\n", __func__, level, params->maxSpurImmunityLevel); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]); if (level > aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurdown++; aniState->spurImmunityLevel = level; break; } case HAL_ANI_PRESENT: break; case HAL_ANI_MODE: if (param == 0) { ahp->ah_procPhyErr &= ~HAL_ANI_ENA; /* Turn off HW counters if we have them */ ar5416AniDetach(ah); ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { /* normal/auto mode */ /* don't mess with state if already enabled */ if (ahp->ah_procPhyErr & HAL_ANI_ENA) break; ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); /* Enable MIB Counters */ enableAniMIBCounters(ah, ahp->ah_curani != AH_NULL ? ahp->ah_curani->params: &ahp->ah_aniParams24 /*XXX*/); ahp->ah_procPhyErr |= HAL_ANI_ENA; } break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid cmd %u\n", __func__, cmd); return AH_FALSE; } return AH_TRUE; }
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); }
void ar9280SpurMitigate(struct ath_hal *ah, const struct ieee80211_channel *chan) { static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; static int inc[4] = { 0, 100, 0, 0 }; int bb_spur = AR_NO_SPUR; int freq; int bin, cur_bin; int bb_spur_off, spur_subchannel_sd; int spur_freq_sd; int spur_delta_phase; int denominator; int upper, lower, cur_vit_mask; int tmp, newVal; int i; CHAN_CENTERS centers; int8_t mask_m[123]; int8_t mask_p[123]; int8_t mask_amt; int tmp_mask; int cur_bb_spur; HAL_BOOL is2GHz = IEEE80211_IS_CHAN_2GHZ(chan); OS_MEMZERO(&mask_m, sizeof(int8_t) * 123); OS_MEMZERO(&mask_p, sizeof(int8_t) * 123); ar5416GetChannelCenters(ah, chan, ¢ers); freq = centers.synth_center; /* * Need to verify range +/- 9.38 for static ht20 and +/- 18.75 for ht40, * otherwise spur is out-of-band and can be ignored. */ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); /* Get actual spur freq in MHz from EEPROM read value */ if (is2GHz) { cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; } else { cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; } if (AR_NO_SPUR == cur_bb_spur) break; cur_bb_spur = cur_bb_spur - freq; if (IEEE80211_IS_CHAN_HT40(chan)) { if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { bb_spur = cur_bb_spur; break; } } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { bb_spur = cur_bb_spur; break; } } if (AR_NO_SPUR == bb_spur) { #if 1 /* * MRC CCK can interfere with beacon detection and cause deaf/mute. * Disable MRC CCK for now. */ OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); #else /* Enable MRC CCK if no spur is found in this channel. */ OS_REG_SET_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); #endif return; } else { /* * For Merlin, spur can break CCK MRC algorithm. Disable CCK MRC if spur * is found in this channel. */ OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); } bin = bb_spur * 320; tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), newVal); newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | AR_PHY_SPUR_REG_ENABLE_MASK_PPM | AR_PHY_SPUR_REG_MASK_RATE_SELECT | AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | SM(AR5416_SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); OS_REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); /* Pick control or extn channel to cancel the spur */ if (IEEE80211_IS_CHAN_HT40(chan)) { if (bb_spur < 0) { spur_subchannel_sd = 1; bb_spur_off = bb_spur + 10; } else { spur_subchannel_sd = 0; bb_spur_off = bb_spur - 10; } } else { spur_subchannel_sd = 0; bb_spur_off = bb_spur; } /* * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, * /80 for dyn2040. */ if (IEEE80211_IS_CHAN_HT40(chan)) spur_delta_phase = ((bb_spur * 262144) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; else spur_delta_phase = ((bb_spur * 524288) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; /* * in 11A mode the denominator of spur_freq_sd should be 40 and * it should be 44 in 11G */ denominator = IEEE80211_IS_CHAN_2GHZ(chan) ? 44 : 40; spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); OS_REG_WRITE(ah, AR_PHY_TIMING11, newVal); /* Choose to cancel between control and extension channels */ newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; OS_REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); /* * ============================================ * Set Pilot and Channel Masks * * pilot mask 1 [31:0] = +6..-26, no 0 bin * pilot mask 2 [19:0] = +26..+7 * * channel mask 1 [31:0] = +6..-26, no 0 bin * channel mask 2 [19:0] = +26..+7 */ cur_bin = -6000; upper = bin + 100; lower = bin - 100; for (i = 0; i < 4; i++) { int pilot_mask = 0; int chan_mask = 0; int bp = 0; for (bp = 0; bp < 30; bp++) { if ((cur_bin > lower) && (cur_bin < upper)) { pilot_mask = pilot_mask | 0x1 << bp; chan_mask = chan_mask | 0x1 << bp; } cur_bin += 100; } cur_bin += inc[i]; OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); } /* ================================================= * viterbi mask 1 based on channel magnitude * four levels 0-3 * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) * [1 2 2 1] for -9.6 or [1 2 1] for +16 * - enable_mask_ppm, all bins move with freq * * - mask_select, 8 bits for rates (reg 67,0x990c) * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) * choose which mask to use mask or mask2 */ /* * viterbi mask 2 2nd set for per data rate puncturing * four levels 0-3 * - mask_select, 8 bits for rates (reg 67) * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) * [1 2 2 1] for -9.6 or [1 2 1] for +16 */ cur_vit_mask = 6100; upper = bin + 120; lower = bin - 120; for (i = 0; i < 123; i++) { if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { if ((abs(cur_vit_mask - bin)) < 75) { mask_amt = 1; } else { mask_amt = 0; } if (cur_vit_mask < 0) { mask_m[abs(cur_vit_mask / 100)] = mask_amt; } else { mask_p[cur_vit_mask / 100] = mask_amt; } } cur_vit_mask -= 100; } tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) | (mask_m[48] << 26) | (mask_m[49] << 24) | (mask_m[50] << 22) | (mask_m[51] << 20) | (mask_m[52] << 18) | (mask_m[53] << 16) | (mask_m[54] << 14) | (mask_m[55] << 12) | (mask_m[56] << 10) | (mask_m[57] << 8) | (mask_m[58] << 6) | (mask_m[59] << 4) | (mask_m[60] << 2) | (mask_m[61] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); tmp_mask = (mask_m[31] << 28) | (mask_m[32] << 26) | (mask_m[33] << 24) | (mask_m[34] << 22) | (mask_m[35] << 20) | (mask_m[36] << 18) | (mask_m[37] << 16) | (mask_m[48] << 14) | (mask_m[39] << 12) | (mask_m[40] << 10) | (mask_m[41] << 8) | (mask_m[42] << 6) | (mask_m[43] << 4) | (mask_m[44] << 2) | (mask_m[45] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) | (mask_m[18] << 26) | (mask_m[18] << 24) | (mask_m[20] << 22) | (mask_m[20] << 20) | (mask_m[22] << 18) | (mask_m[22] << 16) | (mask_m[24] << 14) | (mask_m[24] << 12) | (mask_m[25] << 10) | (mask_m[26] << 8) | (mask_m[27] << 6) | (mask_m[28] << 4) | (mask_m[29] << 2) | (mask_m[30] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) | (mask_m[10] << 10) | (mask_m[11] << 8) | (mask_m[12] << 6) | (mask_m[13] << 4) | (mask_m[14] << 2) | (mask_m[15] << 0); OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); tmp_mask = (mask_p[15] << 28) | (mask_p[14] << 26) | (mask_p[13] << 24) | (mask_p[12] << 22) | (mask_p[11] << 20) | (mask_p[10] << 18) | (mask_p[ 9] << 16) | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); tmp_mask = (mask_p[30] << 28) | (mask_p[29] << 26) | (mask_p[28] << 24) | (mask_p[27] << 22) | (mask_p[26] << 20) | (mask_p[25] << 18) | (mask_p[24] << 16) | (mask_p[23] << 14) | (mask_p[22] << 12) | (mask_p[21] << 10) | (mask_p[20] << 8) | (mask_p[19] << 6) | (mask_p[18] << 4) | (mask_p[17] << 2) | (mask_p[16] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); tmp_mask = (mask_p[45] << 28) | (mask_p[44] << 26) | (mask_p[43] << 24) | (mask_p[42] << 22) | (mask_p[41] << 20) | (mask_p[40] << 18) | (mask_p[39] << 16) | (mask_p[38] << 14) | (mask_p[37] << 12) | (mask_p[36] << 10) | (mask_p[35] << 8) | (mask_p[34] << 6) | (mask_p[33] << 4) | (mask_p[32] << 2) | (mask_p[31] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) | (mask_p[59] << 26) | (mask_p[58] << 24) | (mask_p[57] << 22) | (mask_p[56] << 20) | (mask_p[55] << 18) | (mask_p[54] << 16) | (mask_p[53] << 14) | (mask_p[52] << 12) | (mask_p[51] << 10) | (mask_p[50] << 8) | (mask_p[49] << 6) | (mask_p[48] << 4) | (mask_p[47] << 2) | (mask_p[46] << 0); OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); }
static HAL_BOOL ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan) { static const uint32_t ar5416_cca_regs[] = { AR_PHY_CCA, AR_PHY_CH1_CCA, AR_PHY_CH2_CCA, AR_PHY_EXT_CCA, AR_PHY_CH1_EXT_CCA, AR_PHY_CH2_EXT_CCA }; struct ar5212NfCalHist *h; int i; int32_t val; uint8_t chainmask; int16_t default_nf = ar5416GetDefaultNF(ah, chan); /* * Force NF calibration for all chains. */ if (AR_SREV_KITE(ah)) { /* Kite has only one chain */ chainmask = 0x9; } else if (AR_SREV_MERLIN(ah) || AR_SREV_KIWI(ah)) { /* Merlin/Kiwi has only two chains */ chainmask = 0x1B; } else { chainmask = 0x3F; } /* * Write filtered NF values into maxCCApwr register parameter * so we can load below. */ h = AH5416(ah)->ah_cal.nfCalHist; HALDEBUG(ah, HAL_DEBUG_NFCAL, "CCA: "); for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { /* Don't write to EXT radio CCA registers unless in HT/40 mode */ /* XXX this check should really be cleaner! */ if (i > 2 && !IEEE80211_IS_CHAN_HT40(chan)) continue; if (chainmask & (1 << i)) { int16_t nf_val; if (h) nf_val = h[i].privNF; else nf_val = default_nf; val = OS_REG_READ(ah, ar5416_cca_regs[i]); val &= 0xFFFFFE00; val |= (((uint32_t) nf_val << 1) & 0x1ff); HALDEBUG(ah, HAL_DEBUG_NFCAL, "[%d: %d]", i, nf_val); OS_REG_WRITE(ah, ar5416_cca_regs[i], val); } } HALDEBUG(ah, HAL_DEBUG_NFCAL, "\n"); /* Load software filtered NF value into baseband internal minCCApwr variable. */ OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); /* Wait for load to complete, should be fast, a few 10s of us. */ if (! ar5212WaitNFCalComplete(ah, 1000)) { /* * We timed out waiting for the noisefloor to load, probably due to an * in-progress rx. Simply return here and allow the load plenty of time * to complete before the next calibration interval. We need to avoid * trying to load -50 (which happens below) while the previous load is * still in progress as this can cause rx deafness. Instead by returning * here, the baseband nf cal will just be capped by our present * noisefloor until the next calibration timer. */ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "Timeout while waiting for " "nf to load: AR_PHY_AGC_CONTROL=0x%x\n", OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); return AH_FALSE; } /* * Restore maxCCAPower register parameter again so that we're not capped * by the median we just loaded. This will be initial (and max) value * of next noise floor calibration the baseband does. */ for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { /* Don't write to EXT radio CCA registers unless in HT/40 mode */ /* XXX this check should really be cleaner! */ if (i > 2 && !IEEE80211_IS_CHAN_HT40(chan)) continue; if (chainmask & (1 << i)) { val = OS_REG_READ(ah, ar5416_cca_regs[i]); val &= 0xFFFFFE00; val |= (((uint32_t)(-50) << 1) & 0x1ff); OS_REG_WRITE(ah, ar5416_cca_regs[i], val); } } return AH_TRUE; }
/* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) { #define N(a) (sizeof(a)/sizeof(a[0])) typedef int TABLE[]; struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; switch (cmd) { case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; if (level >= N(ahp->ah_totalSizeDesired)) { HALDEBUG(ah, "%s: level out of range (%u > %u)\n", __func__, level, N(ahp->ah_totalSizeDesired)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, ahp->ah_totalSizeDesired[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, ahp->ah_coarseLow[level]); OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, ahp->ah_coarseHigh[level]); OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, ahp->ah_firpwr[level]); if (level > aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) ahp->ah_stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { const TABLE m1ThreshLow = { 127, 50 }; const TABLE m2ThreshLow = { 127, 40 }; const TABLE m1Thresh = { 127, 0x4d }; const TABLE m2Thresh = { 127, 0x40 }; const TABLE m2CountThr = { 31, 16 }; const TABLE m2CountThrLow = { 63, 48 }; u_int on = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]); if (on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (!on != aniState->ofdmWeakSigDetectOff) { if (on) ahp->ah_stats.ast_ani_ofdmon++; else ahp->ah_stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; } break; } case HAL_ANI_CCK_WEAK_SIGNAL_THR: { const TABLE weakSigThrCck = { 8, 6 }; u_int high = param ? 1 : 0; OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]); if (high != aniState->cckWeakSigThreshold) { if (high) ahp->ah_stats.ast_ani_cckhigh++; else ahp->ah_stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = high; } break; } case HAL_ANI_FIRSTEP_LEVEL: { const TABLE firstep = { 0, 4, 8 }; u_int level = param; if (level >= N(firstep)) { HALDEBUG(ah, "%s: level out of range (%u > %u)\n", __func__, level, N(firstep)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, firstep[level]); if (level > aniState->firstepLevel) ahp->ah_stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) ahp->ah_stats.ast_ani_stepdown++; aniState->firstepLevel = level; break; } case HAL_ANI_SPUR_IMMUNITY_LEVEL: { const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }; u_int level = param; if (level >= N(cycpwrThr1)) { HALDEBUG(ah, "%s: level out of range (%u > %u)\n", __func__, level, N(cycpwrThr1)); return AH_FALSE; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]); if (level > aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) ahp->ah_stats.ast_ani_spurdown++; aniState->spurImmunityLevel = level; break; } case HAL_ANI_PRESENT: break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_MODE: if (param == 0) { ahp->ah_procPhyErr &= ~HAL_PROCESS_ANI; /* Turn off HW counters if we have them */ ar5212AniDetach(ah); ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { /* normal/auto mode */ ahp->ah_procPhyErr |= HAL_PROCESS_ANI; if (ahp->ah_hasHwPhyCounters) { ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { ar5212SetRxFilter(ah, ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); } } break; case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: HALDEBUG(ah, "%s: invalid cmd %u\n", __func__, cmd); return AH_FALSE; } return AH_TRUE; #undef N }
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); } }
/* * Enable radar detection and set the radar parameters per the * values in pe */ void ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) { uint32_t val; val = OS_REG_READ(ah, AR_PHY_RADAR_0); if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_FIRPWR; val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR); } if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_RRSSI; val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI); } if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_HEIGHT; val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT); } if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_PRSSI; val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI); } if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) { val &= ~AR_PHY_RADAR_0_INBAND; val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND); } /*Enable FFT data*/ val |= AR_PHY_RADAR_0_FFT_ENA; OS_REG_WRITE(ah, AR_PHY_RADAR_0, val); /* Implicitly enable */ if (pe->pe_enabled == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); else if (pe->pe_enabled == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); if (pe->pe_usefir128 == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); else if (pe->pe_usefir128 == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); if (pe->pe_enmaxrssi == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); else if (pe->pe_enmaxrssi == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); if (pe->pe_blockradar == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); else if (pe->pe_blockradar == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) { val = OS_REG_READ(ah, AR_PHY_RADAR_1); val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH; val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH); OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); } if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) { val = OS_REG_READ(ah, AR_PHY_RADAR_1); val &= ~AR_PHY_RADAR_1_RELPWR_THRESH; val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH); OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); } if (pe->pe_en_relstep_check == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_RELSTEP_CHECK); else if (pe->pe_en_relstep_check == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_RELSTEP_CHECK); if (pe->pe_enrelpwr == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_RELPWR_ENA); else if (pe->pe_enrelpwr == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_RELPWR_ENA); if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) { val = OS_REG_READ(ah, AR_PHY_RADAR_1); val &= ~AR_PHY_RADAR_1_MAXLEN; val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN); OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); } /* * Enable HT/40 if the upper layer asks; * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS * is available. */ if (pe->pe_extchannel == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); else if (pe->pe_extchannel == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); }