1 /*- 2 * SPDX-License-Identifier: ISC 3 * 4 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 5 * Copyright (c) 2002-2004 Atheros Communications, Inc. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #include "opt_ah.h" 20 21 #include "ah.h" 22 #include "ah_internal.h" 23 24 #include "ar5210/ar5210.h" 25 #include "ar5210/ar5210reg.h" 26 27 /* 28 * Notify Power Mgt is disabled in self-generated frames. 29 * If requested, set Power Mode of chip to auto/normal. 30 */ 31 static void 32 ar5210SetPowerModeAuto(struct ath_hal *ah, int setChip) 33 { 34 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV); 35 if (setChip) 36 OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_ALLOW); 37 } 38 39 /* 40 * Notify Power Mgt is enabled in self-generated frames. 41 * If requested, force chip awake. 42 * 43 * Returns A_OK if chip is awake or successfully forced awake. 44 * 45 * WARNING WARNING WARNING 46 * There is a problem with the chip where sometimes it will not wake up. 47 */ 48 static HAL_BOOL 49 ar5210SetPowerModeAwake(struct ath_hal *ah, int setChip) 50 { 51 #define POWER_UP_TIME 2000 52 uint32_t val; 53 int i; 54 55 if (setChip) { 56 OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE); 57 OS_DELAY(2000); /* Give chip the chance to awake */ 58 59 for (i = POWER_UP_TIME / 200; i != 0; i--) { 60 val = OS_REG_READ(ah, AR_PCICFG); 61 if ((val & AR_PCICFG_SPWR_DN) == 0) 62 break; 63 OS_DELAY(200); 64 OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, 65 AR_SCR_SLE_WAKE); 66 } 67 if (i == 0) { 68 #ifdef AH_DEBUG 69 ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", 70 __func__, POWER_UP_TIME/20); 71 #endif 72 return AH_FALSE; 73 } 74 } 75 76 OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV); 77 return AH_TRUE; 78 #undef POWER_UP_TIME 79 } 80 81 /* 82 * Notify Power Mgt is disabled in self-generated frames. 83 * If requested, force chip to sleep. 84 */ 85 static void 86 ar5210SetPowerModeSleep(struct ath_hal *ah, int setChip) 87 { 88 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV); 89 if (setChip) 90 OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP); 91 } 92 93 HAL_BOOL 94 ar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) 95 { 96 #ifdef AH_DEBUG 97 static const char* modes[] = { 98 "AWAKE", 99 "FULL-SLEEP", 100 "NETWORK SLEEP", 101 "UNDEFINED" 102 }; 103 #endif 104 int status = AH_TRUE; 105 106 HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, 107 modes[ah->ah_powerMode], modes[mode], 108 setChip ? "set chip " : ""); 109 switch (mode) { 110 case HAL_PM_AWAKE: 111 if (setChip) 112 ah->ah_powerMode = mode; 113 status = ar5210SetPowerModeAwake(ah, setChip); 114 break; 115 case HAL_PM_FULL_SLEEP: 116 ar5210SetPowerModeSleep(ah, setChip); 117 if (setChip) 118 ah->ah_powerMode = mode; 119 break; 120 case HAL_PM_NETWORK_SLEEP: 121 ar5210SetPowerModeAuto(ah, setChip); 122 if (setChip) 123 ah->ah_powerMode = mode; 124 break; 125 default: 126 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", 127 __func__, mode); 128 return AH_FALSE; 129 } 130 return status; 131 } 132 133 HAL_POWER_MODE 134 ar5210GetPowerMode(struct ath_hal *ah) 135 { 136 /* Just so happens the h/w maps directly to the abstracted value */ 137 return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE); 138 } 139