1 1.1 alc /* 2 1.1 alc * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 1.1 alc * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 1.1 alc * 5 1.1 alc * Permission to use, copy, modify, and/or distribute this software for any 6 1.1 alc * purpose with or without fee is hereby granted, provided that the above 7 1.1 alc * copyright notice and this permission notice appear in all copies. 8 1.1 alc * 9 1.1 alc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 1.1 alc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 1.1 alc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 1.1 alc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 1.1 alc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 1.1 alc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 1.1 alc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 1.1 alc * 17 1.2 cegger * $Id: ar5212_power.c,v 1.2 2011/03/07 11:25:43 cegger Exp $ 18 1.1 alc */ 19 1.1 alc #include "opt_ah.h" 20 1.1 alc 21 1.1 alc #include "ah.h" 22 1.1 alc #include "ah_internal.h" 23 1.1 alc 24 1.1 alc #include "ar5212/ar5212.h" 25 1.1 alc #include "ar5212/ar5212reg.h" 26 1.1 alc #include "ar5212/ar5212desc.h" 27 1.1 alc 28 1.1 alc /* 29 1.1 alc * Notify Power Mgt is enabled in self-generated frames. 30 1.1 alc * If requested, force chip awake. 31 1.1 alc * 32 1.1 alc * Returns A_OK if chip is awake or successfully forced awake. 33 1.1 alc * 34 1.1 alc * WARNING WARNING WARNING 35 1.1 alc * There is a problem with the chip where sometimes it will not wake up. 36 1.1 alc */ 37 1.1 alc static HAL_BOOL 38 1.1 alc ar5212SetPowerModeAwake(struct ath_hal *ah, int setChip) 39 1.1 alc { 40 1.1 alc #define AR_SCR_MASK \ 41 1.1 alc (AR_SCR_SLDUR|AR_SCR_SLE|AR_SCR_SLE|AR_SCR_SLDTP|AR_SCR_SLDWP|\ 42 1.2 cegger AR_SCR_SLEPOL|AR_SCR_MIBIE|AR_SCR_UNKNOWN) 43 1.1 alc #define POWER_UP_TIME 2000 44 1.1 alc uint32_t scr, val; 45 1.1 alc int i; 46 1.1 alc 47 1.1 alc if (setChip) { 48 1.1 alc /* 49 1.1 alc * Be careful setting the AWAKE mode. When we are called 50 1.1 alc * with the chip powered down the read returns 0xffffffff 51 1.1 alc * which when blindly written back with OS_REG_RMW_FIELD 52 1.1 alc * enables the MIB interrupt for the sleep performance 53 1.1 alc * counters. This can result in an interrupt storm when 54 1.1 alc * ANI is in operation as noone knows to turn off the MIB 55 1.1 alc * interrupt cause. 56 1.1 alc */ 57 1.1 alc scr = OS_REG_READ(ah, AR_SCR); 58 1.1 alc if (scr & ~AR_SCR_MASK) { 59 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, 60 1.1 alc "%s: bogus SCR 0x%x, PCICFG 0x%x\n", 61 1.1 alc __func__, scr, OS_REG_READ(ah, AR_PCICFG)); 62 1.1 alc scr = 0; 63 1.1 alc } 64 1.1 alc scr = (scr &~ AR_SCR_SLE) | AR_SCR_SLE_WAKE; 65 1.1 alc OS_REG_WRITE(ah, AR_SCR, scr); 66 1.1 alc OS_DELAY(10); /* Give chip the chance to awake */ 67 1.1 alc 68 1.1 alc for (i = POWER_UP_TIME / 50; i != 0; i--) { 69 1.1 alc val = OS_REG_READ(ah, AR_PCICFG); 70 1.1 alc if ((val & AR_PCICFG_SPWR_DN) == 0) 71 1.1 alc break; 72 1.1 alc OS_DELAY(50); 73 1.1 alc OS_REG_WRITE(ah, AR_SCR, scr); 74 1.1 alc } 75 1.1 alc if (i == 0) { 76 1.1 alc #ifdef AH_DEBUG 77 1.1 alc ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", 78 1.1 alc __func__, POWER_UP_TIME/50); 79 1.1 alc #endif 80 1.1 alc return AH_FALSE; 81 1.1 alc } 82 1.1 alc } 83 1.1 alc 84 1.1 alc OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 85 1.1 alc return AH_TRUE; 86 1.1 alc #undef POWER_UP_TIME 87 1.1 alc #undef AR_SCR_MASK 88 1.1 alc } 89 1.1 alc 90 1.1 alc /* 91 1.1 alc * Notify Power Mgt is disabled in self-generated frames. 92 1.1 alc * If requested, force chip to sleep. 93 1.1 alc */ 94 1.1 alc static void 95 1.1 alc ar5212SetPowerModeSleep(struct ath_hal *ah, int setChip) 96 1.1 alc { 97 1.1 alc OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 98 1.1 alc if (setChip) 99 1.1 alc OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP); 100 1.1 alc } 101 1.1 alc 102 1.1 alc /* 103 1.1 alc * Notify Power Management is enabled in self-generating 104 1.1 alc * fames. If request, set power mode of chip to 105 1.1 alc * auto/normal. Duration in units of 128us (1/8 TU). 106 1.1 alc */ 107 1.1 alc static void 108 1.1 alc ar5212SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) 109 1.1 alc { 110 1.1 alc OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 111 1.1 alc if (setChip) 112 1.1 alc OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_NORM); 113 1.1 alc } 114 1.1 alc 115 1.1 alc /* 116 1.1 alc * Set power mgt to the requested mode, and conditionally set 117 1.1 alc * the chip as well 118 1.1 alc */ 119 1.1 alc HAL_BOOL 120 1.1 alc ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) 121 1.1 alc { 122 1.1 alc struct ath_hal_5212 *ahp = AH5212(ah); 123 1.1 alc #ifdef AH_DEBUG 124 1.1 alc static const char* modes[] = { 125 1.1 alc "AWAKE", 126 1.1 alc "FULL-SLEEP", 127 1.1 alc "NETWORK SLEEP", 128 1.1 alc "UNDEFINED" 129 1.1 alc }; 130 1.1 alc #endif 131 1.1 alc int status = AH_TRUE; 132 1.1 alc 133 1.1 alc HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, 134 1.1 alc modes[ahp->ah_powerMode], modes[mode], 135 1.1 alc setChip ? "set chip " : ""); 136 1.1 alc switch (mode) { 137 1.1 alc case HAL_PM_AWAKE: 138 1.1 alc status = ar5212SetPowerModeAwake(ah, setChip); 139 1.1 alc break; 140 1.1 alc case HAL_PM_FULL_SLEEP: 141 1.1 alc ar5212SetPowerModeSleep(ah, setChip); 142 1.1 alc break; 143 1.1 alc case HAL_PM_NETWORK_SLEEP: 144 1.1 alc ar5212SetPowerModeNetworkSleep(ah, setChip); 145 1.1 alc break; 146 1.1 alc default: 147 1.1 alc HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", 148 1.1 alc __func__, mode); 149 1.1 alc return AH_FALSE; 150 1.1 alc } 151 1.1 alc ahp->ah_powerMode = mode; 152 1.1 alc return status; 153 1.1 alc } 154 1.1 alc 155 1.1 alc /* 156 1.1 alc * Return the current sleep mode of the chip 157 1.1 alc */ 158 1.1 alc HAL_POWER_MODE 159 1.1 alc ar5212GetPowerMode(struct ath_hal *ah) 160 1.1 alc { 161 1.1 alc /* Just so happens the h/w maps directly to the abstracted value */ 162 1.1 alc return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE); 163 1.1 alc } 164 1.1 alc 165 1.1 alc #if 0 166 1.1 alc /* 167 1.1 alc * Return the current sleep state of the chip 168 1.1 alc * TRUE = sleeping 169 1.1 alc */ 170 1.1 alc HAL_BOOL 171 1.1 alc ar5212GetPowerStatus(struct ath_hal *ah) 172 1.1 alc { 173 1.1 alc return (OS_REG_READ(ah, AR_PCICFG) & AR_PCICFG_SPWR_DN) != 0; 174 1.1 alc } 175 1.1 alc #endif 176