Path: blob/main/sys/dev/ath/ath_hal/ar5416/ar5416_power.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"2223#include "ar5416/ar5416.h"24#include "ar5416/ar5416reg.h"2526/*27* Notify Power Mgt is enabled in self-generated frames.28* If requested, force chip awake.29*30* Returns A_OK if chip is awake or successfully forced awake.31*32* WARNING WARNING WARNING33* There is a problem with the chip where sometimes it will not wake up.34*/35static HAL_BOOL36ar5416SetPowerModeAwake(struct ath_hal *ah, int setChip)37{38#define POWER_UP_TIME 20000039uint32_t val;40int i = 0;4142if (setChip) {43/*44* Do a Power-On-Reset if OWL is shutdown45* the NetBSD driver power-cycles the Cardbus slot46* as part of the reset procedure.47*/48if ((OS_REG_READ(ah, AR_RTC_STATUS)49& AR_RTC_PM_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {50if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))51goto bad;52AH5416(ah)->ah_initPLL(ah, AH_NULL);53}5455if (AR_SREV_HOWL(ah))56OS_REG_SET_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);5758OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);59if (AR_SREV_HOWL(ah))60OS_DELAY(10000);61else62OS_DELAY(50); /* Give chip the chance to awake */6364for (i = POWER_UP_TIME / 50; i != 0; i--) {65val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;66if (val == AR_RTC_STATUS_ON)67break;68OS_DELAY(50);69OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);70}71bad:72if (i == 0) {73#ifdef AH_DEBUG74ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n",75__func__, POWER_UP_TIME/1000);76#endif77return AH_FALSE;78}79}8081OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);82return AH_TRUE;83#undef POWER_UP_TIME84}8586/*87* Notify Power Mgt is disabled in self-generated frames.88* If requested, force chip to sleep.89*/90static void91ar5416SetPowerModeSleep(struct ath_hal *ah, int setChip)92{93OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);94if (setChip) {95/* Clear the RTC force wake bit to allow the mac to sleep */96OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);97if (! AR_SREV_HOWL(ah))98OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF);99/* Shutdown chip. Active low */100if (! AR_SREV_OWL(ah))101OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);102}103}104105/*106* Notify Power Management is enabled in self-generating107* fames. If request, set power mode of chip to108* auto/normal. Duration in units of 128us (1/8 TU).109*/110static void111ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)112{113OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);114115if (setChip)116OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);117}118119/*120* Set power mgt to the requested mode, and conditionally set121* the chip as well122*/123HAL_BOOL124ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)125{126#ifdef AH_DEBUG127static const char* modes[] = {128"AWAKE",129"FULL-SLEEP",130"NETWORK SLEEP",131"UNDEFINED"132};133#endif134int status = AH_TRUE;135136#if 0137if (!setChip)138return AH_TRUE;139#endif140141HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,142modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : "");143switch (mode) {144case HAL_PM_AWAKE:145if (setChip)146ah->ah_powerMode = mode;147status = ar5416SetPowerModeAwake(ah, setChip);148break;149case HAL_PM_FULL_SLEEP:150ar5416SetPowerModeSleep(ah, setChip);151if (setChip)152ah->ah_powerMode = mode;153break;154case HAL_PM_NETWORK_SLEEP:155ar5416SetPowerModeNetworkSleep(ah, setChip);156if (setChip)157ah->ah_powerMode = mode;158break;159default:160HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n",161__func__, mode);162return AH_FALSE;163}164return status;165}166167/*168* Return the current sleep mode of the chip169*/170HAL_POWER_MODE171ar5416GetPowerMode(struct ath_hal *ah)172{173int mode = OS_REG_READ(ah, AR_RTC_STATUS);174switch (mode & AR_RTC_PM_STATUS_M) {175case AR_RTC_STATUS_ON:176case AR_RTC_STATUS_WAKEUP:177return HAL_PM_AWAKE;178case AR_RTC_STATUS_SLEEP:179return HAL_PM_NETWORK_SLEEP;180case AR_RTC_STATUS_SHUTDOWN:181return HAL_PM_FULL_SLEEP;182default:183HALDEBUG(ah, HAL_DEBUG_ANY,184"%s: unknown power mode, RTC_STATUS 0x%x\n",185__func__, mode);186return HAL_PM_UNDEFINED;187}188}189190191