/* * Once configured for I/O - get input lines */ u_int32_t ar5416GpioGet(struct ath_hal *ah, u_int32_t gpio) { HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.hal_num_gpio_pins); if (gpio >= AH_PRIVATE(ah)->ah_caps.hal_num_gpio_pins) { return 0xffffffff; } // Read output value for all gpio's, shift it left, and verify whether a // specific gpio bit is set. if(AR_SREV_K2(ah)) { u_int32_t val; val = OS_REG_READ(ah, AR_GPIO_IN_OUT); if (val == (u_int32_t)(-1)) { return 0; } else { return (MS(val, AR9271_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; } } else if (AR_SREV_KIWI_10_OR_LATER(ah)) { return (MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9287_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; } else if (AR_SREV_KITE_10_OR_LATER(ah)) { return (MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; } else if (AR_SREV_MERLIN_10_OR_LATER(ah)) { return (MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; } else { return (MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; } }
HAL_BOOL ar9285InitCalHardware(struct ath_hal *ah, const struct ieee80211_channel *chan) { if (AR_SREV_KITE(ah) && AR_SREV_KITE_10_OR_LATER(ah) && (! ar9285_hw_clc(ah, chan))) return AH_FALSE; return AH_TRUE; }
/* * Once configured for I/O - get input lines */ uint32_t ar5416GpioGet(struct ath_hal *ah, uint32_t gpio) { uint32_t bits; if (gpio >= AH_PRIVATE(ah)->ah_caps.halNumGpioPins) return 0xffffffff; /* * Read output value for all gpio's, shift it, * and verify whether the specific bit is set. */ if (AR_SREV_KITE_10_OR_LATER(ah)) bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL); else if (AR_SREV_MERLIN_10_OR_LATER(ah)) bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL); else bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL); return ((bits & AR_GPIO_BIT(gpio)) != 0); }
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 ar5416WowApplyPattern(struct ath_hal *ah, u_int8_t *p_ath_pattern, u_int8_t *p_ath_mask, int32_t pattern_count, u_int32_t athPatternLen) { int i; u_int32_t reg_pat[] = { AR_WOW_TB_PATTERN0, AR_WOW_TB_PATTERN1, AR_WOW_TB_PATTERN2, AR_WOW_TB_PATTERN3, AR_WOW_TB_PATTERN4, AR_WOW_TB_PATTERN5, AR_WOW_TB_PATTERN6, AR_WOW_TB_PATTERN7 }; u_int32_t reg_mask[] = { AR_WOW_TB_MASK0, AR_WOW_TB_MASK1, AR_WOW_TB_MASK2, AR_WOW_TB_MASK3, AR_WOW_TB_MASK4, AR_WOW_TB_MASK5, AR_WOW_TB_MASK6, AR_WOW_TB_MASK7 }; u_int32_t pattern_val; u_int32_t mask_val; u_int8_t mask_bit = 0x1; u_int8_t pattern; /* TBD: should check count by querying the hardware capability */ if (pattern_count >= MAX_NUM_USER_PATTERN) { return; } pattern = (u_int8_t)OS_REG_READ(ah, AR_WOW_PATTERN_REG); pattern = pattern | (mask_bit << pattern_count); OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, pattern); /* Set the registers for pattern */ for (i = 0; i < MAX_PATTERN_SIZE; i+=4) { pattern_val = (((u_int32_t)p_ath_pattern[i]) | ((u_int32_t)p_ath_pattern[i+1] << 8) | ((u_int32_t)p_ath_pattern[i+2] << 16) | ((u_int32_t)p_ath_pattern[i+3] << 24)); OS_REG_WRITE(ah, (reg_pat[pattern_count] + i), pattern_val); } /* Set the registers for mask */ for (i = 0; i < MAX_PATTERN_MASK_SIZE; i+=4) { mask_val = (((u_int32_t)p_ath_mask[i]) | ((u_int32_t)p_ath_mask[i+1] << 8) | ((u_int32_t)p_ath_mask[i+2] << 16) | ((u_int32_t)p_ath_mask[i+3] << 24)); OS_REG_WRITE(ah, (reg_mask[pattern_count] + i), mask_val); } if (AR_SREV_KITE_10_OR_LATER(ah)) { /* Set the pattern length to be matched */ u_int32_t val; if (pattern_count < 4) { /* Pattern 0-3 uses AR_WOW_LENGTH1_REG register */ val = OS_REG_READ(ah, AR_WOW_LENGTH1_REG); val = ((val & (~AR_WOW_LENGTH1_MASK(pattern_count))) | ((athPatternLen & AR_WOW_LENGTH_MAX) << AR_WOW_LENGTH1_SHIFT(pattern_count))); OS_REG_WRITE(ah, AR_WOW_LENGTH1_REG, val); } else { /* Pattern 4-7 uses AR_WOW_LENGTH2_REG register */ val = OS_REG_READ(ah, AR_WOW_LENGTH2_REG); val = ((val & (~AR_WOW_LENGTH2_MASK(pattern_count))) | ((athPatternLen & AR_WOW_LENGTH_MAX) << AR_WOW_LENGTH2_SHIFT(pattern_count))); OS_REG_WRITE(ah, AR_WOW_LENGTH2_REG, val); } } AH_PRIVATE(ah)->ah_wow_event_mask |= (1 << (pattern_count + AR_WOW_PATTERN_FOUND_SHIFT)); return; }