ar9300_power.c revision 250003
1250003Sadrian/* 2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc. 3250003Sadrian * 4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any 5250003Sadrian * purpose with or without fee is hereby granted, provided that the above 6250003Sadrian * copyright notice and this permission notice appear in all copies. 7250003Sadrian * 8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14250003Sadrian * PERFORMANCE OF THIS SOFTWARE. 15250003Sadrian */ 16250003Sadrian 17250003Sadrian#include "opt_ah.h" 18250003Sadrian 19250003Sadrian#ifdef AH_SUPPORT_AR9300 20250003Sadrian 21250003Sadrian#include "ah.h" 22250003Sadrian#include "ah_internal.h" 23250003Sadrian 24250003Sadrian#include "ar9300/ar9300.h" 25250003Sadrian#include "ar9300/ar9300reg.h" 26250003Sadrian 27250003Sadrian#if ATH_WOW_OFFLOAD 28250003Sadrianvoid ar9300_wowoffload_prep(struct ath_hal *ah) 29250003Sadrian{ 30250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 31250003Sadrian 32250003Sadrian ahp->ah_mcast_filter_l32_set = 0; 33250003Sadrian ahp->ah_mcast_filter_u32_set = 0; 34250003Sadrian} 35250003Sadrian 36250003Sadrianvoid ar9300_wowoffload_post(struct ath_hal *ah) 37250003Sadrian{ 38250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 39250003Sadrian u_int32_t val; 40250003Sadrian 41250003Sadrian if (ahp->ah_mcast_filter_l32_set != 0) { 42250003Sadrian val = OS_REG_READ(ah, AR_MCAST_FIL0); 43250003Sadrian val &= ~ahp->ah_mcast_filter_l32_set; 44250003Sadrian OS_REG_WRITE(ah, AR_MCAST_FIL0, val); 45250003Sadrian } 46250003Sadrian if (ahp->ah_mcast_filter_u32_set != 0) { 47250003Sadrian val = OS_REG_READ(ah, AR_MCAST_FIL1); 48250003Sadrian val &= ~ahp->ah_mcast_filter_u32_set; 49250003Sadrian OS_REG_WRITE(ah, AR_MCAST_FIL1, val); 50250003Sadrian } 51250003Sadrian 52250003Sadrian ahp->ah_mcast_filter_l32_set = 0; 53250003Sadrian ahp->ah_mcast_filter_u32_set = 0; 54250003Sadrian} 55250003Sadrian 56250003Sadrianstatic void ar9300_wowoffload_add_mcast_filter(struct ath_hal *ah, u_int8_t *mc_addr) 57250003Sadrian{ 58250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 59250003Sadrian u_int32_t reg, val; 60250003Sadrian u_int8_t pos, high32; 61250003Sadrian 62250003Sadrian memcpy((u_int8_t *) &val, &mc_addr[0], 3); 63250003Sadrian pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; 64250003Sadrian memcpy((u_int8_t *) &val, &mc_addr[3], 3); 65250003Sadrian pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; 66250003Sadrian high32 = pos & 0x20; 67250003Sadrian reg = high32 ? AR_MCAST_FIL1 : AR_MCAST_FIL0; 68250003Sadrian pos &= 0x1F; 69250003Sadrian 70250003Sadrian val = OS_REG_READ(ah, reg); 71250003Sadrian if ((val & (1 << pos)) == 0) { 72250003Sadrian val |= (1 << pos); 73250003Sadrian if (high32) { 74250003Sadrian ahp->ah_mcast_filter_u32_set |= (1 << pos); 75250003Sadrian } else { 76250003Sadrian ahp->ah_mcast_filter_l32_set |= (1 << pos); 77250003Sadrian } 78250003Sadrian OS_REG_WRITE(ah, reg, val); 79250003Sadrian } 80250003Sadrian} 81250003Sadrian 82250003Sadrian/* 83250003Sadrian * DeviceID SWAR - EV91928 84250003Sadrian * 85250003Sadrian * During SW WOW, 0x4004[13] is set to allow BT eCPU to access WLAN MAC 86250003Sadrian * registers. Setting 00x4004[13] will prevent eeprom state machine to 87250003Sadrian * load customizable PCIE configuration registers, which lead to the PCIE 88250003Sadrian * device id stay as default 0xABCD. The SWAR to have BT eCPU to write 89250003Sadrian * to PCIE registers as soon as it detects PCIE reset is deasserted. 90250003Sadrian */ 91250003Sadrianvoid ar9300_wowoffload_download_devid_swar(struct ath_hal *ah) 92250003Sadrian{ 93250003Sadrian u_int32_t addr = AR_WOW_OFFLOAD_WLAN_REGSET_NUM; 94250003Sadrian 95250003Sadrian OS_REG_WRITE(ah, addr, 8); 96250003Sadrian addr += 4; 97250003Sadrian OS_REG_WRITE(ah, addr, 0x5000); 98250003Sadrian addr += 4; 99250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_000 = %08x\n", 100250003Sadrian AH_PRIVATE(ah)->ah_config.ath_hal_pcie_000); 101250003Sadrian OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_000); 102250003Sadrian addr += 4; 103250003Sadrian OS_REG_WRITE(ah, addr, 0x5008); 104250003Sadrian addr += 4; 105250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_008 = %08x\n", 106250003Sadrian AH_PRIVATE(ah)->ah_config.ath_hal_pcie_008); 107250003Sadrian OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_008); 108250003Sadrian addr += 4; 109250003Sadrian OS_REG_WRITE(ah, addr, 0x502c); 110250003Sadrian addr += 4; 111250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_02c = %08x\n", 112250003Sadrian AH_PRIVATE(ah)->ah_config.ath_hal_pcie_02c); 113250003Sadrian OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_02c); 114250003Sadrian addr += 4; 115250003Sadrian OS_REG_WRITE(ah, addr, 0x18c00); 116250003Sadrian addr += 4; 117250003Sadrian OS_REG_WRITE(ah, addr, 0x18212ede); 118250003Sadrian addr += 4; 119250003Sadrian OS_REG_WRITE(ah, addr, 0x18c04); 120250003Sadrian addr += 4; 121250003Sadrian OS_REG_WRITE(ah, addr, 0x008001d8); 122250003Sadrian addr += 4; 123250003Sadrian OS_REG_WRITE(ah, addr, 0x18c08); 124250003Sadrian addr += 4; 125250003Sadrian OS_REG_WRITE(ah, addr, 0x0003580c); 126250003Sadrian addr += 4; 127250003Sadrian OS_REG_WRITE(ah, addr, 0x570c); 128250003Sadrian addr += 4; 129250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_70c = %08x\n", 130250003Sadrian AH_PRIVATE(ah)->ah_config.ath_hal_pcie_70c); 131250003Sadrian OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_70c); 132250003Sadrian addr += 4; 133250003Sadrian OS_REG_WRITE(ah, addr, 0x5040); 134250003Sadrian addr += 4; 135250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) pcie_040 = %08x\n", 136250003Sadrian AH_PRIVATE(ah)->ah_config.ath_hal_pcie_040); 137250003Sadrian OS_REG_WRITE(ah, addr, AH_PRIVATE(ah)->ah_config.ath_hal_pcie_040); 138250003Sadrian addr += 4; 139250003Sadrian/* 140250003Sadrian A_SOC_REG_WRITE(0x45000, 0x0034168c); 141250003Sadrian A_SOC_REG_WRITE(0x45008, 0x02800001); 142250003Sadrian A_SOC_REG_WRITE(0x4502c, 0x3117168c); 143250003Sadrian A_SOC_REG_WRITE(0x58c00, 0x18212ede); 144250003Sadrian A_SOC_REG_WRITE(0x58c04, 0x000801d8); 145250003Sadrian A_SOC_REG_WRITE(0x58c08, 0x0003580c); 146250003Sadrian A_SOC_REG_WRITE(0x4570c, 0x275f3f01); 147250003Sadrian A_SOC_REG_WRITE(0x45040, 0xffc25001); 148250003Sadrian*/ 149250003Sadrian} 150250003Sadrian 151250003Sadrian/* Retrieve updated information from MAC PCU buffer. 152250003Sadrian * Embedded CPU would have written the value before exiting WoW 153250003Sadrian * */ 154250003Sadrianvoid ar9300_wowoffload_retrieve_data(struct ath_hal *ah, void *buf, u_int32_t param) 155250003Sadrian{ 156250003Sadrian u_int32_t rc_lower, rc_upper; 157250003Sadrian 158250003Sadrian if (param == WOW_PARAM_REPLAY_CNTR) { 159250003Sadrian rc_lower = OS_REG_READ(ah, AR_WOW_TXBUF(0)); 160250003Sadrian rc_upper = OS_REG_READ(ah, AR_WOW_TXBUF(1)); 161250003Sadrian *(u_int64_t *)buf = rc_lower + (rc_upper << 32); 162250003Sadrian } 163250003Sadrian else if (param == WOW_PARAM_KEY_TSC) { 164250003Sadrian rc_lower = OS_REG_READ(ah, AR_WOW_TXBUF(2)); 165250003Sadrian rc_upper = OS_REG_READ(ah, AR_WOW_TXBUF(3)); 166250003Sadrian *(u_int64_t *)buf = rc_lower + (rc_upper << 32); 167250003Sadrian } 168250003Sadrian else if (param == WOW_PARAM_TX_SEQNUM) { 169250003Sadrian *(u_int32_t *)buf = OS_REG_READ(ah, AR_WOW_TXBUF(4)); 170250003Sadrian } 171250003Sadrian 172250003Sadrian} 173250003Sadrian 174250003Sadrian/* Download GTK rekey related information to the embedded CPU */ 175250003Sadrianu_int32_t ar9300_wowoffload_download_rekey_data(struct ath_hal *ah, u_int32_t *data, u_int32_t bytes) 176250003Sadrian{ 177250003Sadrian int i; 178250003Sadrian int mbox_status = OS_REG_READ(ah, AR_MBOX_CTRL_STATUS); 179250003Sadrian u_int32_t gtk_data_start; 180250003Sadrian 181250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) %s, bytes=%d\n", __func__, bytes); 182250003Sadrian if (AR_SREV_JUPITER(ah) && 183250003Sadrian (bytes > (AR_WOW_OFFLOAD_GTK_DATA_WORDS_JUPITER * 4))) 184250003Sadrian { 185250003Sadrian bytes = AR_WOW_OFFLOAD_GTK_DATA_WORDS_JUPITER * 4; 186250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) bytes truncated to %d\n", bytes); 187250003Sadrian } 188250003Sadrian /* Check if mailbox is busy */ 189250003Sadrian if (mbox_status != 0) { 190250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: Mailbox register busy! Reg = 0x%x", __func__, mbox_status); 191250003Sadrian return 1; 192250003Sadrian } 193250003Sadrian 194250003Sadrian /* Clear status */ 195250003Sadrian OS_REG_WRITE(ah, AR_EMB_CPU_WOW_STATUS, 0x0); 196250003Sadrian OS_REG_WRITE(ah, AR_WLAN_WOW_ENABLE, 0); 197250003Sadrian OS_REG_WRITE(ah, AR_WLAN_WOW_STATUS, 0xFFFFFFFF); 198250003Sadrian 199250003Sadrian if (AR_SREV_JUPITER(ah)) { 200250003Sadrian gtk_data_start = AR_WOW_OFFLOAD_GTK_DATA_START_JUPITER; 201250003Sadrian } else { 202250003Sadrian gtk_data_start = AR_WOW_OFFLOAD_GTK_DATA_START; 203250003Sadrian } 204250003Sadrian for (i = 0;i < bytes/4; i++) { 205250003Sadrian OS_REG_WRITE(ah, gtk_data_start + i * 4, data[i]); 206250003Sadrian } 207250003Sadrian 208250003Sadrian return 0; 209250003Sadrian} 210250003Sadrian 211250003Sadrianvoid ar9300_wowoffload_download_acer_magic( struct ath_hal *ah, 212250003Sadrian HAL_BOOL valid, 213250003Sadrian u_int8_t* datap, 214250003Sadrian u_int32_t bytes) 215250003Sadrian{ 216250003Sadrian u_int32_t *p32 = (u_int32_t *) datap; 217250003Sadrian u_int32_t l = 0, u = 0; 218250003Sadrian 219250003Sadrian if (valid) { 220250003Sadrian l = *p32; 221250003Sadrian p32++; 222250003Sadrian u = *(u_int16_t *) p32; 223250003Sadrian } 224250003Sadrian 225250003Sadrian OS_REG_WRITE(ah, AR_WOW_OFFLOAD_ACER_MAGIC_START, l); 226250003Sadrian OS_REG_WRITE(ah, AR_WOW_OFFLOAD_ACER_MAGIC_START + 4, u); 227250003Sadrian 228250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, 229250003Sadrian "%s: Aer Magic: %02x-%02x-%02x-%02x-%02x-%02x\n", __func__, 230250003Sadrian datap[0], datap[1], datap[2], datap[3], datap[4], datap[5]); 231250003Sadrian} 232250003Sadrian 233250003Sadrianvoid ar9300_wowoffload_download_acer_swka( struct ath_hal *ah, 234250003Sadrian u_int32_t id, 235250003Sadrian HAL_BOOL valid, 236250003Sadrian u_int32_t period, 237250003Sadrian u_int32_t size, 238250003Sadrian u_int32_t* datap) 239250003Sadrian{ 240250003Sadrian u_int32_t ka_period[2] = { 241250003Sadrian AR_WOW_OFFLOAD_ACER_KA0_PERIOD_MS, 242250003Sadrian AR_WOW_OFFLOAD_ACER_KA1_PERIOD_MS 243250003Sadrian }; 244250003Sadrian u_int32_t ka_size[2] = { 245250003Sadrian AR_WOW_OFFLOAD_ACER_KA0_SIZE, 246250003Sadrian AR_WOW_OFFLOAD_ACER_KA1_SIZE 247250003Sadrian }; 248250003Sadrian u_int32_t ka_data[2] = { 249250003Sadrian AR_WOW_OFFLOAD_ACER_KA0_DATA, 250250003Sadrian AR_WOW_OFFLOAD_ACER_KA1_DATA 251250003Sadrian }; 252250003Sadrian u_int32_t n_data = AR_WOW_OFFLOAD_ACER_KA0_DATA_WORDS; 253250003Sadrian int i; 254250003Sadrian 255250003Sadrian if (id >= 2) { 256250003Sadrian return; 257250003Sadrian } 258250003Sadrian 259250003Sadrian if (valid) { 260250003Sadrian OS_REG_WRITE(ah, ka_period[id], period); 261250003Sadrian OS_REG_WRITE(ah, ka_size[id], size); 262250003Sadrian } else { 263250003Sadrian OS_REG_WRITE(ah, ka_period[id], 0); 264250003Sadrian OS_REG_WRITE(ah, ka_size[id], 0); 265250003Sadrian } 266250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: id=%d, period=%d ms, size=%d bytes\n", 267250003Sadrian __func__, id, period, size); 268250003Sadrian 269250003Sadrian if (size < (n_data * 4)) { 270250003Sadrian n_data = (size + 3) / 4; 271250003Sadrian } 272250003Sadrian for (i=0; i<n_data * 4; i+=4) { 273250003Sadrian OS_REG_WRITE(ah, ka_data[id] + i, *datap); 274250003Sadrian /*HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) %08x\n", *datap);*/ 275250003Sadrian datap++; 276250003Sadrian } 277250003Sadrian} 278250003Sadrian 279250003Sadrianvoid ar9300_wowoffload_download_arp_info(struct ath_hal *ah, u_int32_t id, u_int32_t *data) 280250003Sadrian{ 281250003Sadrian u_int32_t addr; 282250003Sadrian struct hal_wow_offload_arp_info *p_info = (struct hal_wow_offload_arp_info *) data; 283250003Sadrian 284250003Sadrian if (id == 0) { 285250003Sadrian addr = AR_WOW_OFFLOAD_ARP0_VALID; 286250003Sadrian } else if (id == 1) { 287250003Sadrian addr = AR_WOW_OFFLOAD_ARP1_VALID; 288250003Sadrian } else { 289250003Sadrian return; 290250003Sadrian } 291250003Sadrian 292250003Sadrian if (p_info->valid) { 293250003Sadrian OS_REG_WRITE(ah, addr, 0x1); 294250003Sadrian addr += 4; 295250003Sadrian OS_REG_WRITE(ah, addr, p_info->RemoteIPv4Address.u32); 296250003Sadrian addr += 4; 297250003Sadrian OS_REG_WRITE(ah, addr, p_info->HostIPv4Address.u32); 298250003Sadrian addr += 4; 299250003Sadrian OS_REG_WRITE(ah, addr, p_info->MacAddress.u32[0]); 300250003Sadrian addr += 4; 301250003Sadrian OS_REG_WRITE(ah, addr, p_info->MacAddress.u32[1]); 302250003Sadrian } else { 303250003Sadrian OS_REG_WRITE(ah, addr, 0x0); 304250003Sadrian } 305250003Sadrian} 306250003Sadrian 307250003Sadrian#define WOW_WRITE_NS_IPV6_ADDRESS(_ah, _buf_addr, _p_ipv6_addr) \ 308250003Sadrian { \ 309250003Sadrian u_int32_t offset = (_buf_addr); \ 310250003Sadrian u_int32_t *p_ipv6_addr = (u_int32_t *) (_p_ipv6_addr); \ 311250003Sadrian int i; \ 312250003Sadrian for (i = 0; i < 4; i++) { \ 313250003Sadrian OS_REG_WRITE((_ah), offset, *p_ipv6_addr); \ 314250003Sadrian offset += 4; \ 315250003Sadrian p_ipv6_addr ++; \ 316250003Sadrian } \ 317250003Sadrian } 318250003Sadrian 319250003Sadrianvoid ar9300_wowoffload_download_ns_info(struct ath_hal *ah, u_int32_t id, u_int32_t *data) 320250003Sadrian{ 321250003Sadrian u_int32_t addr; 322250003Sadrian struct hal_wow_offload_ns_info *p_info = (struct hal_wow_offload_ns_info *) data; 323250003Sadrian u_int8_t mc_addr[6]; 324250003Sadrian 325250003Sadrian if (id == 0) { 326250003Sadrian addr = AR_WOW_OFFLOAD_NS0_VALID; 327250003Sadrian } else if (id == 1) { 328250003Sadrian addr = AR_WOW_OFFLOAD_NS1_VALID; 329250003Sadrian } else { 330250003Sadrian return; 331250003Sadrian } 332250003Sadrian 333250003Sadrian if (p_info->valid) { 334250003Sadrian OS_REG_WRITE(ah, addr, 0x1); 335250003Sadrian addr += 4; 336250003Sadrian WOW_WRITE_NS_IPV6_ADDRESS(ah, addr, &p_info->RemoteIPv6Address.u32[0]); 337250003Sadrian addr += 4 * 4; 338250003Sadrian WOW_WRITE_NS_IPV6_ADDRESS(ah, addr, &p_info->SolicitedNodeIPv6Address.u32[0]); 339250003Sadrian addr += 4 * 4; 340250003Sadrian OS_REG_WRITE(ah, addr, p_info->MacAddress.u32[0]); 341250003Sadrian addr += 4; 342250003Sadrian OS_REG_WRITE(ah, addr, p_info->MacAddress.u32[1]); 343250003Sadrian addr += 4; 344250003Sadrian WOW_WRITE_NS_IPV6_ADDRESS(ah, addr, &p_info->TargetIPv6Addresses[0].u32[0]); 345250003Sadrian addr += 4 * 4; 346250003Sadrian WOW_WRITE_NS_IPV6_ADDRESS(ah, addr, &p_info->TargetIPv6Addresses[1].u32[0]); 347250003Sadrian 348250003Sadrian mc_addr[0] = 0x33; 349250003Sadrian mc_addr[1] = 0x33; 350250003Sadrian mc_addr[2] = 0xFF; 351250003Sadrian mc_addr[3] = p_info->SolicitedNodeIPv6Address.u8[13]; 352250003Sadrian mc_addr[4] = p_info->SolicitedNodeIPv6Address.u8[14]; 353250003Sadrian mc_addr[5] = p_info->SolicitedNodeIPv6Address.u8[15]; 354250003Sadrian ar9300_wowoffload_add_mcast_filter(ah, mc_addr); 355250003Sadrian } else { 356250003Sadrian OS_REG_WRITE(ah, addr, 0x0); 357250003Sadrian } 358250003Sadrian} 359250003Sadrian 360250003Sadrian/* Download transmit parameters for GTK response frame during WoW 361250003Sadrian * offload */ 362250003Sadrianu_int32_t ar9300_wow_offload_download_hal_params(struct ath_hal *ah) 363250003Sadrian{ 364250003Sadrian u_int32_t tpc = 0x3f; /* Transmit Power Control */ 365250003Sadrian u_int32_t tx_tries_series = 7; 366250003Sadrian u_int32_t tx_rate_series, transmit_rate; 367250003Sadrian u_int32_t gtk_txdesc_param_start; 368250003Sadrian 369250003Sadrian if (AH_PRIVATE(ah)->ah_curchan->channel_flags & CHANNEL_CCK) { 370250003Sadrian transmit_rate = 0x1B; /* CCK_1M */ 371250003Sadrian } else { 372250003Sadrian transmit_rate = 0xB; /* OFDM_6M */ 373250003Sadrian } 374250003Sadrian 375250003Sadrian /* Use single rate for now. Change later as need be */ 376250003Sadrian tx_rate_series = transmit_rate; 377250003Sadrian tx_tries_series = 7; 378250003Sadrian 379250003Sadrian if (AR_SREV_JUPITER(ah)) { 380250003Sadrian gtk_txdesc_param_start = AR_WOW_OFFLOAD_GTK_TXDESC_PARAM_START_JUPITER; 381250003Sadrian } else { 382250003Sadrian gtk_txdesc_param_start = AR_WOW_OFFLOAD_GTK_TXDESC_PARAM_START; 383250003Sadrian } 384250003Sadrian#define AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(x) (gtk_txdesc_param_start + ((x) * 4)) 385250003Sadrian 386250003Sadrian /* Do not change the data order unless firmware code on embedded 387250003Sadrian * CPU is changed correspondingly */ 388250003Sadrian OS_REG_WRITE(ah, AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(0), tx_rate_series); 389250003Sadrian OS_REG_WRITE(ah, AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(1), tx_tries_series); 390250003Sadrian OS_REG_WRITE(ah, AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(2), AH9300(ah)->ah_tx_chainmask); 391250003Sadrian OS_REG_WRITE(ah, AR_WOW_OFFLOAD_GTK_TXDESC_PARAM(3), tpc); 392250003Sadrian 393250003Sadrian return 0; 394250003Sadrian} 395250003Sadrian 396250003Sadrian/* Indicate to the embedded CPU that host is ready to enter WoW mode. 397250003Sadrian * Embedded CPU will copy relevant information from the MAC PCU buffer 398250003Sadrian */ 399250003Sadrianu_int32_t ar9300_wow_offload_handshake(struct ath_hal *ah, u_int32_t pattern_enable) 400250003Sadrian{ 401250003Sadrian int val; 402250003Sadrian int mbox_status = OS_REG_READ(ah, AR_MBOX_CTRL_STATUS); 403250003Sadrian#if ATH_WOW_OFFLOAD 404250003Sadrian u_int32_t bt_handshake_timeout_us = HAL_WOW_CTRL_WAIT_BT_TO(ah) * 100000; 405250003Sadrian 406250003Sadrian#define AH_DEFAULT_BT_WAIT_TIMEOUT 3000000; /* 3 sec */ 407250003Sadrian if (bt_handshake_timeout_us == 0) { 408250003Sadrian bt_handshake_timeout_us = AH_DEFAULT_BT_WAIT_TIMEOUT; 409250003Sadrian } 410250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) TIMEOUT: %d us\n", bt_handshake_timeout_us); 411250003Sadrian#endif /* ATH_WOW_OFFLOAD */ 412250003Sadrian 413250003Sadrian if (mbox_status & AR_MBOX_WOW_REQ) { 414250003Sadrian /* WOW mode request handshake is already in progress. 415250003Sadrian * Do nothing */ 416250003Sadrian return 0; 417250003Sadrian } 418250003Sadrian 419250003Sadrian /* Clear status */ 420250003Sadrian OS_REG_WRITE(ah, AR_MBOX_CTRL_STATUS, 0); 421250003Sadrian OS_REG_WRITE(ah, AR_EMB_CPU_WOW_STATUS, 0x0); 422250003Sadrian OS_REG_WRITE(ah, AR_WLAN_WOW_ENABLE, 0); 423250003Sadrian OS_REG_WRITE(ah, AR_WLAN_WOW_STATUS, 0xFFFFFFFF); 424250003Sadrian 425250003Sadrian OS_REG_WRITE(ah, AR_RIMT, 0); 426250003Sadrian OS_REG_WRITE(ah, AR_TIMT, 0); 427250003Sadrian 428250003Sadrian val = 0; 429250003Sadrian if (pattern_enable & AH_WOW_USER_PATTERN_EN) { 430250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - User pattern\n"); 431250003Sadrian val |= AR_EMB_CPU_WOW_ENABLE_PATTERN_MATCH; 432250003Sadrian } 433250003Sadrian else { 434250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - User pattern\n"); 435250003Sadrian } 436250003Sadrian if ((pattern_enable & AH_WOW_MAGIC_PATTERN_EN) 437250003Sadrian#if ATH_WOW_OFFLOAD 438250003Sadrian || (pattern_enable & AH_WOW_ACER_MAGIC_EN) 439250003Sadrian#endif 440250003Sadrian ) 441250003Sadrian { 442250003Sadrian val |= AR_EMB_CPU_WOW_ENABLE_MAGIC_PATTERN; 443250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Magic pattern\n"); 444250003Sadrian } 445250003Sadrian else { 446250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Magic pattern\n"); 447250003Sadrian } 448250003Sadrian if ((pattern_enable & AH_WOW_LINK_CHANGE) 449250003Sadrian#if ATH_WOW_OFFLOAD 450250003Sadrian || HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_KAFAIL_ENABLE) 451250003Sadrian#endif 452250003Sadrian ) 453250003Sadrian { 454250003Sadrian val |= AR_EMB_CPU_WOW_ENABLE_KEEP_ALIVE_FAIL; 455250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Kepp alive fail\n"); 456250003Sadrian } 457250003Sadrian else { 458250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Kepp alive fail\n"); 459250003Sadrian } 460250003Sadrian if (pattern_enable & AH_WOW_BEACON_MISS) { 461250003Sadrian val |= AR_EMB_CPU_WOW_ENABLE_BEACON_MISS; 462250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Becon Miss\n"); 463250003Sadrian } 464250003Sadrian else { 465250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Becon Miss\n"); 466250003Sadrian } 467250003Sadrian 468250003Sadrian OS_REG_WRITE(ah, AR_EMB_CPU_WOW_ENABLE, val); 469250003Sadrian 470250003Sadrian OS_REG_CLR_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_CONF); 471250003Sadrian OS_REG_SET_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_REQ); 472250003Sadrian OS_REG_SET_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_INT_EMB_CPU); 473250003Sadrian 474250003Sadrian if (!ath_hal_wait(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_CONF, AR_MBOX_WOW_CONF, bt_handshake_timeout_us)) { 475250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: WoW offload handshake failed", __func__); 476250003Sadrian return 0; 477250003Sadrian } 478250003Sadrian else { 479250003Sadrian OS_REG_CLR_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_CONF); 480250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: WoW offload handshake successful",__func__); 481250003Sadrian } 482250003Sadrian return 1; 483250003Sadrian} 484250003Sadrian#endif /* ATH_WOW_OFFLOAD */ 485250003Sadrian 486250003Sadrian/* 487250003Sadrian * Notify Power Mgt is enabled in self-generated frames. 488250003Sadrian * If requested, force chip awake. 489250003Sadrian * 490250003Sadrian * Returns A_OK if chip is awake or successfully forced awake. 491250003Sadrian * 492250003Sadrian * WARNING WARNING WARNING 493250003Sadrian * There is a problem with the chip where sometimes it will not wake up. 494250003Sadrian */ 495250003SadrianHAL_BOOL 496250003Sadrianar9300_set_power_mode_awake(struct ath_hal *ah, int set_chip) 497250003Sadrian{ 498250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 499250003Sadrian#define POWER_UP_TIME 10000 500250003Sadrian u_int32_t val; 501250003Sadrian int i; 502250003Sadrian 503250003Sadrian /* Set Bits 14 and 17 of AR_WA before powering on the chip. */ 504250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), ahp->ah_wa_reg_val); 505250003Sadrian OS_DELAY(10); /* delay to allow the write to take effect. */ 506250003Sadrian 507250003Sadrian if (set_chip) { 508250003Sadrian /* Do a Power-On-Reset if MAC is shutdown */ 509250003Sadrian if ((OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_SHUTDOWN)) { 510250003Sadrian if (ar9300_set_reset_reg(ah, HAL_RESET_POWER_ON) != AH_TRUE) { 511250003Sadrian HALASSERT(0); 512250003Sadrian return AH_FALSE; 513250003Sadrian } 514250003Sadrian } 515250003Sadrian 516250003Sadrian OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 517250003Sadrian 518250003Sadrian OS_DELAY(50); 519250003Sadrian 520250003Sadrian for (i = POWER_UP_TIME / 50; i > 0; i--) { 521250003Sadrian val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; 522250003Sadrian if (val == AR_RTC_STATUS_ON) { 523250003Sadrian break; 524250003Sadrian } 525250003Sadrian OS_DELAY(50); 526250003Sadrian OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 527250003Sadrian } 528250003Sadrian if (i == 0) { 529250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: Failed to wakeup in %uus\n", 530250003Sadrian __func__, POWER_UP_TIME / 20); 531250003Sadrian return AH_FALSE; 532250003Sadrian } 533250003Sadrian 534250003Sadrian } 535250003Sadrian 536250003Sadrian OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 537250003Sadrian return AH_TRUE; 538250003Sadrian#undef POWER_UP_TIME 539250003Sadrian} 540250003Sadrian 541250003Sadrian/* 542250003Sadrian * Notify Power Mgt is disabled in self-generated frames. 543250003Sadrian * If requested, force chip to sleep. 544250003Sadrian */ 545250003Sadrianstatic void 546250003Sadrianar9300_set_power_mode_sleep(struct ath_hal *ah, int set_chip) 547250003Sadrian{ 548250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 549250003Sadrian 550250003Sadrian OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 551250003Sadrian if (set_chip ) { 552250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 553250003Sadrian OS_REG_WRITE(ah, AR_TIMER_MODE, 554250003Sadrian OS_REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00); 555250003Sadrian OS_REG_WRITE(ah, AR_GEN_TIMERS2_MODE, 556250003Sadrian OS_REG_READ(ah, AR_GEN_TIMERS2_MODE) & 0xFFFFFF00); 557250003Sadrian OS_REG_WRITE(ah, AR_SLP32_INC, 558250003Sadrian OS_REG_READ(ah, AR_SLP32_INC) & 0xFFF00000); 559250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0); 560250003Sadrian OS_DELAY(100); 561250003Sadrian } 562250003Sadrian /* Clear the RTC force wake bit to allow the mac to go to sleep */ 563250003Sadrian OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 564250003Sadrian 565250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 566250003Sadrian /* 567250003Sadrian * In Jupiter, after enter sleep mode, hardware will send 568250003Sadrian * a SYS_SLEEPING message through MCI interface. Add a 569250003Sadrian * few us delay to make sure the message can reach BT side. 570250003Sadrian */ 571250003Sadrian OS_DELAY(100); 572250003Sadrian } 573250003Sadrian 574250003Sadrian if (!AR_SREV_JUPITER_10(ah)) { 575250003Sadrian /* Shutdown chip. Active low */ 576250003Sadrian OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); 577250003Sadrian /* Settle time */ 578250003Sadrian OS_DELAY(2); 579250003Sadrian } 580250003Sadrian } 581250003Sadrian 582250003Sadrian#if ATH_WOW_OFFLOAD 583250003Sadrian if (!AR_SREV_JUPITER(ah) || !HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_SET_4004_BIT14)) 584250003Sadrian#endif /* ATH_WOW_OFFLOAD */ 585250003Sadrian { 586250003Sadrian /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ 587250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), 588250003Sadrian ahp->ah_wa_reg_val & ~AR_WA_D3_TO_L1_DISABLE); 589250003Sadrian } 590250003Sadrian} 591250003Sadrian 592250003Sadrian/* 593250003Sadrian * Notify Power Management is enabled in self-generating 594250003Sadrian * frames. If request, set power mode of chip to 595250003Sadrian * auto/normal. Duration in units of 128us (1/8 TU). 596250003Sadrian */ 597250003Sadrianstatic void 598250003Sadrianar9300_set_power_mode_network_sleep(struct ath_hal *ah, int set_chip) 599250003Sadrian{ 600250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 601250003Sadrian 602250003Sadrian OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 603250003Sadrian if (set_chip) { 604250003Sadrian HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; 605250003Sadrian 606250003Sadrian if (! p_cap->hal_auto_sleep_support) { 607250003Sadrian /* Set wake_on_interrupt bit; clear force_wake bit */ 608250003Sadrian OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); 609250003Sadrian } 610250003Sadrian else { 611250003Sadrian /* 612250003Sadrian * When chip goes into network sleep, it could be waken up by 613250003Sadrian * MCI_INT interrupt caused by BT's HW messages (LNA_xxx, CONT_xxx) 614250003Sadrian * which chould be in a very fast rate (~100us). This will cause 615250003Sadrian * chip to leave and re-enter network sleep mode frequently, which 616250003Sadrian * in consequence will have WLAN MCI HW to generate lots of 617250003Sadrian * SYS_WAKING and SYS_SLEEPING messages which will make BT CPU 618250003Sadrian * to busy to process. 619250003Sadrian */ 620250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 621250003Sadrian OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 622250003Sadrian OS_REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) & 623250003Sadrian ~AR_MCI_INTERRUPT_RX_HW_MSG_MASK); 624250003Sadrian } 625250003Sadrian 626250003Sadrian /* Clear the RTC force wake bit to allow the mac to go to sleep */ 627250003Sadrian OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 628250003Sadrian 629250003Sadrian if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { 630250003Sadrian /* 631250003Sadrian * In Jupiter, after enter sleep mode, hardware will send 632250003Sadrian * a SYS_SLEEPING message through MCI interface. Add a 633250003Sadrian * few us delay to make sure the message can reach BT side. 634250003Sadrian */ 635250003Sadrian OS_DELAY(30); 636250003Sadrian } 637250003Sadrian } 638250003Sadrian } 639250003Sadrian 640250003Sadrian#if ATH_WOW_OFFLOAD 641250003Sadrian if (!AR_SREV_JUPITER(ah) || !HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_SET_4004_BIT14)) 642250003Sadrian#endif /* ATH_WOW_OFFLOAD */ 643250003Sadrian { 644250003Sadrian /* Clear Bit 14 of AR_WA after putting chip into Sleep mode. */ 645250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), 646250003Sadrian ahp->ah_wa_reg_val & ~AR_WA_D3_TO_L1_DISABLE); 647250003Sadrian } 648250003Sadrian} 649250003Sadrian 650250003Sadrian/* 651250003Sadrian * Set power mgt to the requested mode, and conditionally set 652250003Sadrian * the chip as well 653250003Sadrian */ 654250003SadrianHAL_BOOL 655250003Sadrianar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip) 656250003Sadrian{ 657250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 658250003Sadrian#if AH_DEBUG || AH_PRINT_FILTER 659250003Sadrian static const char* modes[] = { 660250003Sadrian "AWAKE", 661250003Sadrian "FULL-SLEEP", 662250003Sadrian "NETWORK SLEEP", 663250003Sadrian "UNDEFINED" 664250003Sadrian }; 665250003Sadrian#endif 666250003Sadrian int status = AH_TRUE; 667250003Sadrian 668250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__, 669250003Sadrian modes[ar9300_get_power_mode(ah)], modes[mode], 670250003Sadrian set_chip ? "set chip " : ""); 671250003Sadrian 672250003Sadrian switch (mode) { 673250003Sadrian case HAL_PM_AWAKE: 674250003Sadrian status = ar9300_set_power_mode_awake(ah, set_chip); 675250003Sadrian#if ATH_SUPPORT_MCI 676250003Sadrian if (AH_PRIVATE(ah)->ah_caps.hal_mci_support) { 677250003Sadrian OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); 678250003Sadrian } 679250003Sadrian#endif 680250003Sadrian break; 681250003Sadrian case HAL_PM_FULL_SLEEP: 682250003Sadrian#if ATH_SUPPORT_MCI 683250003Sadrian if (AH_PRIVATE(ah)->ah_caps.hal_mci_support) { 684250003Sadrian if (ar9300_get_power_mode(ah) == HAL_PM_AWAKE) { 685250003Sadrian if ((ar9300_mci_state(ah, HAL_MCI_STATE_ENABLE, NULL) != 0) && 686250003Sadrian (ahp->ah_mci_bt_state != MCI_BT_SLEEP) && 687250003Sadrian !ahp->ah_mci_halted_bt_gpm) 688250003Sadrian { 689250003Sadrian HALDEBUG(ah, HAL_DEBUG_BT_COEX, 690250003Sadrian "(MCI) %s: HALT BT GPM (full_sleep)\n", __func__); 691250003Sadrian ar9300_mci_send_coex_halt_bt_gpm(ah, AH_TRUE, AH_TRUE); 692250003Sadrian } 693250003Sadrian } 694250003Sadrian ahp->ah_mci_ready = AH_FALSE; 695250003Sadrian } 696250003Sadrian#endif 697250003Sadrian#if ATH_SUPPORT_MCI 698250003Sadrian if (AH_PRIVATE(ah)->ah_caps.hal_mci_support) { 699250003Sadrian OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); 700250003Sadrian } 701250003Sadrian#endif 702250003Sadrian ar9300_set_power_mode_sleep(ah, set_chip); 703250003Sadrian ahp->ah_chip_full_sleep = AH_TRUE; 704250003Sadrian break; 705250003Sadrian case HAL_PM_NETWORK_SLEEP: 706250003Sadrian#if ATH_SUPPORT_MCI 707250003Sadrian if (AH_PRIVATE(ah)->ah_caps.hal_mci_support) { 708250003Sadrian OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); 709250003Sadrian } 710250003Sadrian#endif 711250003Sadrian ar9300_set_power_mode_network_sleep(ah, set_chip); 712250003Sadrian break; 713250003Sadrian default: 714250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 715250003Sadrian "%s: unknown power mode %u\n", __func__, mode); 716250003Sadrian return AH_FALSE; 717250003Sadrian } 718250003Sadrian return status; 719250003Sadrian} 720250003Sadrian 721250003Sadrian/* 722250003Sadrian * Return the current sleep mode of the chip 723250003Sadrian */ 724250003SadrianHAL_POWER_MODE 725250003Sadrianar9300_get_power_mode(struct ath_hal *ah) 726250003Sadrian{ 727250003Sadrian int mode = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; 728250003Sadrian 729250003Sadrian switch (mode) { 730250003Sadrian case AR_RTC_STATUS_ON: 731250003Sadrian case AR_RTC_STATUS_WAKEUP: 732250003Sadrian return HAL_PM_AWAKE; 733250003Sadrian break; 734250003Sadrian case AR_RTC_STATUS_SLEEP: 735250003Sadrian return HAL_PM_NETWORK_SLEEP; 736250003Sadrian break; 737250003Sadrian case AR_RTC_STATUS_SHUTDOWN: 738250003Sadrian return HAL_PM_FULL_SLEEP; 739250003Sadrian break; 740250003Sadrian default: 741250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, 742250003Sadrian "%s: unknown power mode 0x%x\n", __func__, mode); 743250003Sadrian return HAL_PM_UNDEFINED; 744250003Sadrian } 745250003Sadrian} 746250003Sadrian 747250003Sadrian/* 748250003Sadrian * Set SM power save mode 749250003Sadrian */ 750250003Sadrianvoid 751250003Sadrianar9300_set_sm_power_mode(struct ath_hal *ah, HAL_SMPS_MODE mode) 752250003Sadrian{ 753250003Sadrian int regval; 754250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 755250003Sadrian 756250003Sadrian if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) != HAL_OK) { 757250003Sadrian return; 758250003Sadrian } 759250003Sadrian 760250003Sadrian /* Program low & high power chainmask settings and enable MAC control */ 761250003Sadrian regval = SM(AR_PCU_SMPS_LPWR_CHNMSK_VAL, AR_PCU_SMPS_LPWR_CHNMSK) | 762250003Sadrian SM(ahp->ah_rx_chainmask, AR_PCU_SMPS_HPWR_CHNMSK) | 763250003Sadrian AR_PCU_SMPS_MAC_CHAINMASK; 764250003Sadrian 765250003Sadrian /* Program registers according to required SM power mode.*/ 766250003Sadrian switch (mode) { 767250003Sadrian case HAL_SMPS_SW_CTRL_LOW_PWR: 768250003Sadrian OS_REG_WRITE(ah, AR_PCU_SMPS, regval); 769250003Sadrian break; 770250003Sadrian case HAL_SMPS_SW_CTRL_HIGH_PWR: 771250003Sadrian OS_REG_WRITE(ah, AR_PCU_SMPS, regval | AR_PCU_SMPS_SW_CTRL_HPWR); 772250003Sadrian break; 773250003Sadrian case HAL_SMPS_HW_CTRL: 774250003Sadrian OS_REG_WRITE(ah, AR_PCU_SMPS, regval | AR_PCU_SMPS_HW_CTRL_EN); 775250003Sadrian break; 776250003Sadrian case HAL_SMPS_DEFAULT: 777250003Sadrian OS_REG_WRITE(ah, AR_PCU_SMPS, 0); 778250003Sadrian break; 779250003Sadrian default: 780250003Sadrian break; 781250003Sadrian } 782250003Sadrian ahp->ah_sm_power_mode = mode; 783250003Sadrian} 784250003Sadrian 785250003Sadrian#if ATH_WOW 786250003Sadrian#if NOT_NEEDED_FOR_OSPREY /* not compiled for darwin */ 787250003Sadrian/* 788250003Sadrian * This routine is called to configure the SerDes register for the 789250003Sadrian * Merlin 2.0 and above chip during WOW sleep. 790250003Sadrian */ 791250003Sadrianstatic void 792250003Sadrianar9280_config_ser_des__wow_sleep(struct ath_hal *ah) 793250003Sadrian{ 794250003Sadrian int i; 795250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 796250003Sadrian 797250003Sadrian /* 798250003Sadrian * For WOW sleep, we reprogram the SerDes so that the PLL and CHK REQ 799250003Sadrian * are both enabled. This uses more power but the Maverick team reported 800250003Sadrian * that otherwise, WOW sleep is unstable and chip may disappears. 801250003Sadrian */ 802250003Sadrian for (i = 0; i < ahp->ah_ini_pcie_serdes_wow.ia_rows; i++) { 803250003Sadrian OS_REG_WRITE(ah, 804250003Sadrian INI_RA(&ahp->ah_ini_pcie_serdes_wow, i, 0), 805250003Sadrian INI_RA(&ahp->ah_ini_pcie_serdes_wow, i, 1)); 806250003Sadrian } 807250003Sadrian OS_DELAY(1000); 808250003Sadrian} 809250003Sadrian#endif /* if NOT_NEEDED_FOR_OSPREY */ 810250003Sadrianstatic HAL_BOOL 811250003Sadrianar9300_wow_create_keep_alive_pattern(struct ath_hal *ah) 812250003Sadrian{ 813250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 814250003Sadrian u_int32_t frame_len = 28; 815250003Sadrian u_int32_t tpc = 0x3f; 816250003Sadrian u_int32_t transmit_rate; 817250003Sadrian u_int32_t frame_type = 0x2; /* Frame Type -> Data; */ 818250003Sadrian u_int32_t sub_type = 0x4; /* Subtype -> Null Data */ 819250003Sadrian u_int32_t to_ds = 1; 820250003Sadrian u_int32_t duration_id = 0x3d; 821250003Sadrian u_int8_t *sta_mac_addr, *ap_mac_addr; 822250003Sadrian u_int8_t *addr1, *addr2, *addr3; 823250003Sadrian u_int32_t ctl[13] = { 0, }; 824250003Sadrian#define NUM_KA_DATA_WORDS 6 825250003Sadrian u_int32_t data_word[NUM_KA_DATA_WORDS]; 826250003Sadrian u_int32_t i; 827250003Sadrian u_int32_t wow_ka_dataword0; 828250003Sadrian 829250003Sadrian sta_mac_addr = (u_int8_t *)ahp->ah_macaddr; 830250003Sadrian ap_mac_addr = (u_int8_t *)ahp->ah_bssid; 831250003Sadrian addr2 = sta_mac_addr; 832250003Sadrian addr1 = addr3 = ap_mac_addr; 833250003Sadrian 834250003Sadrian if (AH_PRIVATE(ah)->ah_curchan->channel_flags & CHANNEL_CCK) { 835250003Sadrian transmit_rate = 0x1B; /* CCK_1M */ 836250003Sadrian } else { 837250003Sadrian transmit_rate = 0xB; /* OFDM_6M */ 838250003Sadrian } 839250003Sadrian 840250003Sadrian /* Set the Transmit Buffer. */ 841250003Sadrian ctl[0] = (frame_len | (tpc << 16)); 842250003Sadrian ctl[1] = 0; 843250003Sadrian ctl[2] = (0x7 << 16); /* tx_tries0 */ 844250003Sadrian ctl[3] = transmit_rate; 845250003Sadrian ctl[4] = 0; 846250003Sadrian ctl[7] = ahp->ah_tx_chainmask << 2; 847250003Sadrian 848250003Sadrian for (i = 0; i < 13; i++) { 849250003Sadrian OS_REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); 850250003Sadrian } 851250003Sadrian 852250003Sadrian data_word[0] = 853250003Sadrian (frame_type << 2) | 854250003Sadrian (sub_type << 4) | 855250003Sadrian (to_ds << 8) | 856250003Sadrian (duration_id << 16); 857250003Sadrian data_word[1] = (((u_int32_t)addr1[3] << 24) | ((u_int32_t)addr1[2] << 16) | 858250003Sadrian ((u_int32_t)addr1[1]) << 8 | ((u_int32_t)addr1[0])); 859250003Sadrian data_word[2] = (((u_int32_t)addr2[1] << 24) | ((u_int32_t)addr2[0] << 16) | 860250003Sadrian ((u_int32_t)addr1[5]) << 8 | ((u_int32_t)addr1[4])); 861250003Sadrian data_word[3] = (((u_int32_t)addr2[5] << 24) | ((u_int32_t)addr2[4] << 16) | 862250003Sadrian ((u_int32_t)addr2[3]) << 8 | ((u_int32_t)addr2[2])); 863250003Sadrian data_word[4] = (((u_int32_t)addr3[3] << 24) | ((u_int32_t)addr3[2] << 16) | 864250003Sadrian ((u_int32_t)addr3[1]) << 8 | (u_int32_t)addr3[0]); 865250003Sadrian data_word[5] = (((u_int32_t)addr3[5]) << 8 | ((u_int32_t)addr3[4])); 866250003Sadrian 867250003Sadrian if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) { 868250003Sadrian /* Jupiter 2.0 has an extra descriptor word (Time based 869250003Sadrian * discard) compared to other chips */ 870250003Sadrian OS_REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + 12 * 4), 0); 871250003Sadrian wow_ka_dataword0 = AR_WOW_TXBUF(13); 872250003Sadrian } 873250003Sadrian else { 874250003Sadrian wow_ka_dataword0 = AR_WOW_TXBUF(12); 875250003Sadrian } 876250003Sadrian 877250003Sadrian for (i = 0; i < NUM_KA_DATA_WORDS; i++) { 878250003Sadrian OS_REG_WRITE(ah, (wow_ka_dataword0 + i * 4), data_word[i]); 879250003Sadrian } 880250003Sadrian 881250003Sadrian return AH_TRUE; 882250003Sadrian} 883250003Sadrian 884250003Sadrian/* TBD: Should querying hal for hardware capability */ 885250003Sadrian#define MAX_PATTERN_SIZE 256 886250003Sadrian#define MAX_PATTERN_MASK_SIZE 32 887250003Sadrian#define MAX_NUM_USER_PATTERN 6 /* Deducting the disassoc/deauth packets */ 888250003Sadrian 889250003Sadrianvoid 890250003Sadrianar9300_wow_apply_pattern( 891250003Sadrian struct ath_hal *ah, 892250003Sadrian u_int8_t *p_ath_pattern, 893250003Sadrian u_int8_t *p_ath_mask, 894250003Sadrian int32_t pattern_count, 895250003Sadrian u_int32_t ath_pattern_len) 896250003Sadrian{ 897250003Sadrian int i; 898250003Sadrian u_int32_t reg_pat[] = { 899250003Sadrian AR_WOW_TB_PATTERN0, 900250003Sadrian AR_WOW_TB_PATTERN1, 901250003Sadrian AR_WOW_TB_PATTERN2, 902250003Sadrian AR_WOW_TB_PATTERN3, 903250003Sadrian AR_WOW_TB_PATTERN4, 904250003Sadrian AR_WOW_TB_PATTERN5, 905250003Sadrian AR_WOW_TB_PATTERN6, 906250003Sadrian AR_WOW_TB_PATTERN7 907250003Sadrian }; 908250003Sadrian u_int32_t reg_mask[] = { 909250003Sadrian AR_WOW_TB_MASK0, 910250003Sadrian AR_WOW_TB_MASK1, 911250003Sadrian AR_WOW_TB_MASK2, 912250003Sadrian AR_WOW_TB_MASK3, 913250003Sadrian AR_WOW_TB_MASK4, 914250003Sadrian AR_WOW_TB_MASK5, 915250003Sadrian AR_WOW_TB_MASK6, 916250003Sadrian AR_WOW_TB_MASK7 917250003Sadrian }; 918250003Sadrian u_int32_t pattern_val; 919250003Sadrian u_int32_t mask_val; 920250003Sadrian u_int32_t val; 921250003Sadrian u_int8_t mask_bit = 0x1; 922250003Sadrian u_int8_t pattern; 923250003Sadrian 924250003Sadrian /* TBD: should check count by querying the hardware capability */ 925250003Sadrian if (pattern_count >= MAX_NUM_USER_PATTERN) { 926250003Sadrian return; 927250003Sadrian } 928250003Sadrian 929250003Sadrian pattern = (u_int8_t)OS_REG_READ(ah, AR_WOW_PATTERN_REG); 930250003Sadrian pattern = pattern | (mask_bit << pattern_count); 931250003Sadrian OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, pattern); 932250003Sadrian 933250003Sadrian /* Set the registers for pattern */ 934250003Sadrian for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { 935250003Sadrian pattern_val = (((u_int32_t)p_ath_pattern[i + 0]) | 936250003Sadrian ((u_int32_t)p_ath_pattern[i + 1] << 8) | 937250003Sadrian ((u_int32_t)p_ath_pattern[i + 2] << 16) | 938250003Sadrian ((u_int32_t)p_ath_pattern[i + 3] << 24)); 939250003Sadrian OS_REG_WRITE(ah, (reg_pat[pattern_count] + i), pattern_val); 940250003Sadrian } 941250003Sadrian 942250003Sadrian /* Set the registers for mask */ 943250003Sadrian for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { 944250003Sadrian mask_val = (((u_int32_t)p_ath_mask[i + 0]) | 945250003Sadrian ((u_int32_t)p_ath_mask[i + 1] << 8) | 946250003Sadrian ((u_int32_t)p_ath_mask[i + 2] << 16) | 947250003Sadrian ((u_int32_t)p_ath_mask[i + 3] << 24)); 948250003Sadrian OS_REG_WRITE(ah, (reg_mask[pattern_count] + i), mask_val); 949250003Sadrian } 950250003Sadrian 951250003Sadrian /* XXX */ 952250003Sadrian /* Set the pattern length to be matched */ 953250003Sadrian if (pattern_count < 4) { 954250003Sadrian /* Pattern 0-3 uses AR_WOW_LENGTH1_REG register */ 955250003Sadrian val = OS_REG_READ(ah, AR_WOW_LENGTH1_REG); 956250003Sadrian val = ((val & (~AR_WOW_LENGTH1_MASK(pattern_count))) | 957250003Sadrian ((ath_pattern_len & AR_WOW_LENGTH_MAX) << 958250003Sadrian AR_WOW_LENGTH1_SHIFT(pattern_count))); 959250003Sadrian OS_REG_WRITE(ah, AR_WOW_LENGTH1_REG, val); 960250003Sadrian } else { 961250003Sadrian /* Pattern 4-7 uses AR_WOW_LENGTH2_REG register */ 962250003Sadrian val = OS_REG_READ(ah, AR_WOW_LENGTH2_REG); 963250003Sadrian val = ((val & (~AR_WOW_LENGTH2_MASK(pattern_count))) | 964250003Sadrian ((ath_pattern_len & AR_WOW_LENGTH_MAX) << 965250003Sadrian AR_WOW_LENGTH2_SHIFT(pattern_count))); 966250003Sadrian OS_REG_WRITE(ah, AR_WOW_LENGTH2_REG, val); 967250003Sadrian } 968250003Sadrian 969250003Sadrian AH_PRIVATE(ah)->ah_wow_event_mask |= 970250003Sadrian (1 << (pattern_count + AR_WOW_PATTERN_FOUND_SHIFT)); 971250003Sadrian 972250003Sadrian return; 973250003Sadrian} 974250003Sadrian 975250003SadrianHAL_BOOL 976250003Sadrianar9300_set_power_mode_wow_sleep(struct ath_hal *ah) 977250003Sadrian{ 978250003Sadrian OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 979250003Sadrian 980250003Sadrian OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ 981250003Sadrian if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { 982250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: dma failed to stop in 10ms\n" 983250003Sadrian "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", __func__, 984250003Sadrian OS_REG_READ(ah, AR_CR), OS_REG_READ(ah, AR_DIAG_SW)); 985250003Sadrian return AH_FALSE; 986250003Sadrian } else { 987250003Sadrian#if 0 988250003Sadrian OS_REG_WRITE(ah, AR_RXDP, 0x0); 989250003Sadrian#endif 990250003Sadrian 991250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 992250003Sadrian "%s: TODO How to disable RXDP!!\n", __func__); 993250003Sadrian 994250003Sadrian#if ATH_SUPPORT_MCI 995250003Sadrian if (AH_PRIVATE(ah)->ah_caps.hal_mci_support) { 996250003Sadrian OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); 997250003Sadrian } 998250003Sadrian#endif 999250003Sadrian OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); 1000250003Sadrian 1001250003Sadrian return AH_TRUE; 1002250003Sadrian } 1003250003Sadrian} 1004250003Sadrian 1005250003Sadrian 1006250003SadrianHAL_BOOL 1007250003Sadrianar9300_wow_enable( 1008250003Sadrian struct ath_hal *ah, 1009250003Sadrian u_int32_t pattern_enable, 1010250003Sadrian u_int32_t timeout_in_seconds, 1011250003Sadrian int clearbssid, 1012250003Sadrian HAL_BOOL offloadEnable) 1013250003Sadrian{ 1014250003Sadrian uint32_t init_val, val, rval = 0; 1015250003Sadrian const int ka_delay = 4; /* Delay of 4 millisec between two keep_alive's */ 1016250003Sadrian uint32_t wow_event_mask; 1017250003Sadrian#if ATH_WOW_OFFLOAD 1018250003Sadrian uint32_t wow_feature_enable = 1019250003Sadrian //AR_WOW_OFFLOAD_ENA_GTK | 1020250003Sadrian //AR_WOW_OFFLOAD_ENA_ARP_OFFLOAD | 1021250003Sadrian //AR_WOW_OFFLOAD_ENA_NS_OFFLOAD | 1022250003Sadrian //AR_WOW_OFFLOAD_ENA_ACER_MAGIC | 1023250003Sadrian //AR_WOW_OFFLOAD_ENA_STD_MAGIC | 1024250003Sadrian //AR_WOW_OFFLOAD_ENA_4WAY_WAKE | 1025250003Sadrian //AR_WOW_OFFLOAD_ENA_SWKA | 1026250003Sadrian //AR_WOW_OFFLOAD_ENA_BT_SLEEP | 1027250003Sadrian AR_WOW_OFFLOAD_ENA_SW_NULL; 1028250003Sadrian#endif 1029250003Sadrian 1030250003Sadrian /* 1031250003Sadrian * ah_wow_event_mask is a mask to the AR_WOW_PATTERN_REG register to 1032250003Sadrian * indicate which WOW events that we have enabled. The WOW Events are 1033250003Sadrian * from the pattern_enable in this function and pattern_count of 1034250003Sadrian * ar9300_wow_apply_pattern() 1035250003Sadrian */ 1036250003Sadrian wow_event_mask = AH_PRIVATE(ah)->ah_wow_event_mask; 1037250003Sadrian 1038250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 1039250003Sadrian "%s: offload: %d, pattern: %08x, event_mask: %08x\n", 1040250003Sadrian __func__, offloadEnable, pattern_enable, wow_event_mask); 1041250003Sadrian 1042250003Sadrian /* 1043250003Sadrian * Untie Power-On-Reset from the PCI-E Reset. When we are in WOW sleep, 1044250003Sadrian * we do not want the Reset from the PCI-E to disturb our hw state. 1045250003Sadrian */ 1046250003Sadrian if (AH_PRIVATE(ah)->ah_is_pci_express == AH_TRUE) { 1047250003Sadrian 1048250003Sadrian u_int32_t wa_reg_val; 1049250003Sadrian /* 1050250003Sadrian * We need to untie the internal POR (power-on-reset) to the external 1051250003Sadrian * PCI-E reset. We also need to tie the PCI-E Phy reset to the PCI-E 1052250003Sadrian * reset. 1053250003Sadrian */ 1054250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 1055250003Sadrian "%s: Untie POR and PCIE reset\n", __func__); 1056250003Sadrian wa_reg_val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_WA)); 1057250003Sadrian wa_reg_val = wa_reg_val & ~(AR_WA_UNTIE_RESET_EN); 1058250003Sadrian wa_reg_val = wa_reg_val | AR_WA_RESET_EN | AR_WA_POR_SHORT; 1059250003Sadrian /* 1060250003Sadrian * This bit is to bypass the EEPROM/OTP state machine, (by clearing its 1061250003Sadrian * busy state while PCIE_rst is asserted), to allow BT embedded CPU 1062250003Sadrian * be able to access WLAN registers. Otherwise the eCPU access will be 1063250003Sadrian * stalled as eeprom_sm is held in busy state. 1064250003Sadrian * 1065250003Sadrian * EV91928 is that when this bit is set, after host wakeup and PCIE_rst 1066250003Sadrian * deasserted, PCIE configuration registers will be reset and DeviceID 1067250003Sadrian * SubsystemID etc. registers will be different from values before 1068250003Sadrian * entering sleep. This will cause Windows to detect a device removal. 1069250003Sadrian * 1070250003Sadrian * For HW WOW, this bit should keep as cleared. 1071250003Sadrian */ 1072250003Sadrian if (offloadEnable) { 1073250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 1074250003Sadrian "%s: Set AR_WA.13 COLD_RESET_OVERRIDE\n", __func__); 1075250003Sadrian wa_reg_val = wa_reg_val | AR_WA_COLD_RESET_OVERRIDE; 1076250003Sadrian 1077250003Sadrian#if ATH_WOW_OFFLOAD 1078250003Sadrian if (AR_SREV_JUPITER(ah)) { 1079250003Sadrian wa_reg_val = wa_reg_val | AR_WA_D3_TO_L1_DISABLE; 1080250003Sadrian } 1081250003Sadrian#endif 1082250003Sadrian } 1083250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), wa_reg_val); 1084250003Sadrian } 1085250003Sadrian 1086250003Sadrian /* 1087250003Sadrian * Set the power states appropriately and enable pme. 1088250003Sadrian */ 1089250003Sadrian val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL)); 1090250003Sadrian val |= 1091250003Sadrian AR_PMCTRL_HOST_PME_EN | 1092250003Sadrian AR_PMCTRL_PWR_PM_CTRL_ENA | 1093250003Sadrian AR_PMCTRL_AUX_PWR_DET; 1094250003Sadrian 1095250003Sadrian /* 1096250003Sadrian * Set and clear WOW_PME_CLEAR registers for the chip to generate next 1097250003Sadrian * wow signal. 1098250003Sadrian */ 1099250003Sadrian val |= AR_PMCTRL_WOW_PME_CLR; 1100250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), val); 1101250003Sadrian val &= ~AR_PMCTRL_WOW_PME_CLR; 1102250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), val); 1103250003Sadrian 1104250003Sadrian /* 1105250003Sadrian * Setup for for: 1106250003Sadrian * - beacon misses 1107250003Sadrian * - magic pattern 1108250003Sadrian * - keep alive timeout 1109250003Sadrian * - pattern matching 1110250003Sadrian */ 1111250003Sadrian 1112250003Sadrian /* 1113250003Sadrian * Program some default values for keep-alives, beacon misses, etc. 1114250003Sadrian */ 1115250003Sadrian init_val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); 1116250003Sadrian val = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF) | init_val; 1117250003Sadrian OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, val); 1118250003Sadrian rval = OS_REG_READ(ah, AR_WOW_PATTERN_REG); 1119250003Sadrian 1120250003Sadrian val = 1121250003Sadrian AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | 1122250003Sadrian AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | 1123250003Sadrian AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); 1124250003Sadrian OS_REG_WRITE(ah, AR_WOW_COUNT_REG, val); 1125250003Sadrian rval = OS_REG_READ(ah, AR_WOW_COUNT_REG); 1126250003Sadrian 1127250003Sadrian if (pattern_enable & AH_WOW_BEACON_MISS) { 1128250003Sadrian val = AR_WOW_BEACON_TIMO; 1129250003Sadrian } else { 1130250003Sadrian /* We are not using the beacon miss. Program a large value. */ 1131250003Sadrian val = AR_WOW_BEACON_TIMO_MAX; 1132250003Sadrian } 1133250003Sadrian OS_REG_WRITE(ah, AR_WOW_BCN_TIMO_REG, val); 1134250003Sadrian rval = OS_REG_READ(ah, AR_WOW_BCN_TIMO_REG); 1135250003Sadrian 1136250003Sadrian /* 1137250003Sadrian * Keep Alive Timo in ms. 1138250003Sadrian */ 1139250003Sadrian if (pattern_enable == 0) { 1140250003Sadrian val = AR_WOW_KEEP_ALIVE_NEVER; 1141250003Sadrian } else { 1142250003Sadrian val = AH_PRIVATE(ah)->ah_config.ath_hal_keep_alive_timeout * 32; 1143250003Sadrian } 1144250003Sadrian OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO_REG, val); 1145250003Sadrian rval = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_TIMO_REG); 1146250003Sadrian 1147250003Sadrian /* 1148250003Sadrian * Keep Alive delay in us. 1149250003Sadrian */ 1150250003Sadrian val = ka_delay * 1000; 1151250003Sadrian OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY_REG, val); 1152250003Sadrian rval = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_DELAY_REG); 1153250003Sadrian 1154250003Sadrian /* 1155250003Sadrian * Create keep_alive Pattern to respond to beacons. 1156250003Sadrian */ 1157250003Sadrian ar9300_wow_create_keep_alive_pattern(ah); 1158250003Sadrian 1159250003Sadrian /* 1160250003Sadrian * Configure Mac Wow Registers. 1161250003Sadrian */ 1162250003Sadrian 1163250003Sadrian val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_REG); 1164250003Sadrian 1165250003Sadrian /* 1166250003Sadrian * Send keep alive timeouts anyway. 1167250003Sadrian */ 1168250003Sadrian val &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS; 1169250003Sadrian 1170250003Sadrian if (pattern_enable & AH_WOW_LINK_CHANGE) { 1171250003Sadrian val &= ~ AR_WOW_KEEP_ALIVE_FAIL_DIS; 1172250003Sadrian wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; 1173250003Sadrian } else { 1174250003Sadrian val |= AR_WOW_KEEP_ALIVE_FAIL_DIS; 1175250003Sadrian } 1176250003Sadrian#if ATH_WOW_OFFLOAD 1177250003Sadrian if (offloadEnable) { 1178250003Sadrian /* Don't enable KA frames yet. BT CPU is not 1179250003Sadrian * yet ready. */ 1180250003Sadrian } 1181250003Sadrian else 1182250003Sadrian#endif /* ATH_WOW_OFFLOAD */ 1183250003Sadrian { 1184250003Sadrian OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_REG, val); 1185250003Sadrian val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_REG); 1186250003Sadrian } 1187250003Sadrian 1188250003Sadrian 1189250003Sadrian /* 1190250003Sadrian * We are relying on a bmiss failure. Ensure we have enough 1191250003Sadrian * threshold to prevent AH_FALSE positives. 1192250003Sadrian */ 1193250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, 1194250003Sadrian AR_WOW_BMISSTHRESHOLD); 1195250003Sadrian 1196250003Sadrian val = OS_REG_READ(ah, AR_WOW_BCN_EN_REG); 1197250003Sadrian if (pattern_enable & AH_WOW_BEACON_MISS) { 1198250003Sadrian val |= AR_WOW_BEACON_FAIL_EN; 1199250003Sadrian wow_event_mask |= AR_WOW_BEACON_FAIL; 1200250003Sadrian } else { 1201250003Sadrian val &= ~AR_WOW_BEACON_FAIL_EN; 1202250003Sadrian } 1203250003Sadrian OS_REG_WRITE(ah, AR_WOW_BCN_EN_REG, val); 1204250003Sadrian val = OS_REG_READ(ah, AR_WOW_BCN_EN_REG); 1205250003Sadrian 1206250003Sadrian /* 1207250003Sadrian * Enable the magic packet registers. 1208250003Sadrian */ 1209250003Sadrian val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); 1210250003Sadrian if ((pattern_enable & AH_WOW_MAGIC_PATTERN_EN) 1211250003Sadrian#if ATH_WOW_OFFLOAD 1212250003Sadrian || (pattern_enable & AH_WOW_ACER_MAGIC_EN) 1213250003Sadrian#endif 1214250003Sadrian ) 1215250003Sadrian { 1216250003Sadrian val |= AR_WOW_MAGIC_EN; 1217250003Sadrian wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; 1218250003Sadrian } else { 1219250003Sadrian val &= ~AR_WOW_MAGIC_EN; 1220250003Sadrian } 1221250003Sadrian val |= AR_WOW_MAC_INTR_EN; 1222250003Sadrian OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, val); 1223250003Sadrian val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); 1224250003Sadrian 1225250003Sadrian#if ATH_WOW_OFFLOAD 1226250003Sadrian if (HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_FORCE_BT_SLEEP)) { 1227250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_BT_SLEEP; 1228250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - BT SLEEP\n"); 1229250003Sadrian } else { 1230250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_BT_SLEEP; 1231250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - BT SLEEP\n"); 1232250003Sadrian } 1233250003Sadrian 1234250003Sadrian if (HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_SW_NULL_DISABLE)) { 1235250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - SW NULL\n"); 1236250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_SW_NULL; 1237250003Sadrian } else { 1238250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - SW NULL\n"); 1239250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_SW_NULL; 1240250003Sadrian } 1241250003Sadrian 1242250003Sadrian if (HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_DEVID_SWAR_DISABLE)) { 1243250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - DevID SWAR\n"); 1244250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_DEVID_SWAR; 1245250003Sadrian } else { 1246250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - DevID SWAR\n"); 1247250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_DEVID_SWAR; 1248250003Sadrian } 1249250003Sadrian 1250250003Sadrian if (pattern_enable & AH_WOW_ACER_KEEP_ALIVE_EN) { 1251250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Acer SWKA\n"); 1252250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_SWKA; 1253250003Sadrian } else { 1254250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Acer SWKA\n"); 1255250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_SWKA; 1256250003Sadrian } 1257250003Sadrian 1258250003Sadrian if (pattern_enable & AH_WOW_ACER_MAGIC_EN) { 1259250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Standard Magic\n"); 1260250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_STD_MAGIC; 1261250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Acer Magic\n"); 1262250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_ACER_MAGIC; 1263250003Sadrian } else { 1264250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - Standard Magic\n"); 1265250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_STD_MAGIC; 1266250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - Acer Magic\n"); 1267250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_ACER_MAGIC; 1268250003Sadrian } 1269250003Sadrian 1270250003Sadrian if ((pattern_enable & AH_WOW_4WAY_HANDSHAKE_EN) || 1271250003Sadrian HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_FORCE_4WAY_HS_WAKE)) { 1272250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - 4Way Handshake\n"); 1273250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_4WAY_WAKE; 1274250003Sadrian } else { 1275250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - 4Way Handshake\n"); 1276250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_4WAY_WAKE; 1277250003Sadrian } 1278250003Sadrian 1279250003Sadrian if((pattern_enable & AH_WOW_AP_ASSOCIATION_LOST_EN) || 1280250003Sadrian HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_FORCE_AP_LOSS_WAKE)) 1281250003Sadrian { 1282250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - AP loss wake\n"); 1283250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_AP_LOSS_WAKE; 1284250003Sadrian } else { 1285250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - AP loss wake\n"); 1286250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_AP_LOSS_WAKE; 1287250003Sadrian } 1288250003Sadrian 1289250003Sadrian if((pattern_enable & AH_WOW_GTK_HANDSHAKE_ERROR_EN) || 1290250003Sadrian HAL_WOW_CTRL(ah, HAL_WOW_OFFLOAD_FORCE_GTK_ERR_WAKE)) 1291250003Sadrian { 1292250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - GTK error wake\n"); 1293250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_GTK_ERROR_WAKE; 1294250003Sadrian } else { 1295250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - GTK error wake\n"); 1296250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_GTK_ERROR_WAKE; 1297250003Sadrian } 1298250003Sadrian 1299250003Sadrian if (pattern_enable & AH_WOW_GTK_OFFLOAD_EN) { 1300250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - GTK offload\n"); 1301250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_GTK; 1302250003Sadrian } else { 1303250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - GTK offload\n"); 1304250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_GTK; 1305250003Sadrian } 1306250003Sadrian 1307250003Sadrian if (pattern_enable & AH_WOW_ARP_OFFLOAD_EN) { 1308250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - ARP offload\n"); 1309250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_ARP_OFFLOAD; 1310250003Sadrian } else { 1311250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - ARP offload\n"); 1312250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_ARP_OFFLOAD; 1313250003Sadrian } 1314250003Sadrian 1315250003Sadrian if (pattern_enable & AH_WOW_NS_OFFLOAD_EN) { 1316250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) ENA - NS offload\n"); 1317250003Sadrian wow_feature_enable |= AR_WOW_OFFLOAD_ENA_NS_OFFLOAD; 1318250003Sadrian } else { 1319250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) DIS - NS offload\n"); 1320250003Sadrian wow_feature_enable &= ~AR_WOW_OFFLOAD_ENA_NS_OFFLOAD; 1321250003Sadrian } 1322250003Sadrian 1323250003Sadrian#endif /* ATH_WOW_OFFLOAD */ 1324250003Sadrian 1325250003Sadrian /* For Kite and later version of the chips 1326250003Sadrian * enable wow pattern match for packets less than 1327250003Sadrian * 256 bytes for all patterns. 1328250003Sadrian */ 1329250003Sadrian /* XXX */ 1330250003Sadrian OS_REG_WRITE( 1331250003Sadrian ah, AR_WOW_PATTERN_MATCH_LT_256B_REG, AR_WOW_PATTERN_SUPPORTED); 1332250003Sadrian 1333250003Sadrian /* 1334250003Sadrian * Set the power states appropriately and enable PME. 1335250003Sadrian */ 1336250003Sadrian val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL)); 1337250003Sadrian val |= 1338250003Sadrian AR_PMCTRL_PWR_STATE_D1D3 | 1339250003Sadrian AR_PMCTRL_HOST_PME_EN | 1340250003Sadrian AR_PMCTRL_PWR_PM_CTRL_ENA; 1341250003Sadrian val &= ~AR_PCIE_PM_CTRL_ENA; 1342250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), val); 1343250003Sadrian 1344250003Sadrian /* Wake on Timer Interrupt. Test mode only. Used in Manufacturing line. */ 1345250003Sadrian if (timeout_in_seconds) { 1346250003Sadrian /* convert Timeout to u_secs */ 1347250003Sadrian OS_REG_WRITE(ah, AR_NEXT_NDP_TIMER, 1348250003Sadrian OS_REG_READ(ah, AR_TSF_L32) + timeout_in_seconds * 1000000 ); 1349250003Sadrian /* timer_period = 30 seconds always */ 1350250003Sadrian OS_REG_WRITE(ah, AR_NDP_PERIOD, 30 * 1000000); 1351250003Sadrian OS_REG_WRITE(ah, AR_TIMER_MODE, OS_REG_READ(ah, AR_TIMER_MODE) | 0x80); 1352250003Sadrian OS_REG_WRITE(ah, AR_IMR_S5, OS_REG_READ(ah, AR_IMR_S5) | 0x80); 1353250003Sadrian OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_GENTMR); 1354250003Sadrian if (clearbssid) { 1355250003Sadrian OS_REG_WRITE(ah, AR_BSS_ID0, 0); 1356250003Sadrian OS_REG_WRITE(ah, AR_BSS_ID1, 0); 1357250003Sadrian } 1358250003Sadrian } 1359250003Sadrian 1360250003Sadrian /* Enable Seq# generation when asleep. */ 1361250003Sadrian OS_REG_WRITE(ah, AR_STA_ID1, 1362250003Sadrian OS_REG_READ(ah, AR_STA_ID1) & ~AR_STA_ID1_PRESERVE_SEQNUM); 1363250003Sadrian 1364250003Sadrian 1365250003Sadrian AH_PRIVATE(ah)->ah_wow_event_mask = wow_event_mask; 1366250003Sadrian 1367250003Sadrian#if ATH_WOW_OFFLOAD 1368250003Sadrian if (offloadEnable) { 1369250003Sadrian /* Force MAC awake before entering SW WoW mode */ 1370250003Sadrian OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 1371250003Sadrian#if ATH_SUPPORT_MCI 1372250003Sadrian if (AH_PRIVATE(ah)->ah_caps.hal_mci_support) { 1373250003Sadrian OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); 1374250003Sadrian } 1375250003Sadrian#endif 1376250003Sadrian 1377250003Sadrian OS_REG_WRITE(ah, AR_WOW_OFFLOAD_COMMAND_JUPITER, wow_feature_enable); 1378250003Sadrian OS_REG_WRITE(ah, AR_WOW_OFFLOAD_STATUS_JUPITER, 0x0); 1379250003Sadrian if (wow_feature_enable & AR_WOW_OFFLOAD_ENA_SW_NULL) { 1380250003Sadrian OS_REG_WRITE(ah, AR_WOW_SW_NULL_PARAMETER, 1381250003Sadrian ((1000) | 1382250003Sadrian (4 << AR_WOW_SW_NULL_SHORT_PERIOD_MASK_S))); 1383250003Sadrian } 1384250003Sadrian 1385250003Sadrian if (wow_feature_enable & AR_WOW_OFFLOAD_ENA_DEVID_SWAR) { 1386250003Sadrian ar9300_wowoffload_download_devid_swar(ah); 1387250003Sadrian } 1388250003Sadrian 1389250003Sadrian ar9300_wow_offload_download_hal_params(ah); 1390250003Sadrian ar9300_wow_offload_handshake(ah, pattern_enable); 1391250003Sadrian AH9300(ah)->ah_chip_full_sleep = AH_FALSE; 1392250003Sadrian 1393250003Sadrian //OS_REG_SET_BIT(ah, AR_SW_WOW_CONTROL, AR_HW_WOW_DISABLE); 1394250003Sadrian } 1395250003Sadrian else 1396250003Sadrian#endif /* ATH_WOW_OFFLOAD */ 1397250003Sadrian { 1398250003Sadrian#if ATH_SUPPORT_MCI 1399250003Sadrian if (AH_PRIVATE(ah)->ah_caps.hal_mci_support) { 1400250003Sadrian OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); 1401250003Sadrian } 1402250003Sadrian#endif 1403250003Sadrian ar9300_set_power_mode_wow_sleep(ah); 1404250003Sadrian AH9300(ah)->ah_chip_full_sleep = AH_TRUE; 1405250003Sadrian } 1406250003Sadrian 1407250003Sadrian return (AH_TRUE); 1408250003Sadrian} 1409250003Sadrian 1410250003Sadrianu_int32_t 1411250003Sadrian//ar9300_wow_wake_up(struct ath_hal *ah, u_int8_t *chipPatternBytes) 1412250003Sadrianar9300_wow_wake_up(struct ath_hal *ah, HAL_BOOL offloadEnabled) 1413250003Sadrian{ 1414250003Sadrian uint32_t wow_status = 0; 1415250003Sadrian uint32_t val = 0, rval; 1416250003Sadrian 1417250003Sadrian OS_REG_CLR_BIT(ah, AR_SW_WOW_CONTROL, AR_HW_WOW_DISABLE); 1418250003Sadrian OS_REG_CLR_BIT(ah, AR_SW_WOW_CONTROL, AR_SW_WOW_ENABLE); 1419250003Sadrian 1420250003Sadrian#if ATH_WOW_OFFLOAD 1421250003Sadrian /* If WoW was offloaded to embedded CPU, use the global 1422250003Sadrian * shared register to know the wakeup reason */ 1423250003Sadrian if (offloadEnabled) { 1424250003Sadrian val = OS_REG_READ(ah, AR_EMB_CPU_WOW_STATUS); 1425250003Sadrian if (val) { 1426250003Sadrian if (val & AR_EMB_CPU_WOW_STATUS_MAGIC_PATTERN) { 1427250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) SW MAGIC_PATTERN\n"); 1428250003Sadrian wow_status |= AH_WOW_MAGIC_PATTERN_EN; 1429250003Sadrian } 1430250003Sadrian if (val & AR_EMB_CPU_WOW_STATUS_PATTERN_MATCH) { 1431250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) SW USER_PATTERN\n"); 1432250003Sadrian wow_status |= AH_WOW_USER_PATTERN_EN; 1433250003Sadrian } 1434250003Sadrian if (val & AR_EMB_CPU_WOW_STATUS_KEEP_ALIVE_FAIL) { 1435250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) SW KEEP_ALIVE_FAIL\n"); 1436250003Sadrian wow_status |= AH_WOW_LINK_CHANGE; 1437250003Sadrian } 1438250003Sadrian if (val & AR_EMB_CPU_WOW_STATUS_BEACON_MISS) { 1439250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) SW BEACON_FAIL\n"); 1440250003Sadrian wow_status |= AH_WOW_BEACON_MISS; 1441250003Sadrian } 1442250003Sadrian } 1443250003Sadrian 1444250003Sadrian /* Clear status and mask registers */ 1445250003Sadrian OS_REG_WRITE(ah, AR_EMB_CPU_WOW_STATUS, 0x0); 1446250003Sadrian OS_REG_WRITE(ah, AR_EMB_CPU_WOW_ENABLE, 0); 1447250003Sadrian OS_REG_WRITE(ah, AR_MBOX_CTRL_STATUS, 0); 1448250003Sadrian 1449250003Sadrian } 1450250003Sadrian else 1451250003Sadrian#endif /* ATH_WOW_OFFLOAD */ 1452250003Sadrian { 1453250003Sadrian /* 1454250003Sadrian * Read the WOW Status register to know the wakeup reason. 1455250003Sadrian */ 1456250003Sadrian rval = OS_REG_READ(ah, AR_WOW_PATTERN_REG); 1457250003Sadrian val = AR_WOW_STATUS(rval); 1458250003Sadrian 1459250003Sadrian /* 1460250003Sadrian * Mask only the WOW events that we have enabled. 1461250003Sadrian * Sometimes we have spurious WOW events from the AR_WOW_PATTERN_REG 1462250003Sadrian * register. This mask will clean it up. 1463250003Sadrian */ 1464250003Sadrian val &= AH_PRIVATE(ah)->ah_wow_event_mask; 1465250003Sadrian 1466250003Sadrian if (val) { 1467250003Sadrian if (val & AR_WOW_MAGIC_PAT_FOUND) { 1468250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) HW MAGIC_PATTERN\n"); 1469250003Sadrian wow_status |= AH_WOW_MAGIC_PATTERN_EN; 1470250003Sadrian } 1471250003Sadrian if (AR_WOW_PATTERN_FOUND(val)) { 1472250003Sadrian //int i, offset; 1473250003Sadrian //offset = OS_REG_READ(ah, AR_WOW_RXBUF_START_ADDR); 1474250003Sadrian //// Read matched pattern for wake packet detection indication. 1475250003Sadrian //for( i = 0; i< MAX_PATTERN_SIZE/4; i+=4) 1476250003Sadrian //{ 1477250003Sadrian // // RX FIFO is only 8K wrapping. 1478250003Sadrian // if(offset >= 8 * 1024 / 4) offset = 0; 1479250003Sadrian // *(u_int32_t*)(chipPatternBytes + i) = OS_REG_READ( ah,offset ); 1480250003Sadrian // offset++; 1481250003Sadrian //} 1482250003Sadrian wow_status |= AH_WOW_USER_PATTERN_EN; 1483250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) HW USER_PATTERN\n"); 1484250003Sadrian } 1485250003Sadrian if (val & AR_WOW_KEEP_ALIVE_FAIL) { 1486250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) HW KEEP_ALIVE_FAIL\n"); 1487250003Sadrian wow_status |= AH_WOW_LINK_CHANGE; 1488250003Sadrian } 1489250003Sadrian if (val & AR_WOW_BEACON_FAIL) { 1490250003Sadrian HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "(WOW) HW BEACON_FAIL\n"); 1491250003Sadrian wow_status |= AH_WOW_BEACON_MISS; 1492250003Sadrian } 1493250003Sadrian } 1494250003Sadrian } 1495250003Sadrian 1496250003Sadrian /* 1497250003Sadrian * Set and clear WOW_PME_CLEAR registers for the chip to generate next 1498250003Sadrian * wow signal. 1499250003Sadrian * Disable D3 before accessing other registers ? 1500250003Sadrian */ 1501250003Sadrian val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL)); 1502250003Sadrian /* Check the bit value 0x01000000 (7-10)? */ 1503250003Sadrian val &= ~AR_PMCTRL_PWR_STATE_D1D3; 1504250003Sadrian val |= AR_PMCTRL_WOW_PME_CLR; 1505250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), val); 1506250003Sadrian 1507250003Sadrian /* 1508250003Sadrian * Clear all events. 1509250003Sadrian */ 1510250003Sadrian OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, 1511250003Sadrian AR_WOW_CLEAR_EVENTS(OS_REG_READ(ah, AR_WOW_PATTERN_REG))); 1512250003Sadrian 1513250003Sadrian //HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 1514250003Sadrian // "%s: Skip PCIE WA programming\n", __func__); 1515250003Sadrian#if 0 1516250003Sadrian /* 1517250003Sadrian * Tie reset register. 1518250003Sadrian * FIXME: Per David Quan not tieing it back might have some repurcussions. 1519250003Sadrian */ 1520250003Sadrian /* XXX */ 1521250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), OS_REG_READ(ah, AR_WA) | 1522250003Sadrian AR_WA_UNTIE_RESET_EN | AR_WA_POR_SHORT | AR_WA_RESET_EN); 1523250003Sadrian#endif 1524250003Sadrian 1525250003Sadrian /* Restore the Beacon Threshold to init value */ 1526250003Sadrian OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR); 1527250003Sadrian 1528250003Sadrian /* 1529250003Sadrian * Restore the way the PCI-E Reset, Power-On-Reset, external PCIE_POR_SHORT 1530250003Sadrian * pins are tied to its original value. Previously just before WOW sleep, 1531250003Sadrian * we untie the PCI-E Reset to our Chip's Power On Reset so that 1532250003Sadrian * any PCI-E reset from the bus will not reset our chip. 1533250003Sadrian */ 1534250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "%s: restore AR_WA\n", __func__); 1535250003Sadrian if (AH_PRIVATE(ah)->ah_is_pci_express == AH_TRUE) { 1536250003Sadrian ar9300_config_pci_power_save(ah, 0, 0); 1537250003Sadrian } 1538250003Sadrian 1539250003Sadrian AH_PRIVATE(ah)->ah_wow_event_mask = 0; 1540250003Sadrian HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, 1541250003Sadrian "(WOW) wow_status=%08x\n", wow_status); 1542250003Sadrian 1543250003Sadrian return (wow_status); 1544250003Sadrian} 1545250003Sadrian 1546250003Sadrianvoid 1547250003Sadrianar9300_wow_set_gpio_reset_low(struct ath_hal *ah) 1548250003Sadrian{ 1549250003Sadrian uint32_t val; 1550250003Sadrian 1551250003Sadrian val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT)); 1552250003Sadrian val |= (1 << (2 * 2)); 1553250003Sadrian OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT), val); 1554250003Sadrian val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT)); 1555250003Sadrian /* val = OS_REG_READ(ah,AR_GPIO_IN_OUT ); */ 1556250003Sadrian} 1557250003Sadrian#endif /* ATH_WOW */ 1558250003Sadrian 1559250003Sadrian#endif /* AH_SUPPORT_AR9300 */ 1560