xref: /freebsd/sys/contrib/dev/acpica/components/hardware/hwgpe.c (revision a0ee8cc636cd5c2374ec44ca71226564ea0bca95)
1 /******************************************************************************
2  *
3  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2015, 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 <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/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 static ACPI_STATUS
62 AcpiHwGpeEnableWrite (
63     UINT8                   EnableMask,
64     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo);
65 
66 
67 /******************************************************************************
68  *
69  * FUNCTION:    AcpiHwGetGpeRegisterBit
70  *
71  * PARAMETERS:  GpeEventInfo        - Info block for the GPE
72  *
73  * RETURN:      Register mask with a one in the GPE bit position
74  *
75  * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the
76  *              correct position for the input GPE.
77  *
78  ******************************************************************************/
79 
80 UINT32
81 AcpiHwGetGpeRegisterBit (
82     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
83 {
84 
85     return ((UINT32) 1 <<
86         (GpeEventInfo->GpeNumber - GpeEventInfo->RegisterInfo->BaseGpeNumber));
87 }
88 
89 
90 /******************************************************************************
91  *
92  * FUNCTION:    AcpiHwLowSetGpe
93  *
94  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be disabled
95  *              Action              - Enable or disable
96  *
97  * RETURN:      Status
98  *
99  * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
100  *              The EnableMask field of the involved GPE register must be
101  *              updated by the caller if necessary.
102  *
103  ******************************************************************************/
104 
105 ACPI_STATUS
106 AcpiHwLowSetGpe (
107     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
108     UINT32                  Action)
109 {
110     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
111     ACPI_STATUS             Status;
112     UINT32                  EnableMask;
113     UINT32                  RegisterBit;
114 
115 
116     ACPI_FUNCTION_ENTRY ();
117 
118 
119     /* Get the info block for the entire GPE register */
120 
121     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
122     if (!GpeRegisterInfo)
123     {
124         return (AE_NOT_EXIST);
125     }
126 
127     /* Get current value of the enable register that contains this GPE */
128 
129     Status = AcpiHwRead (&EnableMask, &GpeRegisterInfo->EnableAddress);
130     if (ACPI_FAILURE (Status))
131     {
132         return (Status);
133     }
134 
135     /* Set or clear just the bit that corresponds to this GPE */
136 
137     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
138     switch (Action)
139     {
140     case ACPI_GPE_CONDITIONAL_ENABLE:
141 
142         /* Only enable if the corresponding EnableMask bit is set */
143 
144         if (!(RegisterBit & GpeRegisterInfo->EnableMask))
145         {
146             return (AE_BAD_PARAMETER);
147         }
148 
149         /*lint -fallthrough */
150 
151     case ACPI_GPE_ENABLE:
152 
153         ACPI_SET_BIT (EnableMask, RegisterBit);
154         break;
155 
156     case ACPI_GPE_DISABLE:
157 
158         ACPI_CLEAR_BIT (EnableMask, RegisterBit);
159         break;
160 
161     default:
162 
163         ACPI_ERROR ((AE_INFO, "Invalid GPE Action, %u", Action));
164         return (AE_BAD_PARAMETER);
165     }
166 
167     /* Write the updated enable mask */
168 
169     Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);
170     return (Status);
171 }
172 
173 
174 /******************************************************************************
175  *
176  * FUNCTION:    AcpiHwClearGpe
177  *
178  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be cleared
179  *
180  * RETURN:      Status
181  *
182  * DESCRIPTION: Clear the status bit for a single GPE.
183  *
184  ******************************************************************************/
185 
186 ACPI_STATUS
187 AcpiHwClearGpe (
188     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
189 {
190     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
191     ACPI_STATUS             Status;
192     UINT32                  RegisterBit;
193 
194 
195     ACPI_FUNCTION_ENTRY ();
196 
197     /* Get the info block for the entire GPE register */
198 
199     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
200     if (!GpeRegisterInfo)
201     {
202         return (AE_NOT_EXIST);
203     }
204 
205     /*
206      * Write a one to the appropriate bit in the status register to
207      * clear this GPE.
208      */
209     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
210 
211     Status = AcpiHwWrite (RegisterBit,
212                     &GpeRegisterInfo->StatusAddress);
213 
214     return (Status);
215 }
216 
217 
218 /******************************************************************************
219  *
220  * FUNCTION:    AcpiHwGetGpeStatus
221  *
222  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to queried
223  *              EventStatus         - Where the GPE status is returned
224  *
225  * RETURN:      Status
226  *
227  * DESCRIPTION: Return the status of a single GPE.
228  *
229  ******************************************************************************/
230 
231 ACPI_STATUS
232 AcpiHwGetGpeStatus (
233     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
234     ACPI_EVENT_STATUS       *EventStatus)
235 {
236     UINT32                  InByte;
237     UINT32                  RegisterBit;
238     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
239     ACPI_EVENT_STATUS       LocalEventStatus = 0;
240     ACPI_STATUS             Status;
241 
242 
243     ACPI_FUNCTION_ENTRY ();
244 
245 
246     if (!EventStatus)
247     {
248         return (AE_BAD_PARAMETER);
249     }
250 
251     /* GPE currently handled? */
252 
253     if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) !=
254             ACPI_GPE_DISPATCH_NONE)
255     {
256         LocalEventStatus |= ACPI_EVENT_FLAG_HAS_HANDLER;
257     }
258 
259     /* Get the info block for the entire GPE register */
260 
261     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
262 
263     /* Get the register bitmask for this GPE */
264 
265     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
266 
267     /* GPE currently enabled? (enabled for runtime?) */
268 
269     if (RegisterBit & GpeRegisterInfo->EnableForRun)
270     {
271         LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED;
272     }
273 
274     /* GPE enabled for wake? */
275 
276     if (RegisterBit & GpeRegisterInfo->EnableForWake)
277     {
278         LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED;
279     }
280 
281     /* GPE currently enabled (enable bit == 1)? */
282 
283     Status = AcpiHwRead (&InByte, &GpeRegisterInfo->EnableAddress);
284     if (ACPI_FAILURE (Status))
285     {
286         return (Status);
287     }
288 
289     if (RegisterBit & InByte)
290     {
291         LocalEventStatus |= ACPI_EVENT_FLAG_ENABLE_SET;
292     }
293 
294     /* GPE currently active (status bit == 1)? */
295 
296     Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress);
297     if (ACPI_FAILURE (Status))
298     {
299         return (Status);
300     }
301 
302     if (RegisterBit & InByte)
303     {
304         LocalEventStatus |= ACPI_EVENT_FLAG_STATUS_SET;
305     }
306 
307     /* Set return value */
308 
309     (*EventStatus) = LocalEventStatus;
310     return (AE_OK);
311 }
312 
313 
314 /******************************************************************************
315  *
316  * FUNCTION:    AcpiHwGpeEnableWrite
317  *
318  * PARAMETERS:  EnableMask          - Bit mask to write to the GPE register
319  *              GpeRegisterInfo     - Gpe Register info
320  *
321  * RETURN:      Status
322  *
323  * DESCRIPTION: Write the enable mask byte to the given GPE register.
324  *
325  ******************************************************************************/
326 
327 static ACPI_STATUS
328 AcpiHwGpeEnableWrite (
329     UINT8                   EnableMask,
330     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo)
331 {
332     ACPI_STATUS             Status;
333 
334 
335     GpeRegisterInfo->EnableMask = EnableMask;
336     Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);
337 
338     return (Status);
339 }
340 
341 
342 /******************************************************************************
343  *
344  * FUNCTION:    AcpiHwDisableGpeBlock
345  *
346  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
347  *              GpeBlock            - Gpe Block info
348  *
349  * RETURN:      Status
350  *
351  * DESCRIPTION: Disable all GPEs within a single GPE block
352  *
353  ******************************************************************************/
354 
355 ACPI_STATUS
356 AcpiHwDisableGpeBlock (
357     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
358     ACPI_GPE_BLOCK_INFO     *GpeBlock,
359     void                    *Context)
360 {
361     UINT32                  i;
362     ACPI_STATUS             Status;
363 
364 
365     /* Examine each GPE Register within the block */
366 
367     for (i = 0; i < GpeBlock->RegisterCount; i++)
368     {
369         /* Disable all GPEs in this register */
370 
371         Status = AcpiHwGpeEnableWrite (0x00, &GpeBlock->RegisterInfo[i]);
372         if (ACPI_FAILURE (Status))
373         {
374             return (Status);
375         }
376     }
377 
378     return (AE_OK);
379 }
380 
381 
382 /******************************************************************************
383  *
384  * FUNCTION:    AcpiHwClearGpeBlock
385  *
386  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
387  *              GpeBlock            - Gpe Block info
388  *
389  * RETURN:      Status
390  *
391  * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
392  *
393  ******************************************************************************/
394 
395 ACPI_STATUS
396 AcpiHwClearGpeBlock (
397     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
398     ACPI_GPE_BLOCK_INFO     *GpeBlock,
399     void                    *Context)
400 {
401     UINT32                  i;
402     ACPI_STATUS             Status;
403 
404 
405     /* Examine each GPE Register within the block */
406 
407     for (i = 0; i < GpeBlock->RegisterCount; i++)
408     {
409         /* Clear status on all GPEs in this register */
410 
411         Status = AcpiHwWrite (0xFF, &GpeBlock->RegisterInfo[i].StatusAddress);
412         if (ACPI_FAILURE (Status))
413         {
414             return (Status);
415         }
416     }
417 
418     return (AE_OK);
419 }
420 
421 
422 /******************************************************************************
423  *
424  * FUNCTION:    AcpiHwEnableRuntimeGpeBlock
425  *
426  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
427  *              GpeBlock            - Gpe Block info
428  *
429  * RETURN:      Status
430  *
431  * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
432  *              combination wake/run GPEs.
433  *
434  ******************************************************************************/
435 
436 ACPI_STATUS
437 AcpiHwEnableRuntimeGpeBlock (
438     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
439     ACPI_GPE_BLOCK_INFO     *GpeBlock,
440     void                    *Context)
441 {
442     UINT32                  i;
443     ACPI_STATUS             Status;
444     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
445 
446 
447     /* NOTE: assumes that all GPEs are currently disabled */
448 
449     /* Examine each GPE Register within the block */
450 
451     for (i = 0; i < GpeBlock->RegisterCount; i++)
452     {
453         GpeRegisterInfo = &GpeBlock->RegisterInfo[i];
454         if (!GpeRegisterInfo->EnableForRun)
455         {
456             continue;
457         }
458 
459         /* Enable all "runtime" GPEs in this register */
460 
461         Status = AcpiHwGpeEnableWrite (GpeRegisterInfo->EnableForRun,
462                     GpeRegisterInfo);
463         if (ACPI_FAILURE (Status))
464         {
465             return (Status);
466         }
467     }
468 
469     return (AE_OK);
470 }
471 
472 
473 /******************************************************************************
474  *
475  * FUNCTION:    AcpiHwEnableWakeupGpeBlock
476  *
477  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
478  *              GpeBlock            - Gpe Block info
479  *
480  * RETURN:      Status
481  *
482  * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
483  *              combination wake/run GPEs.
484  *
485  ******************************************************************************/
486 
487 static ACPI_STATUS
488 AcpiHwEnableWakeupGpeBlock (
489     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
490     ACPI_GPE_BLOCK_INFO     *GpeBlock,
491     void                    *Context)
492 {
493     UINT32                  i;
494     ACPI_STATUS             Status;
495     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
496 
497 
498     /* Examine each GPE Register within the block */
499 
500     for (i = 0; i < GpeBlock->RegisterCount; i++)
501     {
502         GpeRegisterInfo = &GpeBlock->RegisterInfo[i];
503 
504         /*
505          * Enable all "wake" GPEs in this register and disable the
506          * remaining ones.
507          */
508         Status = AcpiHwGpeEnableWrite (GpeRegisterInfo->EnableForWake,
509                     GpeRegisterInfo);
510         if (ACPI_FAILURE (Status))
511         {
512             return (Status);
513         }
514     }
515 
516     return (AE_OK);
517 }
518 
519 
520 /******************************************************************************
521  *
522  * FUNCTION:    AcpiHwDisableAllGpes
523  *
524  * PARAMETERS:  None
525  *
526  * RETURN:      Status
527  *
528  * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
529  *
530  ******************************************************************************/
531 
532 ACPI_STATUS
533 AcpiHwDisableAllGpes (
534     void)
535 {
536     ACPI_STATUS             Status;
537 
538 
539     ACPI_FUNCTION_TRACE (HwDisableAllGpes);
540 
541 
542     Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL);
543     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
544     return_ACPI_STATUS (Status);
545 }
546 
547 
548 /******************************************************************************
549  *
550  * FUNCTION:    AcpiHwEnableAllRuntimeGpes
551  *
552  * PARAMETERS:  None
553  *
554  * RETURN:      Status
555  *
556  * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
557  *
558  ******************************************************************************/
559 
560 ACPI_STATUS
561 AcpiHwEnableAllRuntimeGpes (
562     void)
563 {
564     ACPI_STATUS             Status;
565 
566 
567     ACPI_FUNCTION_TRACE (HwEnableAllRuntimeGpes);
568 
569 
570     Status = AcpiEvWalkGpeList (AcpiHwEnableRuntimeGpeBlock, NULL);
571     return_ACPI_STATUS (Status);
572 }
573 
574 
575 /******************************************************************************
576  *
577  * FUNCTION:    AcpiHwEnableAllWakeupGpes
578  *
579  * PARAMETERS:  None
580  *
581  * RETURN:      Status
582  *
583  * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
584  *
585  ******************************************************************************/
586 
587 ACPI_STATUS
588 AcpiHwEnableAllWakeupGpes (
589     void)
590 {
591     ACPI_STATUS             Status;
592 
593 
594     ACPI_FUNCTION_TRACE (HwEnableAllWakeupGpes);
595 
596 
597     Status = AcpiEvWalkGpeList (AcpiHwEnableWakeupGpeBlock, NULL);
598     return_ACPI_STATUS (Status);
599 }
600 
601 #endif /* !ACPI_REDUCED_HARDWARE */
602