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