Path: blob/main/sys/dev/ath/ath_hal/ar5212/ar5212_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 "ar5212/ar5212.h"24#include "ar5212/ar5212reg.h"25#include "ar5212/ar5212desc.h"2627/*28* Notify Power Mgt is enabled in self-generated frames.29* If requested, force chip awake.30*31* Returns A_OK if chip is awake or successfully forced awake.32*33* WARNING WARNING WARNING34* There is a problem with the chip where sometimes it will not wake up.35*/36static HAL_BOOL37ar5212SetPowerModeAwake(struct ath_hal *ah, int setChip)38{39#define AR_SCR_MASK \40(AR_SCR_SLDUR|AR_SCR_SLE|AR_SCR_SLDTP|AR_SCR_SLDWP|\41AR_SCR_SLEPOL|AR_SCR_MIBIE|AR_SCR_UNKNOWN)42#define POWER_UP_TIME 200043uint32_t scr, val;44int i;4546if (setChip) {47/*48* Be careful setting the AWAKE mode. When we are called49* with the chip powered down the read returns 0xffffffff50* which when blindly written back with OS_REG_RMW_FIELD51* enables the MIB interrupt for the sleep performance52* counters. This can result in an interrupt storm when53* ANI is in operation as no one knows to turn off the MIB54* interrupt cause.55*/56scr = OS_REG_READ(ah, AR_SCR);57if (scr & ~AR_SCR_MASK) {58HALDEBUG(ah, HAL_DEBUG_ANY,59"%s: bogus SCR 0x%x, PCICFG 0x%x\n",60__func__, scr, OS_REG_READ(ah, AR_PCICFG));61scr = 0;62}63scr = (scr &~ AR_SCR_SLE) | AR_SCR_SLE_WAKE;64OS_REG_WRITE(ah, AR_SCR, scr);65OS_DELAY(10); /* Give chip the chance to awake */6667for (i = POWER_UP_TIME / 50; i != 0; i--) {68val = OS_REG_READ(ah, AR_PCICFG);69if ((val & AR_PCICFG_SPWR_DN) == 0)70break;71OS_DELAY(50);72OS_REG_WRITE(ah, AR_SCR, scr);73}74if (i == 0) {75#ifdef AH_DEBUG76ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n",77__func__, POWER_UP_TIME/50);78#endif79return AH_FALSE;80}81}8283OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);84return AH_TRUE;85#undef POWER_UP_TIME86#undef AR_SCR_MASK87}8889/*90* Notify Power Mgt is disabled in self-generated frames.91* If requested, force chip to sleep.92*/93static void94ar5212SetPowerModeSleep(struct ath_hal *ah, int setChip)95{96OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);97if (setChip)98OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP);99}100101/*102* Notify Power Management is enabled in self-generating103* fames. If request, set power mode of chip to104* auto/normal. Duration in units of 128us (1/8 TU).105*/106static void107ar5212SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)108{109OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);110if (setChip)111OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_NORM);112}113114/*115* Set power mgt to the requested mode, and conditionally set116* the chip as well117*/118HAL_BOOL119ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)120{121#ifdef AH_DEBUG122static const char* modes[] = {123"AWAKE",124"FULL-SLEEP",125"NETWORK SLEEP",126"UNDEFINED"127};128#endif129int status = AH_TRUE;130131HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,132modes[ah->ah_powerMode], modes[mode],133setChip ? "set chip " : "");134switch (mode) {135case HAL_PM_AWAKE:136if (setChip)137ah->ah_powerMode = mode;138status = ar5212SetPowerModeAwake(ah, setChip);139break;140case HAL_PM_FULL_SLEEP:141ar5212SetPowerModeSleep(ah, setChip);142if (setChip)143ah->ah_powerMode = mode;144break;145case HAL_PM_NETWORK_SLEEP:146ar5212SetPowerModeNetworkSleep(ah, setChip);147if (setChip)148ah->ah_powerMode = mode;149break;150default:151HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n",152__func__, mode);153return AH_FALSE;154}155return status;156}157158/*159* Return the current sleep mode of the chip160*/161HAL_POWER_MODE162ar5212GetPowerMode(struct ath_hal *ah)163{164/* Just so happens the h/w maps directly to the abstracted value */165return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE);166}167168#if 0169/*170* Return the current sleep state of the chip171* TRUE = sleeping172*/173HAL_BOOL174ar5212GetPowerStatus(struct ath_hal *ah)175{176return (OS_REG_READ(ah, AR_PCICFG) & AR_PCICFG_SPWR_DN) != 0;177}178#endif179180181