1185377Ssam/* 2185377Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2006 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17204644Srpaulo * $FreeBSD$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam 24185377Ssam#include "ar5211/ar5211.h" 25185377Ssam#include "ar5211/ar5211reg.h" 26185377Ssam#include "ar5211/ar5211desc.h" 27185377Ssam 28185377Ssam/* 29185377Ssam * Notify Power Mgt is enabled in self-generated frames. 30185377Ssam * If requested, force chip awake. 31185377Ssam * 32185377Ssam * Returns A_OK if chip is awake or successfully forced awake. 33185377Ssam * 34185377Ssam * WARNING WARNING WARNING 35185377Ssam * There is a problem with the chip where sometimes it will not wake up. 36185377Ssam */ 37185377Ssamstatic HAL_BOOL 38185377Ssamar5211SetPowerModeAwake(struct ath_hal *ah, int setChip) 39185377Ssam{ 40185377Ssam#define POWER_UP_TIME 2000 41185377Ssam uint32_t val; 42185377Ssam int i; 43185377Ssam 44185377Ssam if (setChip) { 45185377Ssam OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE); 46185377Ssam OS_DELAY(10); /* Give chip the chance to awake */ 47185377Ssam 48185377Ssam for (i = POWER_UP_TIME / 200; i != 0; i--) { 49185377Ssam val = OS_REG_READ(ah, AR_PCICFG); 50185377Ssam if ((val & AR_PCICFG_SPWR_DN) == 0) 51185377Ssam break; 52185377Ssam OS_DELAY(200); 53185377Ssam OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, 54185377Ssam AR_SCR_SLE_WAKE); 55185377Ssam } 56185377Ssam if (i == 0) { 57185377Ssam#ifdef AH_DEBUG 58185377Ssam ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", 59185377Ssam __func__, POWER_UP_TIME/20); 60185377Ssam#endif 61185377Ssam return AH_FALSE; 62185377Ssam } 63185377Ssam } 64185377Ssam 65185377Ssam OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 66185377Ssam return AH_TRUE; 67185377Ssam#undef POWER_UP_TIME 68185377Ssam} 69185377Ssam 70185377Ssam/* 71185377Ssam * Notify Power Mgt is disabled in self-generated frames. 72185377Ssam * If requested, force chip to sleep. 73185377Ssam */ 74185377Ssamstatic void 75185377Ssamar5211SetPowerModeSleep(struct ath_hal *ah, int setChip) 76185377Ssam{ 77185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 78185377Ssam if (setChip) 79185377Ssam OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP); 80185377Ssam} 81185377Ssam 82185377Ssam/* 83185377Ssam * Notify Power Management is enabled in self-generating 84185377Ssam * fames. If request, set power mode of chip to 85185377Ssam * auto/normal. Duration in units of 128us (1/8 TU). 86185377Ssam */ 87185377Ssamstatic void 88185377Ssamar5211SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) 89185377Ssam{ 90185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 91185377Ssam if (setChip) 92185377Ssam OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_NORM); 93185377Ssam} 94185377Ssam 95185377SsamHAL_BOOL 96185377Ssamar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) 97185377Ssam{ 98185377Ssam struct ath_hal_5211 *ahp = AH5211(ah); 99185377Ssam#ifdef AH_DEBUG 100185377Ssam static const char* modes[] = { 101185377Ssam "AWAKE", 102185377Ssam "FULL-SLEEP", 103185377Ssam "NETWORK SLEEP", 104185377Ssam "UNDEFINED" 105185377Ssam }; 106185377Ssam#endif 107185377Ssam int status = AH_TRUE; 108185377Ssam 109185377Ssam HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, 110185377Ssam modes[ahp->ah_powerMode], modes[mode], 111185377Ssam setChip ? "set chip " : ""); 112185377Ssam switch (mode) { 113185377Ssam case HAL_PM_AWAKE: 114185377Ssam status = ar5211SetPowerModeAwake(ah, setChip); 115185377Ssam break; 116185377Ssam case HAL_PM_FULL_SLEEP: 117185377Ssam ar5211SetPowerModeSleep(ah, setChip); 118185377Ssam break; 119185377Ssam case HAL_PM_NETWORK_SLEEP: 120185377Ssam ar5211SetPowerModeNetworkSleep(ah, setChip); 121185377Ssam break; 122185377Ssam default: 123185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", 124185377Ssam __func__, mode); 125185377Ssam return AH_FALSE; 126185377Ssam } 127185377Ssam ahp->ah_powerMode = mode; 128185377Ssam return status; 129185377Ssam} 130185377Ssam 131185377SsamHAL_POWER_MODE 132185377Ssamar5211GetPowerMode(struct ath_hal *ah) 133185377Ssam{ 134185377Ssam /* Just so happens the h/w maps directly to the abstracted value */ 135185377Ssam return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE); 136185377Ssam} 137