1#include "headers.h"
2
3/*
4Function:	InterfaceIdleModeWakeup
5
6Description:	This is the hardware specific Function for
7		waking up HW device from Idle mode.
8		A software abort pattern is written to the
9		device to wake it and necessary power state
10		transitions from host are performed here.
11
12Input parameters: IN struct bcm_mini_adapter *Adapter
13		  - Miniport Adapter Context
14
15Return:		BCM_STATUS_SUCCESS - If Wakeup of the HW Interface
16				     was successful.
17		Other              - If an error occurred.
18*/
19
20/*
21Function:	InterfaceIdleModeRespond
22
23Description:	This is the hardware specific Function for
24		responding to Idle mode request from target.
25		Necessary power state transitions from host for
26		idle mode or other device specific initializations
27		are performed here.
28
29Input parameters: IN struct bcm_mini_adapter * Adapter
30		  - Miniport Adapter Context
31
32Return:		BCM_STATUS_SUCCESS - If Idle mode response related
33				     HW configuration was successful.
34		Other              - If an error occurred.
35*/
36
37/*
38"dmem bfc02f00  100" tells how many time device went in Idle mode.
39this value will be at address bfc02fa4.just before value d0ea1dle.
40
41Set time value by writing at bfc02f98 7d0
42
43checking the Ack timer expire on kannon by running command
44d qcslog .. if it shows e means host has not send response
45to f/w with in 200 ms. Response should be
46send to f/w with in 200 ms after the Idle/Shutdown req issued
47
48*/
49
50
51int InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter,
52			unsigned int *puiBuffer)
53{
54	int	status = STATUS_SUCCESS;
55	unsigned int	uiRegRead = 0;
56	int bytes;
57
58	if (ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD) {
59		if (ntohl(*(puiBuffer+1)) == 0) {
60
61			status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
62					&uiRegRead, sizeof(uiRegRead));
63			if (status)
64				return status;
65
66			if (Adapter->ulPowerSaveMode ==
67				DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
68				uiRegRead = 0x00000000;
69				status = wrmalt(Adapter,
70					DEBUG_INTERRUPT_GENERATOR_REGISTOR,
71					&uiRegRead, sizeof(uiRegRead));
72				if (status)
73					return status;
74			}
75			/* Below Register should not br read in case of
76			 * Manual and Protocol Idle mode */
77			else if (Adapter->ulPowerSaveMode !=
78				DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) {
79				/* clear on read Register */
80				bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0,
81					&uiRegRead, sizeof(uiRegRead));
82				if (bytes < 0) {
83					status = bytes;
84					return status;
85				}
86				/* clear on read Register */
87				bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1,
88					&uiRegRead, sizeof(uiRegRead));
89				if (bytes < 0) {
90					status = bytes;
91					return status;
92				}
93			}
94
95			/* Set Idle Mode Flag to False and
96			 * Clear IdleMode reg. */
97			Adapter->IdleMode = false;
98			Adapter->bTriedToWakeUpFromlowPowerMode = false;
99
100			wake_up(&Adapter->lowpower_mode_wait_queue);
101
102		} else {
103			if (TRUE == Adapter->IdleMode)
104				return status;
105
106			uiRegRead = 0;
107
108			if (Adapter->chip_id == BCS220_2 ||
109				Adapter->chip_id == BCS220_2BC ||
110					Adapter->chip_id == BCS250_BC ||
111					Adapter->chip_id == BCS220_3) {
112
113				bytes = rdmalt(Adapter, HPM_CONFIG_MSW,
114					&uiRegRead, sizeof(uiRegRead));
115				if (bytes < 0) {
116					status = bytes;
117					return status;
118				}
119
120
121				uiRegRead |= (1<<17);
122
123				status = wrmalt(Adapter, HPM_CONFIG_MSW,
124					&uiRegRead, sizeof(uiRegRead));
125				if (status)
126					return status;
127			}
128			SendIdleModeResponse(Adapter);
129		}
130	} else if (ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG) {
131		OverrideServiceFlowParams(Adapter, puiBuffer);
132	}
133	return status;
134}
135
136static int InterfaceAbortIdlemode(struct bcm_mini_adapter *Adapter,
137				unsigned int Pattern)
138{
139	int status = STATUS_SUCCESS;
140	unsigned int value;
141	unsigned int chip_id;
142	unsigned long timeout = 0, itr = 0;
143
144	int lenwritten = 0;
145	unsigned char aucAbortPattern[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
146						0xFF, 0xFF, 0xFF};
147	struct bcm_interface_adapter *psInterfaceAdapter =
148				Adapter->pvInterfaceAdapter;
149
150	/* Abort Bus suspend if its already suspended */
151	if ((TRUE == psInterfaceAdapter->bSuspended) &&
152			(TRUE == Adapter->bDoSuspend))
153		status = usb_autopm_get_interface(
154				psInterfaceAdapter->interface);
155
156	if ((Adapter->ulPowerSaveMode ==
157			DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) ||
158	   (Adapter->ulPowerSaveMode ==
159			DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)) {
160		/* write the SW abort pattern. */
161		status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
162				&Pattern, sizeof(Pattern));
163		if (status)
164			return status;
165	}
166
167	if (Adapter->ulPowerSaveMode ==
168		DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
169		value = 0x80000000;
170		status = wrmalt(Adapter,
171				DEBUG_INTERRUPT_GENERATOR_REGISTOR,
172				&value, sizeof(value));
173		if (status)
174			return status;
175	} else if (Adapter->ulPowerSaveMode !=
176			DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) {
177		/*
178		 * Get a Interrupt Out URB and send 8 Bytes Down
179		 * To be Done in Thread Context.
180		 * Not using Asynchronous Mechanism.
181		 */
182		status = usb_interrupt_msg(psInterfaceAdapter->udev,
183			usb_sndintpipe(psInterfaceAdapter->udev,
184			psInterfaceAdapter->sIntrOut.int_out_endpointAddr),
185			aucAbortPattern,
186			8,
187			&lenwritten,
188			5000);
189		if (status)
190			return status;
191
192		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
193				IDLE_MODE, DBG_LVL_ALL,
194				"NOB Sent down :%d", lenwritten);
195
196		/* mdelay(25); */
197
198		timeout = jiffies +  msecs_to_jiffies(50);
199		while (time_after(timeout, jiffies)) {
200			itr++;
201			rdmalt(Adapter, CHIP_ID_REG, &chip_id, sizeof(UINT));
202			if (0xbece3200 == (chip_id&~(0xF0)))
203				chip_id = chip_id&~(0xF0);
204			if (chip_id == Adapter->chip_id)
205				break;
206		}
207		if (time_before(timeout, jiffies))
208			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
209				IDLE_MODE, DBG_LVL_ALL,
210				"Not able to read chip-id even after 25 msec");
211		else
212			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
213				IDLE_MODE, DBG_LVL_ALL,
214				"Number of completed iteration to read chip-id :%lu", itr);
215
216		status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
217				&Pattern, sizeof(status));
218		if (status)
219			return status;
220	}
221	return status;
222}
223int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter)
224{
225	if (Adapter->bTriedToWakeUpFromlowPowerMode) {
226		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
227		IDLE_MODE, DBG_LVL_ALL,
228		"Wake up already attempted.. ignoring\n");
229	} else {
230		Adapter->bTriedToWakeUpFromlowPowerMode = TRUE;
231		InterfaceAbortIdlemode(Adapter, Adapter->usIdleModePattern);
232
233	}
234	return 0;
235}
236
237void InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter)
238{
239	unsigned int uiRegVal = 0;
240	INT Status = 0;
241	int bytes;
242
243	if (Adapter->ulPowerSaveMode ==
244		DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
245		/* clear idlemode interrupt. */
246		uiRegVal = 0;
247		Status = wrmalt(Adapter,
248			DEBUG_INTERRUPT_GENERATOR_REGISTOR,
249			&uiRegVal, sizeof(uiRegVal));
250		if (Status)
251			return;
252	}
253
254	else {
255
256/* clear Interrupt EP registers. */
257		bytes = rdmalt(Adapter,
258			DEVICE_INT_OUT_EP_REG0,
259			&uiRegVal, sizeof(uiRegVal));
260		if (bytes < 0) {
261			Status = bytes;
262			return;
263		}
264
265		bytes = rdmalt(Adapter,
266			DEVICE_INT_OUT_EP_REG1,
267			&uiRegVal, sizeof(uiRegVal));
268		if (bytes < 0) {
269			Status = bytes;
270			return;
271		}
272	}
273}
274
275