Path: blob/main/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c
48526 views
/*1* Copyright (c) 2013 Qualcomm Atheros, Inc.2*3* Permission to use, copy, modify, and/or distribute this software for any4* purpose with or without fee is hereby granted, provided that the above5* copyright notice and this permission notice appear in all copies.6*7* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH8* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY9* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,10* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM11* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR12* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR13* PERFORMANCE OF THIS SOFTWARE.14*/1516#include "opt_ah.h"1718#include "ah.h"19#include "ah_internal.h"2021#include "ar9300/ar9300.h"22#include "ar9300/ar9300reg.h"2324#if ATH_WOW_OFFLOAD25void ar9300_wowoffload_prep(struct ath_hal *ah)26{27struct ath_hal_9300 *ahp = AH9300(ah);2829ahp->ah_mcast_filter_l32_set = 0;30ahp->ah_mcast_filter_u32_set = 0;31}3233void ar9300_wowoffload_post(struct ath_hal *ah)34{35struct ath_hal_9300 *ahp = AH9300(ah);36u_int32_t val;3738if (ahp->ah_mcast_filter_l32_set != 0) {39val = OS_REG_READ(ah, AR_MCAST_FIL0);40val &= ~ahp->ah_mcast_filter_l32_set;41OS_REG_WRITE(ah, AR_MCAST_FIL0, val);42}43if (ahp->ah_mcast_filter_u32_set != 0) {44val = OS_REG_READ(ah, AR_MCAST_FIL1);45val &= ~ahp->ah_mcast_filter_u32_set;46OS_REG_WRITE(ah, AR_MCAST_FIL1, val);47}4849ahp->ah_mcast_filter_l32_set = 0;50ahp->ah_mcast_filter_u32_set = 0;51}5253static void ar9300_wowoffload_add_mcast_filter(struct ath_hal *ah, u_int8_t *mc_addr)54{55struct ath_hal_9300 *ahp = AH9300(ah);56u_int32_t reg, val;57u_int8_t pos, high32;5859memcpy((u_int8_t *) &val, &mc_addr[0], 3);60pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;61memcpy((u_int8_t *) &val, &mc_addr[3], 3);62pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;63high32 = pos & 0x20;64reg = high32 ? AR_MCAST_FIL1 : AR_MCAST_FIL0;65pos &= 0x1F;6667val = OS_REG_READ(ah, reg);68if ((val & (1 << pos)) == 0) {69val |= (1 << pos);70if (high32) {71ahp->ah_mcast_filter_u32_set |= (1 << pos);72} else {73ahp->ah_mcast_filter_l32_set |= (1 << pos);74}75OS_REG_WRITE(ah, reg, val);76}77}7879/*80* DeviceID SWAR - EV9192881*82* During SW WOW, 0x4004[13] is set to allow BT eCPU to access WLAN MAC83* registers. Setting 00x4004[13] will prevent eeprom state machine to84* load customizable PCIE configuration registers, which lead to the PCIE85* device id stay as default 0xABCD. The SWAR to have BT eCPU to write86* to PCIE registers as soon as it detects PCIE reset is deasserted.87*/88void ar9300_wowoffload_download_devid_swar(struct ath_hal *ah)89{90u_int32_t addr = AR_WOW_OFFLOAD_WLAN_REGSET_NUM;9192OS_REG_WRITE(ah, addr, 8);93addr += 4;94OS_REG_WRITE(ah, addr, 0x5000);95addr += 4;96HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_000 = %08x\n",97AH_PRIVATE(ah)->ah_config.ath_hal_pcie_000);98OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_000);99addr += 4;100OS_REG_WRITE(ah, addr, 0x5008);101addr += 4;102HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_008 = %08x\n",103AH_PRIVATE(ah)->ah_config.ath_hal_pcie_008);104OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_008);105addr += 4;106OS_REG_WRITE(ah, addr, 0x502c);107addr += 4;108HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_02c = %08x\n",109AH_PRIVATE(ah)->ah_config.ath_hal_pcie_02c);110OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_02c);111addr += 4;112OS_REG_WRITE(ah, addr, 0x18c00);113addr += 4;114OS_REG_WRITE(ah, addr, 0x18212ede);115addr += 4;116OS_REG_WRITE(ah, addr, 0x18c04);117addr += 4;118OS_REG_WRITE(ah, addr, 0x008001d8);119addr += 4;120OS_REG_WRITE(ah, addr, 0x18c08);121addr += 4;122OS_REG_WRITE(ah, addr, 0x0003580c);123addr += 4;124OS_REG_WRITE(ah, addr, 0x570c);125addr += 4;126HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_70c = %08x\n",127AH_PRIVATE(ah)->ah_config.ath_hal_pcie_70c);128OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_70c);129addr += 4;130OS_REG_WRITE(ah, addr, 0x5040);131addr += 4;132HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_040 = %08x\n",133AH_PRIVATE(ah)->ah_config.ath_hal_pcie_040);134OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_040);135addr += 4;136/*137A_SOC_REG_WRITE(0x45000, 0x0034168c);138A_SOC_REG_WRITE(0x45008, 0x02800001);139A_SOC_REG_WRITE(0x4502c, 0x3117168c);140A_SOC_REG_WRITE(0x58c00, 0x18212ede);141A_SOC_REG_WRITE(0x58c04, 0x000801d8);142A_SOC_REG_WRITE(0x58c08, 0x0003580c);143A_SOC_REG_WRITE(0x4570c, 0x275f3f01);144A_SOC_REG_WRITE(0x45040, 0xffc25001);145*/146}147148/* Retrieve updated information from MAC PCU buffer.149* Embedded CPU would have written the value before exiting WoW150* */151void ar9300_wowoffload_retrieve_data(struct ath_hal *ah, void *buf, u_int32_t param)152{153u_int32_t rc_lower, rc_upper;154155if (param == WOW_PARAM_REPLAY_CNTR) {156rc_lower = OS_REG_READ(ah, AR_WOW_TXBUF(0));157rc_upper = OS_REG_READ(ah, AR_WOW_TXBUF(1));158*(u_int64_t *)buf = rc_lower + (rc_upper << 32);159}160else if (param == WOW_PARAM_KEY_TSC) {161rc_lower = OS_REG_READ(ah, AR_WOW_TXBUF(2));162rc_upper = OS_REG_READ(ah, AR_WOW_TXBUF(3));163*(u_int64_t *)buf = rc_lower + (rc_upper << 32);164}165else if (param == WOW_PARAM_TX_SEQNUM) {166*(u_int32_t *)buf = OS_REG_READ(ah, AR_WOW_TXBUF(4));167}168169}170171/* Download GTK rekey related information to the embedded CPU */172u_int32_t ar9300_wowoffload_download_rekey_data(struct ath_hal *ah, u_int32_t *data, u_int32_t bytes)173{174int i;175int mbox_status = OS_REG_READ(ah, AR_MBOX_CTRL_STATUS);176u_int32_t gtk_data_start;177178HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) %s, bytes=%d\n", __func__, bytes);179if (AR_SREV_JUPITER(ah) &&180(bytes > (AR_WOW_OFFLOAD_GTK_DATA_WORDS_JUPITER * 4)))181{182bytes = AR_WOW_OFFLOAD_GTK_DATA_WORDS_JUPITER * 4;183HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) bytes truncated to %d\n", bytes);184}185/* Check if mailbox is busy */186if (mbox_status != 0) {187HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: Mailbox register busy! Reg = 0x%x", __func__, mbox_status);188return 1;189}190191/* Clear status */192OS_REG_WRITE(ah, AR_EMB_CPU_WOW_STATUS, 0x0);193OS_REG_WRITE(ah, AR_WLAN_WOW_ENABLE, 0);194OS_REG_WRITE(ah, AR_WLAN_WOW_STATUS, 0xFFFFFFFF);195196if (AR_SREV_JUPITER(ah)) {197gtk_data_start = AR_WOW_OFFLOAD_GTK_DATA_START_JUPITER;198} else {199gtk_data_start = AR_WOW_OFFLOAD_GTK_DATA_START;200}201for (i = 0;i < bytes/4; i++) {202OS_REG_WRITE(ah, gtk_data_start + i * 4, data[i]);203}204205return 0;206}207208void ar9300_wowoffload_download_acer_magic( struct ath_hal *ah,209HAL_BOOL valid,210u_int8_t* datap,211u_int32_t bytes)212{213u_int32_t *p32 = (u_int32_t *) datap;214u_int32_t l = 0, u = 0;215216if (valid) {217l = *p32;218p32++;219u = *(u_int16_t *) p32;220}221222OS_REG_WRITE(ah, AR_WOW_OFFLOAD_ACER_MAGIC_START, l);223OS_REG_WRITE(ah, AR_WOW_OFFLOAD_ACER_MAGIC_START + 4, u);224225HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,226"%s: Aer Magic: %02x-%02x-%02x-%02x-%02x-%02x\n", __func__,227datap[0], datap[1], datap[2], datap[3], datap[4], datap[5]);228}229230void ar9300_wowoffload_download_acer_swka( struct ath_hal *ah,231u_int32_t id,232HAL_BOOL valid,233u_int32_t period,234u_int32_t size,235u_int32_t* datap)236{237u_int32_t ka_period[2] = {238AR_WOW_OFFLOAD_ACER_KA0_PERIOD_MS,239AR_WOW_OFFLOAD_ACER_KA1_PERIOD_MS240};241u_int32_t ka_size[2] = {242AR_WOW_OFFLOAD_ACER_KA0_SIZE,243AR_WOW_OFFLOAD_ACER_KA1_SIZE244};245u_int32_t ka_data[2] = {246AR_WOW_OFFLOAD_ACER_KA0_DATA,247AR_WOW_OFFLOAD_ACER_KA1_DATA248};249u_int32_t n_data = AR_WOW_OFFLOAD_ACER_KA0_DATA_WORDS;250int i;251252if (id >= 2) {253return;254}255256if (valid) {257OS_REG_WRITE(ah, ka_period[id], period);258OS_REG_WRITE(ah, ka_size[id], size);259} else {260OS_REG_WRITE(ah, ka_period[id], 0);261OS_REG_WRITE(ah, ka_size[id], 0);262}263HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: id=%d, period=%d ms, size=%d bytes\n",264__func__, id, period, size);265266if (size < (n_data * 4)) {267n_data = (size + 3) / 4;268}269for (i=0; i<n_data * 4; i+=4) {270OS_REG_WRITE(ah, ka_data[id] + i, *datap);271/*HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) %08x\n", *datap);*/272datap++;273}274}275276void ar9300_wowoffload_download_arp_info(struct ath_hal *ah, u_int32_t id, u_int32_t *data)277{278u_int32_t addr;279struct hal_wow_offload_arp_info *p_info = (struct hal_wow_offload_arp_info *) data;280281if (id == 0) {282addr = AR_WOW_OFFLOAD_ARP0_VALID;283} else if (id == 1) {284addr = AR_WOW_OFFLOAD_ARP1_VALID;285} else {286return;287}288289if (p_info->valid) {290OS_REG_WRITE(ah, addr, 0x1);291addr += 4;292OS_REG_WRITE(ah, addr, p_info->RemoteIPv4Address.u32);293addr += 4;294OS_REG_WRITE(ah, addr, p_info->HostIPv4Address.u32);295addr += 4;296OS_REG_WRITE(ah, addr, p_info->MacAddress.u32[0]);297addr += 4;298OS_REG_WRITE(ah, addr, p_info->MacAddress.u32[1]);299} else {300OS_REG_WRITE(ah, addr, 0x0);301}302}303304#define WOW_WRITE_NS_IPV6_ADDRESS(_ah, _buf_addr, _p_ipv6_addr) \305{ \306u_int32_t offset = (_buf_addr); \307u_int32_t *p_ipv6_addr = (u_int32_t *) (_p_ipv6_addr); \308int i; \309for (i = 0; i < 4; i++) { \310OS_REG_WRITE((_ah), offset, *p_ipv6_addr); \311offset += 4; \312p_ipv6_addr ++; \313} \314}315316void ar9300_wowoffload_download_ns_info(struct ath_hal *ah, u_int32_t id, u_int32_t *data)317{318u_int32_t addr;319struct hal_wow_offload_ns_info *p_info = (struct hal_wow_offload_ns_info *) data;320u_int8_t mc_addr[6];321322if (id == 0) {323addr = AR_WOW_OFFLOAD_NS0_VALID;324} else if (id == 1) {325addr = AR_WOW_OFFLOAD_NS1_VALID;326} else {327return;328}329330if (p_info->valid) {331OS_REG_WRITE(ah, addr, 0x1);332addr += 4;333WOW_WRITE_NS_IPV6_ADDRESS(ah, addr, &p_info->RemoteIPv6Address.u32[0]);334addr += 4 * 4;335WOW_WRITE_NS_IPV6_ADDRESS(ah, addr, &p_info->SolicitedNodeIPv6Address.u32[0]);336addr += 4 * 4;337OS_REG_WRITE(ah, addr, p_info->MacAddress.u32[0]);338addr += 4;339OS_REG_WRITE(ah, addr, p_info->MacAddress.u32[1]);340addr += 4;341WOW_WRITE_NS_IPV6_ADDRESS(ah, addr, &p_info->TargetIPv6Addresses[0].u32[0]);342addr += 4 * 4;343WOW_WRITE_NS_IPV6_ADDRESS(ah, addr, &p_info->TargetIPv6Addresses[1].u32[0]);344345mc_addr[0] = 0x33;346mc_addr[1] = 0x33;347mc_addr[2] = 0xFF;348mc_addr[3] = p_info->SolicitedNodeIPv6Address.u8[13];349mc_addr[4] = p_info->SolicitedNodeIPv6Address.u8[14];350mc_addr[5] = p_info->SolicitedNodeIPv6Address.u8[15];351ar9300_wowoffload_add_mcast_filter(ah, mc_addr);352} else {353OS_REG_WRITE(ah, addr, 0x0);354}355}356357/* Download transmit parameters for GTK response frame during WoW358* offload */359u_int32_t ar9300_wow_offload_download_hal_params(struct ath_hal *ah)360{361u_int32_t tpc = 0x3f; /* Transmit Power Control */362u_int32_t tx_tries_series = 7;363u_int32_t tx_rate_series, transmit_rate;364u_int32_t gtk_txdesc_param_start;365366if (AH_PRIVATE(ah)->ah_curchan->channel_flags & CHANNEL_CCK) {367transmit_rate = 0x1B; /* CCK_1M */368} else {369transmit_rate = 0xB; /* OFDM_6M */370}371372/* Use single rate for now. Change later as need be */373tx_rate_series = transmit_rate;374tx_tries_series = 7;375376if (AR_SREV_JUPITER(ah)) {377gtk_txdesc_param_start = AR_WOW_OFFLOAD_GTK_TXDESC_PARAM_START_JUPITER;378} else {379gtk_txdesc_param_start = AR_WOW_OFFLOAD_GTK_TXDESC_PARAM_START;380}381#define AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(x) (gtk_txdesc_param_start + ((x) * 4))382383/* Do not change the data order unless firmware code on embedded384* CPU is changed correspondingly */385OS_REG_WRITE(ah, AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(0), tx_rate_series);386OS_REG_WRITE(ah, AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(1), tx_tries_series);387OS_REG_WRITE(ah, AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(2), AH9300(ah)->ah_tx_chainmask);388OS_REG_WRITE(ah, AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(3), tpc);389390return 0;391}392393/* Indicate to the embedded CPU that host is ready to enter WoW mode.394* Embedded CPU will copy relevant information from the MAC PCU buffer395*/396u_int32_t ar9300_wow_offload_handshake(struct ath_hal *ah, u_int32_t pattern_enable)397{398int val;399int mbox_status = OS_REG_READ(ah, AR_MBOX_CTRL_STATUS);400#if ATH_WOW_OFFLOAD401u_int32_t bt_handshake_timeout_us = HAL_WOW_CTRL_WAIT_BT_TO(ah) * 100000;402403#define AH_DEFAULT_BT_WAIT_TIMEOUT 3000000; /* 3 sec */404if (bt_handshake_timeout_us == 0) {405bt_handshake_timeout_us = AH_DEFAULT_BT_WAIT_TIMEOUT;406}407HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) TIMEOUT: %d us\n", bt_handshake_timeout_us);408#endif /* ATH_WOW_OFFLOAD */409410if (mbox_status & AR_MBOX_WOW_REQ) {411/* WOW mode request handshake is already in progress.412* Do nothing */413return 0;414}415416/* Clear status */417OS_REG_WRITE(ah, AR_MBOX_CTRL_STATUS, 0);418OS_REG_WRITE(ah, AR_EMB_CPU_WOW_STATUS, 0x0);419OS_REG_WRITE(ah, AR_WLAN_WOW_ENABLE, 0);420OS_REG_WRITE(ah, AR_WLAN_WOW_STATUS, 0xFFFFFFFF);421422OS_REG_WRITE(ah, AR_RIMT, 0);423OS_REG_WRITE(ah, AR_TIMT, 0);424425val = 0;426if (pattern_enable & AH_WOW_USER_PATTERN_EN) {427HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - User pattern\n");428val |= AR_EMB_CPU_WOW_ENABLE_PATTERN_MATCH;429}430else {431HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - User pattern\n");432}433if ((pattern_enable & AH_WOW_MAGIC_PATTERN_EN)434#if ATH_WOW_OFFLOAD435|| (pattern_enable & AH_WOW_ACER_MAGIC_EN)436#endif437)438{439val |= AR_EMB_CPU_WOW_ENABLE_MAGIC_PATTERN;440HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Magic pattern\n");441}442else {443HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Magic pattern\n");444}445if ((pattern_enable & AH_WOW_LINK_CHANGE)446#if ATH_WOW_OFFLOAD447|| HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_KAFAIL_ENABLE)448#endif449)450{451val |= AR_EMB_CPU_WOW_ENABLE_KEEP_ALIVE_FAIL;452HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Kepp alive fail\n");453}454else {455HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Kepp alive fail\n");456}457if (pattern_enable & AH_WOW_BEACON_MISS) {458val |= AR_EMB_CPU_WOW_ENABLE_BEACON_MISS;459HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Becon Miss\n");460}461else {462HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Becon Miss\n");463}464465OS_REG_WRITE(ah, AR_EMB_CPU_WOW_ENABLE, val);466467OS_REG_CLR_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_CONF);468OS_REG_SET_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_REQ);469OS_REG_SET_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_INT_EMB_CPU);470471if (!ath_hal_waitfor(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_CONF, AR_MBOX_WOW_CONF, bt_handshake_timeout_us)) {472HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: WoW offload handshake failed", __func__);473return 0;474}475else {476OS_REG_CLR_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_CONF);477HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: WoW offload handshake successful",__func__);478}479return 1;480}481#endif /* ATH_WOW_OFFLOAD */482483/*484* Notify Power Mgt is enabled in self-generated frames.485* If requested, force chip awake.486*487* Returns A_OK if chip is awake or successfully forced awake.488*489* WARNING WARNING WARNING490* There is a problem with the chip where sometimes it will not wake up.491*/492HAL_BOOL493ar9300_set_power_mode_awake(struct ath_hal *ah, int set_chip)494{495struct ath_hal_9300 *ahp = AH9300(ah);496#define POWER_UP_TIME 10000497u_int32_t val;498int i;499500/* Set Bits 14 and 17 of AR_WA before powering on the chip. */501OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), ahp->ah_wa_reg_val);502OS_DELAY(10); /* delay to allow the write to take effect. */503504if (set_chip) {505/* Do a Power-On-Reset if MAC is shutdown */506if ((OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_SHUTDOWN)) {507if (ar9300_set_reset_reg(ah, HAL_RESET_POWER_ON) != AH_TRUE) {508HALASSERT(0);509return AH_FALSE;510}511}512513OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);514515OS_DELAY(50);516517for (i = POWER_UP_TIME / 50; i > 0; i--) {518val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;519if (val == AR_RTC_STATUS_ON) {520break;521}522OS_DELAY(50);523OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);524}525if (i == 0) {526HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: Failed to wakeup in %uus\n",527__func__, POWER_UP_TIME / 20);528return AH_FALSE;529}530531}532533OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);534return AH_TRUE;535#undef POWER_UP_TIME536}537538/*539* Notify Power Mgt is disabled in self-generated frames.540* If requested, force chip to sleep.541*/542static void543ar9300_set_power_mode_sleep(struct ath_hal *ah, int set_chip)544{545struct ath_hal_9300 *ahp = AH9300(ah);546547OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);548if (set_chip ) {549if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {550OS_REG_WRITE(ah, AR_TIMER_MODE,551OS_REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00);552OS_REG_WRITE(ah, AR_GEN_TIMERS2_MODE,553OS_REG_READ(ah, AR_GEN_TIMERS2_MODE) & 0xFFFFFF00);554OS_REG_WRITE(ah, AR_SLP32_INC,555OS_REG_READ(ah, AR_SLP32_INC) & 0xFFF00000);556OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);557OS_DELAY(100);558}559/* Clear the RTC force wake bit to allow the mac to go to sleep */560OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);561562if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {563/*564* In Jupiter, after enter sleep mode, hardware will send565* a SYS_SLEEPING message through MCI interface. Add a566* few us delay to make sure the message can reach BT side.567*/568OS_DELAY(100);569}570571if (!AR_SREV_JUPITER_10(ah)) {572/* Shutdown chip. Active low */573OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);574/* Settle time */575OS_DELAY(2);576}577}578579#if ATH_WOW_OFFLOAD580if (!AR_SREV_JUPITER(ah) || !HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_SET_4004_BIT14))581#endif /* ATH_WOW_OFFLOAD */582{583/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */584OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA),585ahp->ah_wa_reg_val & ~AR_WA_D3_TO_L1_DISABLE);586}587}588589/*590* Notify Power Management is enabled in self-generating591* frames. If request, set power mode of chip to592* auto/normal. Duration in units of 128us (1/8 TU).593*/594static void595ar9300_set_power_mode_network_sleep(struct ath_hal *ah, int set_chip)596{597struct ath_hal_9300 *ahp = AH9300(ah);598599OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);600if (set_chip) {601HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;602603if (! p_cap->halAutoSleepSupport) {604/* Set wake_on_interrupt bit; clear force_wake bit */605OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);606}607else {608/*609* When chip goes into network sleep, it could be waken up by610* MCI_INT interrupt caused by BT's HW messages (LNA_xxx, CONT_xxx)611* which chould be in a very fast rate (~100us). This will cause612* chip to leave and re-enter network sleep mode frequently, which613* in consequence will have WLAN MCI HW to generate lots of614* SYS_WAKING and SYS_SLEEPING messages which will make BT CPU615* to busy to process.616*/617if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {618OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN,619OS_REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) &620~AR_MCI_INTERRUPT_RX_HW_MSG_MASK);621}622623/* Clear the RTC force wake bit to allow the mac to go to sleep */624OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);625626if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {627/*628* In Jupiter, after enter sleep mode, hardware will send629* a SYS_SLEEPING message through MCI interface. Add a630* few us delay to make sure the message can reach BT side.631*/632OS_DELAY(30);633}634}635}636637#if ATH_WOW_OFFLOAD638if (!AR_SREV_JUPITER(ah) || !HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_SET_4004_BIT14))639#endif /* ATH_WOW_OFFLOAD */640{641/* Clear Bit 14 of AR_WA after putting chip into Sleep mode. */642OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA),643ahp->ah_wa_reg_val & ~AR_WA_D3_TO_L1_DISABLE);644}645}646647/*648* Set power mgt to the requested mode, and conditionally set649* the chip as well650*/651HAL_BOOL652ar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip)653{654struct ath_hal_9300 *ahp = AH9300(ah);655#if defined(AH_DEBUG) || defined(AH_PRINT_FILTER)656static const char* modes[] = {657"AWAKE",658"FULL-SLEEP",659"NETWORK SLEEP",660"UNDEFINED"661};662#endif663int status = AH_TRUE;664665HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__,666modes[ar9300_get_power_mode(ah)], modes[mode],667set_chip ? "set chip " : "");668OS_MARK(ah, AH_MARK_CHIP_POWER, mode);669670switch (mode) {671case HAL_PM_AWAKE:672if (set_chip)673ah->ah_powerMode = mode;674status = ar9300_set_power_mode_awake(ah, set_chip);675#if ATH_SUPPORT_MCI676if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {677OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);678}679#endif680ahp->ah_chip_full_sleep = AH_FALSE;681break;682case HAL_PM_FULL_SLEEP:683#if ATH_SUPPORT_MCI684if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {685if (ar9300_get_power_mode(ah) == HAL_PM_AWAKE) {686if ((ar9300_mci_state(ah, HAL_MCI_STATE_ENABLE, NULL) != 0) &&687(ahp->ah_mci_bt_state != MCI_BT_SLEEP) &&688!ahp->ah_mci_halted_bt_gpm)689{690HALDEBUG(ah, HAL_DEBUG_BT_COEX,691"(MCI) %s: HALT BT GPM (full_sleep)\n", __func__);692ar9300_mci_send_coex_halt_bt_gpm(ah, AH_TRUE, AH_TRUE);693}694}695ahp->ah_mci_ready = AH_FALSE;696}697#endif698#if ATH_SUPPORT_MCI699if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {700OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);701}702#endif703ar9300_set_power_mode_sleep(ah, set_chip);704if (set_chip) {705ahp->ah_chip_full_sleep = AH_TRUE;706ah->ah_powerMode = mode;707}708break;709case HAL_PM_NETWORK_SLEEP:710#if ATH_SUPPORT_MCI711if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {712OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);713}714#endif715ar9300_set_power_mode_network_sleep(ah, set_chip);716if (set_chip) {717ah->ah_powerMode = mode;718}719break;720default:721HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,722"%s: unknown power mode %u\n", __func__, mode);723OS_MARK(ah, AH_MARK_CHIP_POWER_DONE, -1);724return AH_FALSE;725}726OS_MARK(ah, AH_MARK_CHIP_POWER_DONE, status);727return status;728}729730/*731* Return the current sleep mode of the chip732*/733HAL_POWER_MODE734ar9300_get_power_mode(struct ath_hal *ah)735{736int mode = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;737738switch (mode) {739case AR_RTC_STATUS_ON:740case AR_RTC_STATUS_WAKEUP:741return HAL_PM_AWAKE;742break;743case AR_RTC_STATUS_SLEEP:744return HAL_PM_NETWORK_SLEEP;745break;746case AR_RTC_STATUS_SHUTDOWN:747return HAL_PM_FULL_SLEEP;748break;749default:750HALDEBUG(ah, HAL_DEBUG_POWER_MGMT,751"%s: unknown power mode 0x%x\n", __func__, mode);752return HAL_PM_UNDEFINED;753}754}755756/*757* Set SM power save mode758*/759void760ar9300_set_sm_power_mode(struct ath_hal *ah, HAL_SMPS_MODE mode)761{762int regval;763struct ath_hal_9300 *ahp = AH9300(ah);764765if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) != HAL_OK) {766return;767}768769/* Program low & high power chainmask settings and enable MAC control */770regval = SM(AR_PCU_SMPS_LPWR_CHNMSK_VAL, AR_PCU_SMPS_LPWR_CHNMSK) |771SM(ahp->ah_rx_chainmask, AR_PCU_SMPS_HPWR_CHNMSK) |772AR_PCU_SMPS_MAC_CHAINMASK;773774/* Program registers according to required SM power mode.*/775switch (mode) {776case HAL_SMPS_SW_CTRL_LOW_PWR:777OS_REG_WRITE(ah, AR_PCU_SMPS, regval);778break;779case HAL_SMPS_SW_CTRL_HIGH_PWR:780OS_REG_WRITE(ah, AR_PCU_SMPS, regval | AR_PCU_SMPS_SW_CTRL_HPWR);781break;782case HAL_SMPS_HW_CTRL:783OS_REG_WRITE(ah, AR_PCU_SMPS, regval | AR_PCU_SMPS_HW_CTRL_EN);784break;785case HAL_SMPS_DEFAULT:786OS_REG_WRITE(ah, AR_PCU_SMPS, 0);787break;788default:789break;790}791ahp->ah_sm_power_mode = mode;792}793794#if ATH_WOW795#if NOT_NEEDED_FOR_OSPREY /* not compiled for darwin */796/*797* This routine is called to configure the SerDes register for the798* Merlin 2.0 and above chip during WOW sleep.799*/800static void801ar9280_config_ser_des__wow_sleep(struct ath_hal *ah)802{803int i;804struct ath_hal_9300 *ahp = AH9300(ah);805806/*807* For WOW sleep, we reprogram the SerDes so that the PLL and CHK REQ808* are both enabled. This uses more power but the Maverick team reported809* that otherwise, WOW sleep is unstable and chip may disappears.810*/811for (i = 0; i < ahp->ah_ini_pcie_serdes_wow.ia_rows; i++) {812OS_REG_WRITE(ah,813INI_RA(&ahp->ah_ini_pcie_serdes_wow, i, 0),814INI_RA(&ahp->ah_ini_pcie_serdes_wow, i, 1));815}816OS_DELAY(1000);817}818#endif /* if NOT_NEEDED_FOR_OSPREY */819static HAL_BOOL820ar9300_wow_create_keep_alive_pattern(struct ath_hal *ah)821{822struct ath_hal_9300 *ahp = AH9300(ah);823u_int32_t frame_len = 28;824u_int32_t tpc = 0x3f;825u_int32_t transmit_rate;826u_int32_t frame_type = 0x2; /* Frame Type -> Data; */827u_int32_t sub_type = 0x4; /* Subtype -> Null Data */828u_int32_t to_ds = 1;829u_int32_t duration_id = 0x3d;830u_int8_t *sta_mac_addr, *ap_mac_addr;831u_int8_t *addr1, *addr2, *addr3;832u_int32_t ctl[13] = { 0, };833#define NUM_KA_DATA_WORDS 6834u_int32_t data_word[NUM_KA_DATA_WORDS];835u_int32_t i;836u_int32_t wow_ka_dataword0;837838sta_mac_addr = (u_int8_t *)ahp->ah_macaddr;839ap_mac_addr = (u_int8_t *)ahp->ah_bssid;840addr2 = sta_mac_addr;841addr1 = addr3 = ap_mac_addr;842843if (AH_PRIVATE(ah)->ah_curchan->channel_flags & CHANNEL_CCK) {844transmit_rate = 0x1B; /* CCK_1M */845} else {846transmit_rate = 0xB; /* OFDM_6M */847}848849/* Set the Transmit Buffer. */850ctl[0] = (frame_len | (tpc << 16));851ctl[1] = 0;852ctl[2] = (0x7 << 16); /* tx_tries0 */853ctl[3] = transmit_rate;854ctl[4] = 0;855ctl[7] = ahp->ah_tx_chainmask << 2;856857for (i = 0; i < 13; i++) {858OS_REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);859}860861data_word[0] =862(frame_type << 2) |863(sub_type << 4) |864(to_ds << 8) |865(duration_id << 16);866data_word[1] = (((u_int32_t)addr1[3] << 24) | ((u_int32_t)addr1[2] << 16) |867((u_int32_t)addr1[1]) << 8 | ((u_int32_t)addr1[0]));868data_word[2] = (((u_int32_t)addr2[1] << 24) | ((u_int32_t)addr2[0] << 16) |869((u_int32_t)addr1[5]) << 8 | ((u_int32_t)addr1[4]));870data_word[3] = (((u_int32_t)addr2[5] << 24) | ((u_int32_t)addr2[4] << 16) |871((u_int32_t)addr2[3]) << 8 | ((u_int32_t)addr2[2]));872data_word[4] = (((u_int32_t)addr3[3] << 24) | ((u_int32_t)addr3[2] << 16) |873((u_int32_t)addr3[1]) << 8 | (u_int32_t)addr3[0]);874data_word[5] = (((u_int32_t)addr3[5]) << 8 | ((u_int32_t)addr3[4]));875876if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) {877/* Jupiter 2.0 has an extra descriptor word (Time based878* discard) compared to other chips */879OS_REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + 12 * 4), 0);880wow_ka_dataword0 = AR_WOW_TXBUF(13);881}882else {883wow_ka_dataword0 = AR_WOW_TXBUF(12);884}885886for (i = 0; i < NUM_KA_DATA_WORDS; i++) {887OS_REG_WRITE(ah, (wow_ka_dataword0 + i * 4), data_word[i]);888}889890return AH_TRUE;891}892893/* TBD: Should querying hal for hardware capability */894#define MAX_PATTERN_SIZE 256895#define MAX_PATTERN_MASK_SIZE 32896#define MAX_NUM_USER_PATTERN 6 /* Deducting the disassoc/deauth packets */897898void899ar9300_wow_apply_pattern(900struct ath_hal *ah,901u_int8_t *p_ath_pattern,902u_int8_t *p_ath_mask,903int32_t pattern_count,904u_int32_t ath_pattern_len)905{906int i;907u_int32_t reg_pat[] = {908AR_WOW_TB_PATTERN0,909AR_WOW_TB_PATTERN1,910AR_WOW_TB_PATTERN2,911AR_WOW_TB_PATTERN3,912AR_WOW_TB_PATTERN4,913AR_WOW_TB_PATTERN5,914AR_WOW_TB_PATTERN6,915AR_WOW_TB_PATTERN7916};917u_int32_t reg_mask[] = {918AR_WOW_TB_MASK0,919AR_WOW_TB_MASK1,920AR_WOW_TB_MASK2,921AR_WOW_TB_MASK3,922AR_WOW_TB_MASK4,923AR_WOW_TB_MASK5,924AR_WOW_TB_MASK6,925AR_WOW_TB_MASK7926};927u_int32_t pattern_val;928u_int32_t mask_val;929u_int32_t val;930u_int8_t mask_bit = 0x1;931u_int8_t pattern;932933/* TBD: should check count by querying the hardware capability */934if (pattern_count >= MAX_NUM_USER_PATTERN) {935return;936}937938pattern = (u_int8_t)OS_REG_READ(ah, AR_WOW_PATTERN_REG);939pattern = pattern | (mask_bit << pattern_count);940OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, pattern);941942/* Set the registers for pattern */943for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {944pattern_val = (((u_int32_t)p_ath_pattern[i + 0]) |945((u_int32_t)p_ath_pattern[i + 1] << 8) |946((u_int32_t)p_ath_pattern[i + 2] << 16) |947((u_int32_t)p_ath_pattern[i + 3] << 24));948OS_REG_WRITE(ah, (reg_pat[pattern_count] + i), pattern_val);949}950951/* Set the registers for mask */952for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {953mask_val = (((u_int32_t)p_ath_mask[i + 0]) |954((u_int32_t)p_ath_mask[i + 1] << 8) |955((u_int32_t)p_ath_mask[i + 2] << 16) |956((u_int32_t)p_ath_mask[i + 3] << 24));957OS_REG_WRITE(ah, (reg_mask[pattern_count] + i), mask_val);958}959960/* XXX */961/* Set the pattern length to be matched */962if (pattern_count < 4) {963/* Pattern 0-3 uses AR_WOW_LENGTH1_REG register */964val = OS_REG_READ(ah, AR_WOW_LENGTH1_REG);965val = ((val & (~AR_WOW_LENGTH1_MASK(pattern_count))) |966((ath_pattern_len & AR_WOW_LENGTH_MAX) <<967AR_WOW_LENGTH1_SHIFT(pattern_count)));968OS_REG_WRITE(ah, AR_WOW_LENGTH1_REG, val);969} else {970/* Pattern 4-7 uses AR_WOW_LENGTH2_REG register */971val = OS_REG_READ(ah, AR_WOW_LENGTH2_REG);972val = ((val & (~AR_WOW_LENGTH2_MASK(pattern_count))) |973((ath_pattern_len & AR_WOW_LENGTH_MAX) <<974AR_WOW_LENGTH2_SHIFT(pattern_count)));975OS_REG_WRITE(ah, AR_WOW_LENGTH2_REG, val);976}977978AH_PRIVATE(ah)->ah_wow_event_mask |=979(1 << (pattern_count + AR_WOW_PATTERN_FOUND_SHIFT));980981return;982}983984HAL_BOOL985ar9300_set_power_mode_wow_sleep(struct ath_hal *ah)986{987OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);988989OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */990if (!ath_hal_waitfor(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) {991HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: dma failed to stop in 10ms\n"992"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", __func__,993OS_REG_READ(ah, AR_CR), OS_REG_READ(ah, AR_DIAG_SW));994return AH_FALSE;995} else {996#if 0997OS_REG_WRITE(ah, AR_RXDP, 0x0);998#endif9991000HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,1001"%s: TODO How to disable RXDP!!\n", __func__);10021003#if ATH_SUPPORT_MCI1004if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {1005OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);1006}1007#endif1008OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);10091010return AH_TRUE;1011}1012}101310141015HAL_BOOL1016ar9300_wow_enable(1017struct ath_hal *ah,1018u_int32_t pattern_enable,1019u_int32_t timeout_in_seconds,1020int clearbssid,1021HAL_BOOL offloadEnable)1022{1023uint32_t init_val, val, rval = 0;1024const int ka_delay = 4; /* Delay of 4 millisec between two keep_alive's */1025uint32_t wow_event_mask;1026#if ATH_WOW_OFFLOAD1027uint32_t wow_feature_enable =1028//AR_WOW_OFFLOAD_ENA_GTK |1029//AR_WOW_OFFLOAD_ENA_ARP_OFFLOAD |1030//AR_WOW_OFFLOAD_ENA_NS_OFFLOAD |1031//AR_WOW_OFFLOAD_ENA_ACER_MAGIC |1032//AR_WOW_OFFLOAD_ENA_STD_MAGIC |1033//AR_WOW_OFFLOAD_ENA_4WAY_WAKE |1034//AR_WOW_OFFLOAD_ENA_SWKA |1035//AR_WOW_OFFLOAD_ENA_BT_SLEEP |1036AR_WOW_OFFLOAD_ENA_SW_NULL;1037#endif10381039/*1040* ah_wow_event_mask is a mask to the AR_WOW_PATTERN_REG register to1041* indicate which WOW events that we have enabled. The WOW Events are1042* from the pattern_enable in this function and pattern_count of1043* ar9300_wow_apply_pattern()1044*/1045wow_event_mask = AH_PRIVATE(ah)->ah_wow_event_mask;10461047HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,1048"%s: offload: %d, pattern: %08x, event_mask: %08x\n",1049__func__, offloadEnable, pattern_enable, wow_event_mask);10501051/*1052* Untie Power-On-Reset from the PCI-E Reset. When we are in WOW sleep,1053* we do not want the Reset from the PCI-E to disturb our hw state.1054*/1055if (AH_PRIVATE(ah)->ah_is_pci_express == AH_TRUE) {10561057u_int32_t wa_reg_val;1058/*1059* We need to untie the internal POR (power-on-reset) to the external1060* PCI-E reset. We also need to tie the PCI-E Phy reset to the PCI-E1061* reset.1062*/1063HAL_DEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,1064"%s: Untie POR and PCIE reset\n", __func__);1065wa_reg_val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_WA));1066wa_reg_val = wa_reg_val & ~(AR_WA_UNTIE_RESET_EN);1067wa_reg_val = wa_reg_val | AR_WA_RESET_EN | AR_WA_POR_SHORT;1068/*1069* This bit is to bypass the EEPROM/OTP state machine, (by clearing its1070* busy state while PCIE_rst is asserted), to allow BT embedded CPU1071* be able to access WLAN registers. Otherwise the eCPU access will be1072* stalled as eeprom_sm is held in busy state.1073*1074* EV91928 is that when this bit is set, after host wakeup and PCIE_rst1075* deasserted, PCIE configuration registers will be reset and DeviceID1076* SubsystemID etc. registers will be different from values before1077* entering sleep. This will cause Windows to detect a device removal.1078*1079* For HW WOW, this bit should keep as cleared.1080*/1081if (offloadEnable) {1082HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,1083"%s: Set AR_WA.13 COLD_RESET_OVERRIDE\n", __func__);1084wa_reg_val = wa_reg_val | AR_WA_COLD_RESET_OVERRIDE;10851086#if ATH_WOW_OFFLOAD1087if (AR_SREV_JUPITER(ah)) {1088wa_reg_val = wa_reg_val | AR_WA_D3_TO_L1_DISABLE;1089}1090#endif1091}1092OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), wa_reg_val);1093}10941095/*1096* Set the power states appropriately and enable pme.1097*/1098val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL));1099val |=1100AR_PMCTRL_HOST_PME_EN |1101AR_PMCTRL_PWR_PM_CTRL_ENA |1102AR_PMCTRL_AUX_PWR_DET;11031104/*1105* Set and clear WOW_PME_CLEAR registers for the chip to generate next1106* wow signal.1107*/1108val |= AR_PMCTRL_WOW_PME_CLR;1109OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), val);1110val &= ~AR_PMCTRL_WOW_PME_CLR;1111OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), val);11121113/*1114* Setup for for:1115* - beacon misses1116* - magic pattern1117* - keep alive timeout1118* - pattern matching1119*/11201121/*1122* Program some default values for keep-alives, beacon misses, etc.1123*/1124init_val = OS_REG_READ(ah, AR_WOW_PATTERN_REG);1125val = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF) | init_val;1126OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, val);1127rval = OS_REG_READ(ah, AR_WOW_PATTERN_REG);11281129val =1130AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |1131AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |1132AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);1133OS_REG_WRITE(ah, AR_WOW_COUNT_REG, val);1134rval = OS_REG_READ(ah, AR_WOW_COUNT_REG);11351136if (pattern_enable & AH_WOW_BEACON_MISS) {1137val = AR_WOW_BEACON_TIMO;1138} else {1139/* We are not using the beacon miss. Program a large value. */1140val = AR_WOW_BEACON_TIMO_MAX;1141}1142OS_REG_WRITE(ah, AR_WOW_BCN_TIMO_REG, val);1143rval = OS_REG_READ(ah, AR_WOW_BCN_TIMO_REG);11441145/*1146* Keep Alive Timo in ms.1147*/1148if (pattern_enable == 0) {1149val = AR_WOW_KEEP_ALIVE_NEVER;1150} else {1151val = AH_PRIVATE(ah)->ah_config.ath_hal_keep_alive_timeout * 32;1152}1153OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO_REG, val);1154rval = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_TIMO_REG);11551156/*1157* Keep Alive delay in us.1158*/1159val = ka_delay * 1000;1160OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY_REG, val);1161rval = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_DELAY_REG);11621163/*1164* Create keep_alive Pattern to respond to beacons.1165*/1166ar9300_wow_create_keep_alive_pattern(ah);11671168/*1169* Configure Mac Wow Registers.1170*/11711172val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_REG);11731174/*1175* Send keep alive timeouts anyway.1176*/1177val &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS;11781179if (pattern_enable & AH_WOW_LINK_CHANGE) {1180val &= ~ AR_WOW_KEEP_ALIVE_FAIL_DIS;1181wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;1182} else {1183val |= AR_WOW_KEEP_ALIVE_FAIL_DIS;1184}1185#if ATH_WOW_OFFLOAD1186if (offloadEnable) {1187/* Don't enable KA frames yet. BT CPU is not1188* yet ready. */1189}1190else1191#endif /* ATH_WOW_OFFLOAD */1192{1193OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_REG, val);1194val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_REG);1195}119611971198/*1199* We are relying on a bmiss failure. Ensure we have enough1200* threshold to prevent AH_FALSE positives.1201*/1202OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,1203AR_WOW_BMISSTHRESHOLD);12041205val = OS_REG_READ(ah, AR_WOW_BCN_EN_REG);1206if (pattern_enable & AH_WOW_BEACON_MISS) {1207val |= AR_WOW_BEACON_FAIL_EN;1208wow_event_mask |= AR_WOW_BEACON_FAIL;1209} else {1210val &= ~AR_WOW_BEACON_FAIL_EN;1211}1212OS_REG_WRITE(ah, AR_WOW_BCN_EN_REG, val);1213val = OS_REG_READ(ah, AR_WOW_BCN_EN_REG);12141215/*1216* Enable the magic packet registers.1217*/1218val = OS_REG_READ(ah, AR_WOW_PATTERN_REG);1219if ((pattern_enable & AH_WOW_MAGIC_PATTERN_EN)1220#if ATH_WOW_OFFLOAD1221|| (pattern_enable & AH_WOW_ACER_MAGIC_EN)1222#endif1223)1224{1225val |= AR_WOW_MAGIC_EN;1226wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;1227} else {1228val &= ~AR_WOW_MAGIC_EN;1229}1230val |= AR_WOW_MAC_INTR_EN;1231OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, val);1232val = OS_REG_READ(ah, AR_WOW_PATTERN_REG);12331234#if ATH_WOW_OFFLOAD1235if (HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_FORCE_BT_SLEEP)) {1236wow_feature_enable |= AR_WOW_OFFLOAD_ENA_BT_SLEEP;1237HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - BT SLEEP\n");1238} else {1239wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_BT_SLEEP;1240HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - BT SLEEP\n");1241}12421243if (HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_SW_NULL_DISABLE)) {1244HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - SW NULL\n");1245wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_SW_NULL;1246} else {1247HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - SW NULL\n");1248wow_feature_enable |= AR_WOW_OFFLOAD_ENA_SW_NULL;1249}12501251if (HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_DEVID_SWAR_DISABLE)) {1252HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - DevID SWAR\n");1253wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_DEVID_SWAR;1254} else {1255HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - DevID SWAR\n");1256wow_feature_enable |= AR_WOW_OFFLOAD_ENA_DEVID_SWAR;1257}12581259if (pattern_enable & AH_WOW_ACER_KEEP_ALIVE_EN) {1260HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Acer SWKA\n");1261wow_feature_enable |= AR_WOW_OFFLOAD_ENA_SWKA;1262} else {1263HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Acer SWKA\n");1264wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_SWKA;1265}12661267if (pattern_enable & AH_WOW_ACER_MAGIC_EN) {1268HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Standard Magic\n");1269wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_STD_MAGIC;1270HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Acer Magic\n");1271wow_feature_enable |= AR_WOW_OFFLOAD_ENA_ACER_MAGIC;1272} else {1273HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Standard Magic\n");1274wow_feature_enable |= AR_WOW_OFFLOAD_ENA_STD_MAGIC;1275HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Acer Magic\n");1276wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_ACER_MAGIC;1277}12781279if ((pattern_enable & AH_WOW_4WAY_HANDSHAKE_EN) ||1280HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_FORCE_4WAY_HS_WAKE)) {1281HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - 4Way Handshake\n");1282wow_feature_enable |= AR_WOW_OFFLOAD_ENA_4WAY_WAKE;1283} else {1284HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - 4Way Handshake\n");1285wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_4WAY_WAKE;1286}12871288if((pattern_enable & AH_WOW_AP_ASSOCIATION_LOST_EN) ||1289HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_FORCE_AP_LOSS_WAKE))1290{1291HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - AP loss wake\n");1292wow_feature_enable |= AR_WOW_OFFLOAD_ENA_AP_LOSS_WAKE;1293} else {1294HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - AP loss wake\n");1295wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_AP_LOSS_WAKE;1296}12971298if((pattern_enable & AH_WOW_GTK_HANDSHAKE_ERROR_EN) ||1299HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_FORCE_GTK_ERR_WAKE))1300{1301HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - GTK error wake\n");1302wow_feature_enable |= AR_WOW_OFFLOAD_ENA_GTK_ERROR_WAKE;1303} else {1304HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - GTK error wake\n");1305wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_GTK_ERROR_WAKE;1306}13071308if (pattern_enable & AH_WOW_GTK_OFFLOAD_EN) {1309HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - GTK offload\n");1310wow_feature_enable |= AR_WOW_OFFLOAD_ENA_GTK;1311} else {1312HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - GTK offload\n");1313wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_GTK;1314}13151316if (pattern_enable & AH_WOW_ARP_OFFLOAD_EN) {1317HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - ARP offload\n");1318wow_feature_enable |= AR_WOW_OFFLOAD_ENA_ARP_OFFLOAD;1319} else {1320HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - ARP offload\n");1321wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_ARP_OFFLOAD;1322}13231324if (pattern_enable & AH_WOW_NS_OFFLOAD_EN) {1325HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - NS offload\n");1326wow_feature_enable |= AR_WOW_OFFLOAD_ENA_NS_OFFLOAD;1327} else {1328HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - NS offload\n");1329wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_NS_OFFLOAD;1330}13311332#endif /* ATH_WOW_OFFLOAD */13331334/* For Kite and later version of the chips1335* enable wow pattern match for packets less than1336* 256 bytes for all patterns.1337*/1338/* XXX */1339OS_REG_WRITE(1340ah, AR_WOW_PATTERN_MATCH_LT_256B_REG, AR_WOW_PATTERN_SUPPORTED);13411342/*1343* Set the power states appropriately and enable PME.1344*/1345val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL));1346val |=1347AR_PMCTRL_PWR_STATE_D1D3 |1348AR_PMCTRL_HOST_PME_EN |1349AR_PMCTRL_PWR_PM_CTRL_ENA;1350val &= ~AR_PCIE_PM_CTRL_ENA;1351OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), val);13521353/* Wake on Timer Interrupt. Test mode only. Used in Manufacturing line. */1354if (timeout_in_seconds) {1355/* convert Timeout to u_secs */1356OS_REG_WRITE(ah, AR_NEXT_NDP_TIMER,1357OS_REG_READ(ah, AR_TSF_L32) + timeout_in_seconds * 1000000 );1358/* timer_period = 30 seconds always */1359OS_REG_WRITE(ah, AR_NDP_PERIOD, 30 * 1000000);1360OS_REG_WRITE(ah, AR_TIMER_MODE, OS_REG_READ(ah, AR_TIMER_MODE) | 0x80);1361OS_REG_WRITE(ah, AR_IMR_S5, OS_REG_READ(ah, AR_IMR_S5) | 0x80);1362OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_GENTMR);1363if (clearbssid) {1364OS_REG_WRITE(ah, AR_BSS_ID0, 0);1365OS_REG_WRITE(ah, AR_BSS_ID1, 0);1366}1367}13681369/* Enable Seq# generation when asleep. */1370OS_REG_WRITE(ah, AR_STA_ID1,1371OS_REG_READ(ah, AR_STA_ID1) & ~AR_STA_ID1_PRESERVE_SEQNUM);13721373AH_PRIVATE(ah)->ah_wow_event_mask = wow_event_mask;13741375#if ATH_WOW_OFFLOAD1376if (offloadEnable) {1377/* Force MAC awake before entering SW WoW mode */1378OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);1379#if ATH_SUPPORT_MCI1380if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {1381OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);1382}1383#endif13841385OS_REG_WRITE(ah, AR_WOW_OFFLOAD_COMMAND_JUPITER, wow_feature_enable);1386OS_REG_WRITE(ah, AR_WOW_OFFLOAD_STATUS_JUPITER, 0x0);1387if (wow_feature_enable & AR_WOW_OFFLOAD_ENA_SW_NULL) {1388OS_REG_WRITE(ah, AR_WOW_SW_NULL_PARAMETER,1389((1000) |1390(4 << AR_WOW_SW_NULL_SHORT_PERIOD_MASK_S)));1391}13921393if (wow_feature_enable & AR_WOW_OFFLOAD_ENA_DEVID_SWAR) {1394ar9300_wowoffload_download_devid_swar(ah);1395}13961397ar9300_wow_offload_download_hal_params(ah);1398ar9300_wow_offload_handshake(ah, pattern_enable);1399AH9300(ah)->ah_chip_full_sleep = AH_FALSE;14001401//OS_REG_SET_BIT(ah, AR_SW_WOW_CONTROL, AR_HW_WOW_DISABLE);1402}1403else1404#endif /* ATH_WOW_OFFLOAD */1405{1406#if ATH_SUPPORT_MCI1407if (AH_PRIVATE(ah)->ah_caps.halMciSupport) {1408OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);1409}1410#endif1411ar9300_set_power_mode_wow_sleep(ah);1412AH9300(ah)->ah_chip_full_sleep = AH_TRUE;1413}14141415return (AH_TRUE);1416}14171418u_int32_t1419//ar9300_wow_wake_up(struct ath_hal *ah, u_int8_t *chipPatternBytes)1420ar9300_wow_wake_up(struct ath_hal *ah, HAL_BOOL offloadEnabled)1421{1422uint32_t wow_status = 0;1423uint32_t val = 0, rval;14241425OS_REG_CLR_BIT(ah, AR_SW_WOW_CONTROL, AR_HW_WOW_DISABLE);1426OS_REG_CLR_BIT(ah, AR_SW_WOW_CONTROL, AR_SW_WOW_ENABLE);14271428#if ATH_WOW_OFFLOAD1429/* If WoW was offloaded to embedded CPU, use the global1430* shared register to know the wakeup reason */1431if (offloadEnabled) {1432val = OS_REG_READ(ah, AR_EMB_CPU_WOW_STATUS);1433if (val) {1434if (val & AR_EMB_CPU_WOW_STATUS_MAGIC_PATTERN) {1435HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) SW MAGIC_PATTERN\n");1436wow_status |= AH_WOW_MAGIC_PATTERN_EN;1437}1438if (val & AR_EMB_CPU_WOW_STATUS_PATTERN_MATCH) {1439HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) SW USER_PATTERN\n");1440wow_status |= AH_WOW_USER_PATTERN_EN;1441}1442if (val & AR_EMB_CPU_WOW_STATUS_KEEP_ALIVE_FAIL) {1443HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) SW KEEP_ALIVE_FAIL\n");1444wow_status |= AH_WOW_LINK_CHANGE;1445}1446if (val & AR_EMB_CPU_WOW_STATUS_BEACON_MISS) {1447HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) SW BEACON_FAIL\n");1448wow_status |= AH_WOW_BEACON_MISS;1449}1450}14511452/* Clear status and mask registers */1453OS_REG_WRITE(ah, AR_EMB_CPU_WOW_STATUS, 0x0);1454OS_REG_WRITE(ah, AR_EMB_CPU_WOW_ENABLE, 0);1455OS_REG_WRITE(ah, AR_MBOX_CTRL_STATUS, 0);14561457}1458else1459#endif /* ATH_WOW_OFFLOAD */1460{1461/*1462* Read the WOW Status register to know the wakeup reason.1463*/1464rval = OS_REG_READ(ah, AR_WOW_PATTERN_REG);1465val = AR_WOW_STATUS(rval);14661467/*1468* Mask only the WOW events that we have enabled.1469* Sometimes we have spurious WOW events from the AR_WOW_PATTERN_REG1470* register. This mask will clean it up.1471*/1472val &= AH_PRIVATE(ah)->ah_wow_event_mask;14731474if (val) {1475if (val & AR_WOW_MAGIC_PAT_FOUND) {1476HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) HW MAGIC_PATTERN\n");1477wow_status |= AH_WOW_MAGIC_PATTERN_EN;1478}1479if (AR_WOW_PATTERN_FOUND(val)) {1480//int i, offset;1481//offset = OS_REG_READ(ah, AR_WOW_RXBUF_START_ADDR);1482//// Read matched pattern for wake packet detection indication.1483//for( i = 0; i< MAX_PATTERN_SIZE/4; i+=4)1484//{1485// // RX FIFO is only 8K wrapping.1486// if(offset >= 8 * 1024 / 4) offset = 0;1487// *(u_int32_t*)(chipPatternBytes + i) = OS_REG_READ( ah,offset );1488// offset++;1489//}1490wow_status |= AH_WOW_USER_PATTERN_EN;1491HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) HW USER_PATTERN\n");1492}1493if (val & AR_WOW_KEEP_ALIVE_FAIL) {1494HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) HW KEEP_ALIVE_FAIL\n");1495wow_status |= AH_WOW_LINK_CHANGE;1496}1497if (val & AR_WOW_BEACON_FAIL) {1498HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) HW BEACON_FAIL\n");1499wow_status |= AH_WOW_BEACON_MISS;1500}1501}1502}15031504/*1505* Set and clear WOW_PME_CLEAR registers for the chip to generate next1506* wow signal.1507* Disable D3 before accessing other registers ?1508*/1509val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL));1510/* Check the bit value 0x01000000 (7-10)? */1511val &= ~AR_PMCTRL_PWR_STATE_D1D3;1512val |= AR_PMCTRL_WOW_PME_CLR;1513OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), val);15141515/*1516* Clear all events.1517*/1518OS_REG_WRITE(ah, AR_WOW_PATTERN_REG,1519AR_WOW_CLEAR_EVENTS(OS_REG_READ(ah, AR_WOW_PATTERN_REG)));15201521//HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,1522// "%s: Skip PCIE WA programming\n", __func__);1523#if 01524/*1525* Tie reset register.1526* FIXME: Per David Quan not tieing it back might have some repurcussions.1527*/1528/* XXX */1529OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), OS_REG_READ(ah, AR_WA) |1530AR_WA_UNTIE_RESET_EN | AR_WA_POR_SHORT | AR_WA_RESET_EN);1531#endif15321533/* Restore the Beacon Threshold to init value */1534OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR);15351536/*1537* Restore the way the PCI-E Reset, Power-On-Reset, external PCIE_POR_SHORT1538* pins are tied to its original value. Previously just before WOW sleep,1539* we untie the PCI-E Reset to our Chip's Power On Reset so that1540* any PCI-E reset from the bus will not reset our chip.1541*/1542HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "%s: restore AR_WA\n", __func__);1543if (AH_PRIVATE(ah)->ah_is_pci_express == AH_TRUE) {1544ar9300_config_pci_power_save(ah, 0, 0);1545}15461547AH_PRIVATE(ah)->ah_wow_event_mask = 0;1548HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,1549"(WOW) wow_status=%08x\n", wow_status);15501551return (wow_status);1552}15531554void1555ar9300_wow_set_gpio_reset_low(struct ath_hal *ah)1556{1557uint32_t val;15581559val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT));1560val |= (1 << (2 * 2));1561OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT), val);1562val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT));1563/* val = OS_REG_READ(ah,AR_GPIO_IN_OUT ); */1564}1565#endif /* ATH_WOW */156615671568