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; 53234269Sadrian AH5416(ah)->ah_initPLL(ah, AH_NULL); 54185377Ssam } 55185377Ssam 56221163Sadrian if (AR_SREV_HOWL(ah)) 57221163Sadrian OS_REG_SET_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); 58221163Sadrian 59185377Ssam OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 60221800Sadrian if (AR_SREV_HOWL(ah)) 61221800Sadrian OS_DELAY(10000); 62221800Sadrian else 63221800Sadrian OS_DELAY(50); /* Give chip the chance to awake */ 64185377Ssam 65185377Ssam for (i = POWER_UP_TIME / 50; i != 0; i--) { 66185377Ssam val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; 67185377Ssam if (val == AR_RTC_STATUS_ON) 68185377Ssam break; 69185377Ssam OS_DELAY(50); 70185377Ssam OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 71185377Ssam } 72185377Ssam bad: 73185377Ssam if (i == 0) { 74185377Ssam#ifdef AH_DEBUG 75185377Ssam ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", 76185377Ssam __func__, POWER_UP_TIME/1000); 77185377Ssam#endif 78185377Ssam return AH_FALSE; 79185377Ssam } 80185377Ssam } 81185377Ssam 82185377Ssam OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 83185377Ssam return AH_TRUE; 84185377Ssam#undef POWER_UP_TIME 85185377Ssam} 86185377Ssam 87185377Ssam/* 88185377Ssam * Notify Power Mgt is disabled in self-generated frames. 89185377Ssam * If requested, force chip to sleep. 90185377Ssam */ 91185377Ssamstatic void 92185377Ssamar5416SetPowerModeSleep(struct ath_hal *ah, int setChip) 93185377Ssam{ 94185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 95185377Ssam if (setChip) { 96185377Ssam /* Clear the RTC force wake bit to allow the mac to sleep */ 97185377Ssam OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 98221163Sadrian if (! AR_SREV_HOWL(ah)) 99221163Sadrian OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); 100185377Ssam /* Shutdown chip. Active low */ 101221800Sadrian if (! AR_SREV_OWL(ah)) 102221800Sadrian OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); 103185377Ssam } 104185377Ssam} 105185377Ssam 106185377Ssam/* 107185377Ssam * Notify Power Management is enabled in self-generating 108185377Ssam * fames. If request, set power mode of chip to 109185377Ssam * auto/normal. Duration in units of 128us (1/8 TU). 110185377Ssam */ 111185377Ssamstatic void 112185377Ssamar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) 113185377Ssam{ 114185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 115185377Ssam 116185377Ssam if (setChip) 117185377Ssam OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 118185377Ssam} 119185377Ssam 120185377Ssam/* 121185377Ssam * Set power mgt to the requested mode, and conditionally set 122185377Ssam * the chip as well 123185377Ssam */ 124185377SsamHAL_BOOL 125185377Ssamar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) 126185377Ssam{ 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; 136265112Sadrian 137265112Sadrian#if 0 138185377Ssam if (!setChip) 139185377Ssam return AH_TRUE; 140265112Sadrian#endif 141185377Ssam 142185377Ssam HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, 143262969Sadrian modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : ""); 144185377Ssam switch (mode) { 145185377Ssam case HAL_PM_AWAKE: 146265112Sadrian if (setChip) 147265112Sadrian ah->ah_powerMode = mode; 148185377Ssam status = ar5416SetPowerModeAwake(ah, setChip); 149185377Ssam break; 150185377Ssam case HAL_PM_FULL_SLEEP: 151185377Ssam ar5416SetPowerModeSleep(ah, setChip); 152265112Sadrian if (setChip) 153265112Sadrian ah->ah_powerMode = mode; 154185377Ssam break; 155185377Ssam case HAL_PM_NETWORK_SLEEP: 156185377Ssam ar5416SetPowerModeNetworkSleep(ah, setChip); 157265112Sadrian if (setChip) 158265112Sadrian ah->ah_powerMode = mode; 159185377Ssam break; 160185377Ssam default: 161185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n", 162185377Ssam __func__, mode); 163185377Ssam return AH_FALSE; 164185377Ssam } 165185377Ssam return status; 166185377Ssam} 167185377Ssam 168185377Ssam/* 169185377Ssam * Return the current sleep mode of the chip 170185377Ssam */ 171185377SsamHAL_POWER_MODE 172185377Ssamar5416GetPowerMode(struct ath_hal *ah) 173185377Ssam{ 174185377Ssam int mode = OS_REG_READ(ah, AR_RTC_STATUS); 175185377Ssam switch (mode & AR_RTC_PM_STATUS_M) { 176185377Ssam case AR_RTC_STATUS_ON: 177185377Ssam case AR_RTC_STATUS_WAKEUP: 178185377Ssam return HAL_PM_AWAKE; 179185377Ssam case AR_RTC_STATUS_SLEEP: 180185377Ssam return HAL_PM_NETWORK_SLEEP; 181185377Ssam case AR_RTC_STATUS_SHUTDOWN: 182185377Ssam return HAL_PM_FULL_SLEEP; 183185377Ssam default: 184185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 185185377Ssam "%s: unknown power mode, RTC_STATUS 0x%x\n", 186185377Ssam __func__, mode); 187185377Ssam return HAL_PM_UNDEFINED; 188185377Ssam } 189185377Ssam} 190