1/*-
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
5 * Copyright (c) 2002-2008 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 * $FreeBSD: releng/12.0/sys/dev/ath/ath_hal/ar5416/ar5416_power.c 326695 2017-12-08 15:57:29Z pfg $
20 */
21#include "opt_ah.h"
22
23#include "ah.h"
24#include "ah_internal.h"
25
26#include "ar5416/ar5416.h"
27#include "ar5416/ar5416reg.h"
28
29/*
30 * Notify Power Mgt is enabled in self-generated frames.
31 * If requested, force chip awake.
32 *
33 * Returns A_OK if chip is awake or successfully forced awake.
34 *
35 * WARNING WARNING WARNING
36 * There is a problem with the chip where sometimes it will not wake up.
37 */
38static HAL_BOOL
39ar5416SetPowerModeAwake(struct ath_hal *ah, int setChip)
40{
41#define	POWER_UP_TIME	200000
42	uint32_t val;
43	int i = 0;
44
45	if (setChip) {
46		/*
47		 * Do a Power-On-Reset if OWL is shutdown
48		 * the NetBSD driver  power-cycles the Cardbus slot
49		 * as part of the reset procedure.
50		 */
51		if ((OS_REG_READ(ah, AR_RTC_STATUS)
52			& AR_RTC_PM_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
53			if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))
54				goto bad;
55			AH5416(ah)->ah_initPLL(ah, AH_NULL);
56		}
57
58		if (AR_SREV_HOWL(ah))
59			OS_REG_SET_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
60
61		OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
62		if (AR_SREV_HOWL(ah))
63			OS_DELAY(10000);
64		else
65			OS_DELAY(50);   /* Give chip the chance to awake */
66
67		for (i = POWER_UP_TIME / 50; i != 0; i--) {
68			val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
69			if (val == AR_RTC_STATUS_ON)
70				break;
71			OS_DELAY(50);
72			OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
73		}
74	bad:
75		if (i == 0) {
76#ifdef AH_DEBUG
77			ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n",
78				__func__, POWER_UP_TIME/1000);
79#endif
80			return AH_FALSE;
81		}
82	}
83
84	OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
85	return AH_TRUE;
86#undef POWER_UP_TIME
87}
88
89/*
90 * Notify Power Mgt is disabled in self-generated frames.
91 * If requested, force chip to sleep.
92 */
93static void
94ar5416SetPowerModeSleep(struct ath_hal *ah, int setChip)
95{
96	OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
97	if (setChip) {
98		/* Clear the RTC force wake bit to allow the mac to sleep */
99		OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
100		if (! AR_SREV_HOWL(ah))
101			OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF);
102		/* Shutdown chip. Active low */
103		if (! AR_SREV_OWL(ah))
104			OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
105	}
106}
107
108/*
109 * Notify Power Management is enabled in self-generating
110 * fames.  If request, set power mode of chip to
111 * auto/normal.  Duration in units of 128us (1/8 TU).
112 */
113static void
114ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)
115{
116	OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
117
118	if (setChip)
119		OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
120}
121
122/*
123 * Set power mgt to the requested mode, and conditionally set
124 * the chip as well
125 */
126HAL_BOOL
127ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
128{
129#ifdef AH_DEBUG
130	static const char* modes[] = {
131		"AWAKE",
132		"FULL-SLEEP",
133		"NETWORK SLEEP",
134		"UNDEFINED"
135	};
136#endif
137	int status = AH_TRUE;
138
139#if 0
140	if (!setChip)
141		return AH_TRUE;
142#endif
143
144	HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
145	    modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : "");
146	switch (mode) {
147	case HAL_PM_AWAKE:
148		if (setChip)
149			ah->ah_powerMode = mode;
150		status = ar5416SetPowerModeAwake(ah, setChip);
151		break;
152	case HAL_PM_FULL_SLEEP:
153		ar5416SetPowerModeSleep(ah, setChip);
154		if (setChip)
155			ah->ah_powerMode = mode;
156		break;
157	case HAL_PM_NETWORK_SLEEP:
158		ar5416SetPowerModeNetworkSleep(ah, setChip);
159		if (setChip)
160			ah->ah_powerMode = mode;
161		break;
162	default:
163		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n",
164		    __func__, mode);
165		return AH_FALSE;
166	}
167	return status;
168}
169
170/*
171 * Return the current sleep mode of the chip
172 */
173HAL_POWER_MODE
174ar5416GetPowerMode(struct ath_hal *ah)
175{
176	int mode = OS_REG_READ(ah, AR_RTC_STATUS);
177	switch (mode & AR_RTC_PM_STATUS_M) {
178	case AR_RTC_STATUS_ON:
179	case AR_RTC_STATUS_WAKEUP:
180		return HAL_PM_AWAKE;
181	case AR_RTC_STATUS_SLEEP:
182		return HAL_PM_NETWORK_SLEEP;
183	case AR_RTC_STATUS_SHUTDOWN:
184		return HAL_PM_FULL_SLEEP;
185	default:
186		HALDEBUG(ah, HAL_DEBUG_ANY,
187		    "%s: unknown power mode, RTC_STATUS 0x%x\n",
188		    __func__, mode);
189		return HAL_PM_UNDEFINED;
190	}
191}
192