1 /******************************************************************************
2  *
3  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2014, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acevents.h"
47 
48 #define _COMPONENT          ACPI_HARDWARE
49         ACPI_MODULE_NAME    ("hwgpe")
50 
51 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
52 
53 /* Local prototypes */
54 
55 static ACPI_STATUS
56 AcpiHwEnableWakeupGpeBlock (
57     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
58     ACPI_GPE_BLOCK_INFO     *GpeBlock,
59     void                    *Context);
60 
61 
62 /******************************************************************************
63  *
64  * FUNCTION:    AcpiHwGetGpeRegisterBit
65  *
66  * PARAMETERS:  GpeEventInfo        - Info block for the GPE
67  *
68  * RETURN:      Register mask with a one in the GPE bit position
69  *
70  * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the
71  *              correct position for the input GPE.
72  *
73  ******************************************************************************/
74 
75 UINT32
76 AcpiHwGetGpeRegisterBit (
77     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
78 {
79 
80     return ((UINT32) 1 <<
81         (GpeEventInfo->GpeNumber - GpeEventInfo->RegisterInfo->BaseGpeNumber));
82 }
83 
84 
85 /******************************************************************************
86  *
87  * FUNCTION:    AcpiHwLowSetGpe
88  *
89  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be disabled
90  *              Action              - Enable or disable
91  *
92  * RETURN:      Status
93  *
94  * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
95  *
96  ******************************************************************************/
97 
98 ACPI_STATUS
99 AcpiHwLowSetGpe (
100     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
101     UINT32                  Action)
102 {
103     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
104     ACPI_STATUS             Status;
105     UINT32                  EnableMask;
106     UINT32                  RegisterBit;
107 
108 
109     ACPI_FUNCTION_ENTRY ();
110 
111 
112     /* Get the info block for the entire GPE register */
113 
114     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
115     if (!GpeRegisterInfo)
116     {
117         return (AE_NOT_EXIST);
118     }
119 
120     /* Get current value of the enable register that contains this GPE */
121 
122     Status = AcpiHwRead (&EnableMask, &GpeRegisterInfo->EnableAddress);
123     if (ACPI_FAILURE (Status))
124     {
125         return (Status);
126     }
127 
128     /* Set or clear just the bit that corresponds to this GPE */
129 
130     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
131     switch (Action)
132     {
133     case ACPI_GPE_CONDITIONAL_ENABLE:
134 
135         /* Only enable if the EnableForRun bit is set */
136 
137         if (!(RegisterBit & GpeRegisterInfo->EnableForRun))
138         {
139             return (AE_BAD_PARAMETER);
140         }
141 
142         /*lint -fallthrough */
143 
144     case ACPI_GPE_ENABLE:
145 
146         ACPI_SET_BIT (EnableMask, RegisterBit);
147         break;
148 
149     case ACPI_GPE_DISABLE:
150 
151         ACPI_CLEAR_BIT (EnableMask, RegisterBit);
152         break;
153 
154     default:
155 
156         ACPI_ERROR ((AE_INFO, "Invalid GPE Action, %u", Action));
157         return (AE_BAD_PARAMETER);
158     }
159 
160     /* Write the updated enable mask */
161 
162     Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);
163     return (Status);
164 }
165 
166 
167 /******************************************************************************
168  *
169  * FUNCTION:    AcpiHwClearGpe
170  *
171  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be cleared
172  *
173  * RETURN:      Status
174  *
175  * DESCRIPTION: Clear the status bit for a single GPE.
176  *
177  ******************************************************************************/
178 
179 ACPI_STATUS
180 AcpiHwClearGpe (
181     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
182 {
183     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
184     ACPI_STATUS             Status;
185     UINT32                  RegisterBit;
186 
187 
188     ACPI_FUNCTION_ENTRY ();
189 
190     /* Get the info block for the entire GPE register */
191 
192     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
193     if (!GpeRegisterInfo)
194     {
195         return (AE_NOT_EXIST);
196     }
197 
198     /*
199      * Write a one to the appropriate bit in the status register to
200      * clear this GPE.
201      */
202     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
203 
204     Status = AcpiHwWrite (RegisterBit,
205                     &GpeRegisterInfo->StatusAddress);
206 
207     return (Status);
208 }
209 
210 
211 /******************************************************************************
212  *
213  * FUNCTION:    AcpiHwGetGpeStatus
214  *
215  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to queried
216  *              EventStatus         - Where the GPE status is returned
217  *
218  * RETURN:      Status
219  *
220  * DESCRIPTION: Return the status of a single GPE.
221  *
222  ******************************************************************************/
223 
224 ACPI_STATUS
225 AcpiHwGetGpeStatus (
226     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
227     ACPI_EVENT_STATUS       *EventStatus)
228 {
229     UINT32                  InByte;
230     UINT32                  RegisterBit;
231     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
232     ACPI_EVENT_STATUS       LocalEventStatus = 0;
233     ACPI_STATUS             Status;
234 
235 
236     ACPI_FUNCTION_ENTRY ();
237 
238 
239     if (!EventStatus)
240     {
241         return (AE_BAD_PARAMETER);
242     }
243 
244     /* Get the info block for the entire GPE register */
245 
246     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
247 
248     /* Get the register bitmask for this GPE */
249 
250     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
251 
252     /* GPE currently enabled? (enabled for runtime?) */
253 
254     if (RegisterBit & GpeRegisterInfo->EnableForRun)
255     {
256         LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED;
257     }
258 
259     /* GPE enabled for wake? */
260 
261     if (RegisterBit & GpeRegisterInfo->EnableForWake)
262     {
263         LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED;
264     }
265 
266     /* GPE currently active (status bit == 1)? */
267 
268     Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress);
269     if (ACPI_FAILURE (Status))
270     {
271         return (Status);
272     }
273 
274     if (RegisterBit & InByte)
275     {
276         LocalEventStatus |= ACPI_EVENT_FLAG_SET;
277     }
278 
279     /* Set return value */
280 
281     (*EventStatus) = LocalEventStatus;
282     return (AE_OK);
283 }
284 
285 
286 /******************************************************************************
287  *
288  * FUNCTION:    AcpiHwDisableGpeBlock
289  *
290  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
291  *              GpeBlock            - Gpe Block info
292  *
293  * RETURN:      Status
294  *
295  * DESCRIPTION: Disable all GPEs within a single GPE block
296  *
297  ******************************************************************************/
298 
299 ACPI_STATUS
300 AcpiHwDisableGpeBlock (
301     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
302     ACPI_GPE_BLOCK_INFO     *GpeBlock,
303     void                    *Context)
304 {
305     UINT32                  i;
306     ACPI_STATUS             Status;
307 
308 
309     /* Examine each GPE Register within the block */
310 
311     for (i = 0; i < GpeBlock->RegisterCount; i++)
312     {
313         /* Disable all GPEs in this register */
314 
315         Status = AcpiHwWrite (0x00, &GpeBlock->RegisterInfo[i].EnableAddress);
316         if (ACPI_FAILURE (Status))
317         {
318             return (Status);
319         }
320     }
321 
322     return (AE_OK);
323 }
324 
325 
326 /******************************************************************************
327  *
328  * FUNCTION:    AcpiHwClearGpeBlock
329  *
330  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
331  *              GpeBlock            - Gpe Block info
332  *
333  * RETURN:      Status
334  *
335  * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
336  *
337  ******************************************************************************/
338 
339 ACPI_STATUS
340 AcpiHwClearGpeBlock (
341     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
342     ACPI_GPE_BLOCK_INFO     *GpeBlock,
343     void                    *Context)
344 {
345     UINT32                  i;
346     ACPI_STATUS             Status;
347 
348 
349     /* Examine each GPE Register within the block */
350 
351     for (i = 0; i < GpeBlock->RegisterCount; i++)
352     {
353         /* Clear status on all GPEs in this register */
354 
355         Status = AcpiHwWrite (0xFF, &GpeBlock->RegisterInfo[i].StatusAddress);
356         if (ACPI_FAILURE (Status))
357         {
358             return (Status);
359         }
360     }
361 
362     return (AE_OK);
363 }
364 
365 
366 /******************************************************************************
367  *
368  * FUNCTION:    AcpiHwEnableRuntimeGpeBlock
369  *
370  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
371  *              GpeBlock            - Gpe Block info
372  *
373  * RETURN:      Status
374  *
375  * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
376  *              combination wake/run GPEs.
377  *
378  ******************************************************************************/
379 
380 ACPI_STATUS
381 AcpiHwEnableRuntimeGpeBlock (
382     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
383     ACPI_GPE_BLOCK_INFO     *GpeBlock,
384     void                    *Context)
385 {
386     UINT32                  i;
387     ACPI_STATUS             Status;
388 
389 
390     /* NOTE: assumes that all GPEs are currently disabled */
391 
392     /* Examine each GPE Register within the block */
393 
394     for (i = 0; i < GpeBlock->RegisterCount; i++)
395     {
396         if (!GpeBlock->RegisterInfo[i].EnableForRun)
397         {
398             continue;
399         }
400 
401         /* Enable all "runtime" GPEs in this register */
402 
403         Status = AcpiHwWrite (GpeBlock->RegisterInfo[i].EnableForRun,
404                     &GpeBlock->RegisterInfo[i].EnableAddress);
405         if (ACPI_FAILURE (Status))
406         {
407             return (Status);
408         }
409     }
410 
411     return (AE_OK);
412 }
413 
414 
415 /******************************************************************************
416  *
417  * FUNCTION:    AcpiHwEnableWakeupGpeBlock
418  *
419  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
420  *              GpeBlock            - Gpe Block info
421  *
422  * RETURN:      Status
423  *
424  * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
425  *              combination wake/run GPEs.
426  *
427  ******************************************************************************/
428 
429 static ACPI_STATUS
430 AcpiHwEnableWakeupGpeBlock (
431     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
432     ACPI_GPE_BLOCK_INFO     *GpeBlock,
433     void                    *Context)
434 {
435     UINT32                  i;
436     ACPI_STATUS             Status;
437 
438 
439     /* Examine each GPE Register within the block */
440 
441     for (i = 0; i < GpeBlock->RegisterCount; i++)
442     {
443         if (!GpeBlock->RegisterInfo[i].EnableForWake)
444         {
445             continue;
446         }
447 
448         /* Enable all "wake" GPEs in this register */
449 
450         Status = AcpiHwWrite (GpeBlock->RegisterInfo[i].EnableForWake,
451                     &GpeBlock->RegisterInfo[i].EnableAddress);
452         if (ACPI_FAILURE (Status))
453         {
454             return (Status);
455         }
456     }
457 
458     return (AE_OK);
459 }
460 
461 
462 /******************************************************************************
463  *
464  * FUNCTION:    AcpiHwDisableAllGpes
465  *
466  * PARAMETERS:  None
467  *
468  * RETURN:      Status
469  *
470  * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
471  *
472  ******************************************************************************/
473 
474 ACPI_STATUS
475 AcpiHwDisableAllGpes (
476     void)
477 {
478     ACPI_STATUS             Status;
479 
480 
481     ACPI_FUNCTION_TRACE (HwDisableAllGpes);
482 
483 
484     Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL);
485     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
486     return_ACPI_STATUS (Status);
487 }
488 
489 
490 /******************************************************************************
491  *
492  * FUNCTION:    AcpiHwEnableAllRuntimeGpes
493  *
494  * PARAMETERS:  None
495  *
496  * RETURN:      Status
497  *
498  * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
499  *
500  ******************************************************************************/
501 
502 ACPI_STATUS
503 AcpiHwEnableAllRuntimeGpes (
504     void)
505 {
506     ACPI_STATUS             Status;
507 
508 
509     ACPI_FUNCTION_TRACE (HwEnableAllRuntimeGpes);
510 
511 
512     Status = AcpiEvWalkGpeList (AcpiHwEnableRuntimeGpeBlock, NULL);
513     return_ACPI_STATUS (Status);
514 }
515 
516 
517 /******************************************************************************
518  *
519  * FUNCTION:    AcpiHwEnableAllWakeupGpes
520  *
521  * PARAMETERS:  None
522  *
523  * RETURN:      Status
524  *
525  * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
526  *
527  ******************************************************************************/
528 
529 ACPI_STATUS
530 AcpiHwEnableAllWakeupGpes (
531     void)
532 {
533     ACPI_STATUS             Status;
534 
535 
536     ACPI_FUNCTION_TRACE (HwEnableAllWakeupGpes);
537 
538 
539     Status = AcpiEvWalkGpeList (AcpiHwEnableWakeupGpeBlock, NULL);
540     return_ACPI_STATUS (Status);
541 }
542 
543 #endif /* !ACPI_REDUCED_HARDWARE */
544