1185377Ssam/* 2185377Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 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 * 17203156Srpaulo * $FreeBSD$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam 24185377Ssam#include "ar5416/ar5416.h" 25185377Ssam#include "ar5416/ar5416reg.h" 26185377Ssam 27185377Ssam/* 28185377Ssam * Notify Power Mgt is enabled in self-generated frames. 29185377Ssam * If requested, force chip awake. 30185377Ssam * 31185377Ssam * Returns A_OK if chip is awake or successfully forced awake. 32185377Ssam * 33185377Ssam * WARNING WARNING WARNING 34185377Ssam * There is a problem with the chip where sometimes it will not wake up. 35185377Ssam */ 36185377Ssamstatic HAL_BOOL 37185377Ssamar5416SetPowerModeAwake(struct ath_hal *ah, int setChip) 38185377Ssam{ 39185377Ssam#define POWER_UP_TIME 200000 40185377Ssam uint32_t val; 41185377Ssam int i = 0; 42185377Ssam 43185377Ssam if (setChip) { 44185377Ssam /* 45185377Ssam * Do a Power-On-Reset if OWL is shutdown 46185377Ssam * the NetBSD driver power-cycles the Cardbus slot 47185377Ssam * as part of the reset procedure. 48185377Ssam */ 49185377Ssam if ((OS_REG_READ(ah, AR_RTC_STATUS) 50185377Ssam & AR_RTC_PM_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { 51185377Ssam if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) 52185377Ssam goto bad; 53185377Ssam } 54185377Ssam 55221163Sadrian if (AR_SREV_HOWL(ah)) 56221163Sadrian OS_REG_SET_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); 57221163Sadrian 58185377Ssam OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 59221800Sadrian if (AR_SREV_HOWL(ah)) 60221800Sadrian OS_DELAY(10000); 61221800Sadrian else 62221800Sadrian OS_DELAY(50); /* Give chip the chance to awake */ 63185377Ssam 64185377Ssam for (i = POWER_UP_TIME / 50; i != 0; i--) { 65185377Ssam val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; 66185377Ssam if (val == AR_RTC_STATUS_ON) 67185377Ssam break; 68185377Ssam OS_DELAY(50); 69185377Ssam OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 70185377Ssam } 71185377Ssam bad: 72185377Ssam if (i == 0) { 73185377Ssam#ifdef AH_DEBUG 74185377Ssam ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", 75185377Ssam __func__, POWER_UP_TIME/1000); 76185377Ssam#endif 77185377Ssam return AH_FALSE; 78185377Ssam } 79185377Ssam } 80185377Ssam 81185377Ssam OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 82185377Ssam return AH_TRUE; 83185377Ssam#undef POWER_UP_TIME 84185377Ssam} 85185377Ssam 86185377Ssam/* 87185377Ssam * Notify Power Mgt is disabled in self-generated frames. 88185377Ssam * If requested, force chip to sleep. 89185377Ssam */ 90185377Ssamstatic void 91185377Ssamar5416SetPowerModeSleep(struct ath_hal *ah, int setChip) 92185377Ssam{ 93185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 94185377Ssam if (setChip) { 95185377Ssam /* Clear the RTC force wake bit to allow the mac to sleep */ 96185377Ssam OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 97221163Sadrian if (! AR_SREV_HOWL(ah)) 98221163Sadrian OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); 99185377Ssam /* Shutdown chip. Active low */ 100221800Sadrian if (! AR_SREV_OWL(ah)) 101221800Sadrian OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); 102185377Ssam } 103185377Ssam} 104185377Ssam 105185377Ssam/* 106185377Ssam * Notify Power Management is enabled in self-generating 107185377Ssam * fames. If request, set power mode of chip to 108185377Ssam * auto/normal. Duration in units of 128us (1/8 TU). 109185377Ssam */ 110185377Ssamstatic void 111185377Ssamar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) 112185377Ssam{ 113185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 114185377Ssam 115185377Ssam if (setChip) 116185377Ssam OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 117185377Ssam} 118185377Ssam 119185377Ssam/* 120185377Ssam * Set power mgt to the requested mode, and conditionally set 121185377Ssam * the chip as well 122185377Ssam */ 123185377SsamHAL_BOOL 124185377Ssamar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) 125185377Ssam{ 126185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 127185377Ssam#ifdef AH_DEBUG 128185377Ssam static const char* modes[] = { 129185377Ssam "AWAKE", 130185377Ssam "FULL-SLEEP", 131185377Ssam "NETWORK SLEEP", 132185377Ssam "UNDEFINED" 133185377Ssam }; 134185377Ssam#endif 135185377Ssam int status = AH_TRUE; 136185377Ssam if (!setChip) 137185377Ssam return AH_TRUE; 138185377Ssam 139185377Ssam HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, 140185377Ssam modes[ahp->ah_powerMode], modes[mode], setChip ? "set chip " : ""); 141185377Ssam switch (mode) { 142185377Ssam case HAL_PM_AWAKE: 143185377Ssam status = ar5416SetPowerModeAwake(ah, setChip); 144185377Ssam break; 145185377Ssam case HAL_PM_FULL_SLEEP: 146185377Ssam ar5416SetPowerModeSleep(ah, setChip); 147185377Ssam break; 148185377Ssam case HAL_PM_NETWORK_SLEEP: 149185377Ssam ar5416SetPowerModeNetworkSleep(ah, setChip); 150185377Ssam break; 151185377Ssam default: 152185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n", 153185377Ssam __func__, mode); 154185377Ssam return AH_FALSE; 155185377Ssam } 156185377Ssam ahp->ah_powerMode = mode; 157185377Ssam return status; 158185377Ssam} 159185377Ssam 160185377Ssam/* 161185377Ssam * Return the current sleep mode of the chip 162185377Ssam */ 163185377SsamHAL_POWER_MODE 164185377Ssamar5416GetPowerMode(struct ath_hal *ah) 165185377Ssam{ 166185377Ssam int mode = OS_REG_READ(ah, AR_RTC_STATUS); 167185377Ssam switch (mode & AR_RTC_PM_STATUS_M) { 168185377Ssam case AR_RTC_STATUS_ON: 169185377Ssam case AR_RTC_STATUS_WAKEUP: 170185377Ssam return HAL_PM_AWAKE; 171185377Ssam case AR_RTC_STATUS_SLEEP: 172185377Ssam return HAL_PM_NETWORK_SLEEP; 173185377Ssam case AR_RTC_STATUS_SHUTDOWN: 174185377Ssam return HAL_PM_FULL_SLEEP; 175185377Ssam default: 176185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 177185377Ssam "%s: unknown power mode, RTC_STATUS 0x%x\n", 178185377Ssam __func__, mode); 179185377Ssam return HAL_PM_UNDEFINED; 180185377Ssam } 181185377Ssam} 182