1 
2 /******************************************************************************
3  *
4  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2004, R. Byron Moore
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 #include <acpi/acpi.h>
46 #include <acpi/acevents.h>
47 
48 #define _COMPONENT          ACPI_HARDWARE
49 	 ACPI_MODULE_NAME    ("hwgpe")
50 
51 
52 /******************************************************************************
53  *
54  * FUNCTION:    acpi_hw_enable_gpe
55  *
56  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be enabled
57  *
58  * RETURN:      Status
59  *
60  * DESCRIPTION: Enable a single GPE.
61  *
62  ******************************************************************************/
63 
64 acpi_status
acpi_hw_enable_gpe(struct acpi_gpe_event_info * gpe_event_info)65 acpi_hw_enable_gpe (
66 	struct acpi_gpe_event_info      *gpe_event_info)
67 {
68 	u32                             in_byte;
69 	acpi_status                     status;
70 
71 
72 	ACPI_FUNCTION_ENTRY ();
73 
74 
75 	/*
76 	 * Read the current value of the register, set the appropriate bit
77 	 * to enable the GPE, and write out the new register.
78 	 */
79 	status = acpi_hw_low_level_read (8, &in_byte,
80 			  &gpe_event_info->register_info->enable_address);
81 	if (ACPI_FAILURE (status)) {
82 		return (status);
83 	}
84 
85 	/* Write with the new GPE bit enabled */
86 
87 	status = acpi_hw_low_level_write (8, (in_byte | gpe_event_info->bit_mask),
88 			  &gpe_event_info->register_info->enable_address);
89 
90 	return (status);
91 }
92 
93 
94 /******************************************************************************
95  *
96  * FUNCTION:    acpi_hw_enable_gpe_for_wakeup
97  *
98  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be enabled
99  *
100  * RETURN:      None
101  *
102  * DESCRIPTION: Keep track of which GPEs the OS has requested not be
103  *              disabled when going to sleep.
104  *
105  ******************************************************************************/
106 
107 void
acpi_hw_enable_gpe_for_wakeup(struct acpi_gpe_event_info * gpe_event_info)108 acpi_hw_enable_gpe_for_wakeup (
109 	struct acpi_gpe_event_info      *gpe_event_info)
110 {
111 	struct acpi_gpe_register_info   *gpe_register_info;
112 
113 
114 	ACPI_FUNCTION_ENTRY ();
115 
116 
117 	/* Get the info block for the entire GPE register */
118 
119 	gpe_register_info = gpe_event_info->register_info;
120 	if (!gpe_register_info) {
121 		return;
122 	}
123 
124 	/*
125 	 * Set the bit so we will not enable this GPE when sleeping (and disable
126 	 * it upon wake)
127 	 */
128 	gpe_register_info->wake_enable |= gpe_event_info->bit_mask;
129 	gpe_event_info->flags |= (ACPI_GPE_TYPE_WAKE | ACPI_GPE_ENABLED);
130 }
131 
132 
133 /******************************************************************************
134  *
135  * FUNCTION:    acpi_hw_disable_gpe
136  *
137  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be disabled
138  *
139  * RETURN:      Status
140  *
141  * DESCRIPTION: Disable a single GPE.
142  *
143  ******************************************************************************/
144 
145 acpi_status
acpi_hw_disable_gpe(struct acpi_gpe_event_info * gpe_event_info)146 acpi_hw_disable_gpe (
147 	struct acpi_gpe_event_info      *gpe_event_info)
148 {
149 	u32                             in_byte;
150 	acpi_status                     status;
151 	struct acpi_gpe_register_info   *gpe_register_info;
152 
153 
154 	ACPI_FUNCTION_ENTRY ();
155 
156 
157 	/* Get the info block for the entire GPE register */
158 
159 	gpe_register_info = gpe_event_info->register_info;
160 	if (!gpe_register_info) {
161 		return (AE_BAD_PARAMETER);
162 	}
163 
164 	/*
165 	 * Read the current value of the register, clear the appropriate bit,
166 	 * and write out the new register value to disable the GPE.
167 	 */
168 	status = acpi_hw_low_level_read (8, &in_byte,
169 			  &gpe_register_info->enable_address);
170 	if (ACPI_FAILURE (status)) {
171 		return (status);
172 	}
173 
174 	/* Write the byte with this GPE bit cleared */
175 
176 	status = acpi_hw_low_level_write (8, (in_byte & ~(gpe_event_info->bit_mask)),
177 			  &gpe_register_info->enable_address);
178 	if (ACPI_FAILURE (status)) {
179 		return (status);
180 	}
181 
182 	/* Make sure this GPE is disabled for wake, also */
183 
184 	acpi_hw_disable_gpe_for_wakeup (gpe_event_info);
185 	return (AE_OK);
186 }
187 
188 
189 /******************************************************************************
190  *
191  * FUNCTION:    acpi_hw_disable_gpe_for_wakeup
192  *
193  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be disabled
194  *
195  * RETURN:      None
196  *
197  * DESCRIPTION: Keep track of which GPEs the OS has requested not be
198  *              disabled when going to sleep.
199  *
200  ******************************************************************************/
201 
202 void
acpi_hw_disable_gpe_for_wakeup(struct acpi_gpe_event_info * gpe_event_info)203 acpi_hw_disable_gpe_for_wakeup (
204 	struct acpi_gpe_event_info      *gpe_event_info)
205 {
206 	struct acpi_gpe_register_info   *gpe_register_info;
207 
208 
209 	ACPI_FUNCTION_ENTRY ();
210 
211 
212 	/* Get the info block for the entire GPE register */
213 
214 	gpe_register_info = gpe_event_info->register_info;
215 	if (!gpe_register_info) {
216 		return;
217 	}
218 
219 	/* Clear the bit so we will disable this when sleeping */
220 
221 	gpe_register_info->wake_enable &= ~(gpe_event_info->bit_mask);
222 }
223 
224 
225 /******************************************************************************
226  *
227  * FUNCTION:    acpi_hw_clear_gpe
228  *
229  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be cleared
230  *
231  * RETURN:      status_status
232  *
233  * DESCRIPTION: Clear the status bit for a single GPE.
234  *
235  ******************************************************************************/
236 
237 acpi_status
acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)238 acpi_hw_clear_gpe (
239 	struct acpi_gpe_event_info      *gpe_event_info)
240 {
241 	acpi_status                     status;
242 
243 
244 	ACPI_FUNCTION_ENTRY ();
245 
246 
247 	/*
248 	 * Write a one to the appropriate bit in the status register to
249 	 * clear this GPE.
250 	 */
251 	status = acpi_hw_low_level_write (8, gpe_event_info->bit_mask,
252 			  &gpe_event_info->register_info->status_address);
253 
254 	return (status);
255 }
256 
257 
258 /******************************************************************************
259  *
260  * FUNCTION:    acpi_hw_get_gpe_status
261  *
262  * PARAMETERS:  gpe_event_info      - Info block for the GPE to queried
263  *              event_status        - Where the GPE status is returned
264  *
265  * RETURN:      Status
266  *
267  * DESCRIPTION: Return the status of a single GPE.
268  *
269  ******************************************************************************/
270 
271 acpi_status
acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,acpi_event_status * event_status)272 acpi_hw_get_gpe_status (
273 	struct acpi_gpe_event_info      *gpe_event_info,
274 	acpi_event_status               *event_status)
275 {
276 	u32                             in_byte;
277 	u8                              bit_mask;
278 	struct acpi_gpe_register_info   *gpe_register_info;
279 	acpi_status                     status;
280 	acpi_event_status               local_event_status = 0;
281 
282 
283 	ACPI_FUNCTION_ENTRY ();
284 
285 
286 	if (!event_status) {
287 		return (AE_BAD_PARAMETER);
288 	}
289 
290 	/* Get the info block for the entire GPE register */
291 
292 	gpe_register_info = gpe_event_info->register_info;
293 
294 	/* Get the register bitmask for this GPE */
295 
296 	bit_mask = gpe_event_info->bit_mask;
297 
298 	/* GPE Enabled? */
299 
300 	status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->enable_address);
301 	if (ACPI_FAILURE (status)) {
302 		goto unlock_and_exit;
303 	}
304 
305 	if (bit_mask & in_byte) {
306 		local_event_status |= ACPI_EVENT_FLAG_ENABLED;
307 	}
308 
309 	/* GPE Enabled for wake? */
310 
311 	if (bit_mask & gpe_register_info->wake_enable) {
312 		local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED;
313 	}
314 
315 	/* GPE active (set)? */
316 
317 	status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->status_address);
318 	if (ACPI_FAILURE (status)) {
319 		goto unlock_and_exit;
320 	}
321 
322 	if (bit_mask & in_byte) {
323 		local_event_status |= ACPI_EVENT_FLAG_SET;
324 	}
325 
326 	/* Set return value */
327 
328 	(*event_status) = local_event_status;
329 
330 
331 unlock_and_exit:
332 	return (status);
333 }
334 
335 
336 /******************************************************************************
337  *
338  * FUNCTION:    acpi_hw_disable_gpe_block
339  *
340  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
341  *              gpe_block           - Gpe Block info
342  *
343  * RETURN:      Status
344  *
345  * DESCRIPTION: Disable all GPEs within a GPE block
346  *
347  ******************************************************************************/
348 
349 acpi_status
acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,struct acpi_gpe_block_info * gpe_block)350 acpi_hw_disable_gpe_block (
351 	struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
352 	struct acpi_gpe_block_info      *gpe_block)
353 {
354 	u32                             i;
355 	acpi_status                     status;
356 
357 
358 	/* Examine each GPE Register within the block */
359 
360 	for (i = 0; i < gpe_block->register_count; i++) {
361 		/* Disable all GPEs in this register */
362 
363 		status = acpi_hw_low_level_write (8, 0x00,
364 				 &gpe_block->register_info[i].enable_address);
365 		if (ACPI_FAILURE (status)) {
366 			return (status);
367 		}
368 	}
369 
370 	return (AE_OK);
371 }
372 
373 
374 /******************************************************************************
375  *
376  * FUNCTION:    acpi_hw_clear_gpe_block
377  *
378  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
379  *              gpe_block           - Gpe Block info
380  *
381  * RETURN:      Status
382  *
383  * DESCRIPTION: Clear status bits for all GPEs within a GPE block
384  *
385  ******************************************************************************/
386 
387 acpi_status
acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,struct acpi_gpe_block_info * gpe_block)388 acpi_hw_clear_gpe_block (
389 	struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
390 	struct acpi_gpe_block_info      *gpe_block)
391 {
392 	u32                             i;
393 	acpi_status                     status;
394 
395 
396 	/* Examine each GPE Register within the block */
397 
398 	for (i = 0; i < gpe_block->register_count; i++) {
399 		/* Clear status on all GPEs in this register */
400 
401 		status = acpi_hw_low_level_write (8, 0xFF,
402 				 &gpe_block->register_info[i].status_address);
403 		if (ACPI_FAILURE (status)) {
404 			return (status);
405 		}
406 	}
407 
408 	return (AE_OK);
409 }
410 
411 
412 /******************************************************************************
413  *
414  * FUNCTION:    acpi_hw_prepare_gpe_block_for_sleep
415  *
416  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
417  *              gpe_block           - Gpe Block info
418  *
419  * RETURN:      Status
420  *
421  * DESCRIPTION: Disable all runtime GPEs and enable all wakeup GPEs -- within
422  *              a single GPE block
423  *
424  ******************************************************************************/
425 
426 static acpi_status
acpi_hw_prepare_gpe_block_for_sleep(struct acpi_gpe_xrupt_info * gpe_xrupt_info,struct acpi_gpe_block_info * gpe_block)427 acpi_hw_prepare_gpe_block_for_sleep (
428 	struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
429 	struct acpi_gpe_block_info      *gpe_block)
430 {
431 	u32                             i;
432 	struct acpi_gpe_register_info   *gpe_register_info;
433 	u32                             in_value;
434 	acpi_status                     status;
435 
436 
437 	/* Get the register info for the entire GPE block */
438 
439 	gpe_register_info = gpe_block->register_info;
440 
441 	/* Examine each GPE Register within the block */
442 
443 	for (i = 0; i < gpe_block->register_count; i++) {
444 		/*
445 		 * Read the enabled/disabled status of all GPEs. We
446 		 * will be using it to restore all the GPEs later.
447 		 *
448 		 * NOTE:  Wake GPEs are are ALL disabled at this time, so when we wake
449 		 * and restore this register, they will be automatically disabled.
450 		 */
451 		status = acpi_hw_low_level_read (8, &in_value,
452 				 &gpe_register_info->enable_address);
453 		if (ACPI_FAILURE (status)) {
454 			return (status);
455 		}
456 
457 		gpe_register_info->enable = (u8) in_value;
458 
459 		/*
460 		 * 1) Disable all runtime GPEs
461 		 * 2) Enable all wakeup GPEs
462 		 */
463 		status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable,
464 				&gpe_register_info->enable_address);
465 		if (ACPI_FAILURE (status)) {
466 			return (status);
467 		}
468 
469 		/* Point to next GPE register */
470 
471 		gpe_register_info++;
472 	}
473 
474 	return (AE_OK);
475 }
476 
477 
478 /******************************************************************************
479  *
480  * FUNCTION:    acpi_hw_prepare_gpes_for_sleep
481  *
482  * PARAMETERS:  None
483  *
484  * RETURN:      Status
485  *
486  * DESCRIPTION: Disable all runtime GPEs, enable all wake GPEs.
487  *              Called with interrupts disabled. The interrupt handler also
488  *              modifies gpe_register_info->Enable, so it should not be
489  *              given the chance to run until after the runtime GPEs are
490  *              re-enabled.
491  *
492  ******************************************************************************/
493 
494 acpi_status
acpi_hw_prepare_gpes_for_sleep(void)495 acpi_hw_prepare_gpes_for_sleep (
496 	void)
497 {
498 	acpi_status                     status;
499 
500 
501 	ACPI_FUNCTION_ENTRY ();
502 
503 
504 	status = acpi_ev_walk_gpe_list (acpi_hw_prepare_gpe_block_for_sleep);
505 	return (status);
506 }
507 
508 
509 /******************************************************************************
510  *
511  * FUNCTION:    acpi_hw_restore_gpe_block_on_wake
512  *
513  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
514  *              gpe_block           - Gpe Block info
515  *
516  * RETURN:      Status
517  *
518  * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in one
519  *              GPE block
520  *
521  ******************************************************************************/
522 
523 static acpi_status
acpi_hw_restore_gpe_block_on_wake(struct acpi_gpe_xrupt_info * gpe_xrupt_info,struct acpi_gpe_block_info * gpe_block)524 acpi_hw_restore_gpe_block_on_wake (
525 	struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
526 	struct acpi_gpe_block_info      *gpe_block)
527 {
528 	u32                             i;
529 	struct acpi_gpe_register_info   *gpe_register_info;
530 	acpi_status                     status;
531 
532 
533 	/* This callback processes one entire GPE block */
534 
535 	/* Get the register info for the entire GPE block */
536 
537 	gpe_register_info = gpe_block->register_info;
538 
539 	/* Examine each GPE register within the block */
540 
541 	for (i = 0; i < gpe_block->register_count; i++) {
542 		/* Clear the entire status register */
543 
544 		status = acpi_hw_low_level_write (8, 0xFF,
545 				 &gpe_block->register_info[i].status_address);
546 		if (ACPI_FAILURE (status)) {
547 			return (status);
548 		}
549 
550 		/*
551 		 * Restore the GPE Enable register, which will do the following:
552 		 *
553 		 * 1) Disable all wakeup GPEs
554 		 * 2) Enable all runtime GPEs
555 		 *
556 		 *  (On sleep, we saved the enabled status of all GPEs)
557 		 */
558 		status = acpi_hw_low_level_write (8, gpe_register_info->enable,
559 				 &gpe_register_info->enable_address);
560 		if (ACPI_FAILURE (status)) {
561 			return (status);
562 		}
563 
564 		/* Point to next GPE register */
565 
566 		gpe_register_info++;
567 	}
568 
569 	return (AE_OK);
570 }
571 
572 
573 /******************************************************************************
574  *
575  * FUNCTION:    acpi_hw_restore_gpes_on_wake
576  *
577  * PARAMETERS:  None
578  *
579  * RETURN:      Status
580  *
581  * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in all
582  *              GPE blocks
583  *
584  ******************************************************************************/
585 
586 acpi_status
acpi_hw_restore_gpes_on_wake(void)587 acpi_hw_restore_gpes_on_wake (
588 	void)
589 {
590 	acpi_status                     status;
591 
592 
593 	ACPI_FUNCTION_ENTRY ();
594 
595 
596 	status = acpi_ev_walk_gpe_list (acpi_hw_restore_gpe_block_on_wake);
597 	return (status);
598 }
599