xref: /freebsd/sys/contrib/dev/acpica/components/hardware/hwgpe.c (revision 076ad2f836d5f49dc1375f1677335a48fe0d4b82)
1 /******************************************************************************
2  *
3  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2017, 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 = AE_OK;
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     if (!(RegisterBit & GpeRegisterInfo->MaskForRun))
168     {
169         /* Write the updated enable mask */
170 
171         Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);
172     }
173     return (Status);
174 }
175 
176 
177 /******************************************************************************
178  *
179  * FUNCTION:    AcpiHwClearGpe
180  *
181  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be cleared
182  *
183  * RETURN:      Status
184  *
185  * DESCRIPTION: Clear the status bit for a single GPE.
186  *
187  ******************************************************************************/
188 
189 ACPI_STATUS
190 AcpiHwClearGpe (
191     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
192 {
193     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
194     ACPI_STATUS             Status;
195     UINT32                  RegisterBit;
196 
197 
198     ACPI_FUNCTION_ENTRY ();
199 
200     /* Get the info block for the entire GPE register */
201 
202     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
203     if (!GpeRegisterInfo)
204     {
205         return (AE_NOT_EXIST);
206     }
207 
208     /*
209      * Write a one to the appropriate bit in the status register to
210      * clear this GPE.
211      */
212     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
213 
214     Status = AcpiHwWrite (RegisterBit, &GpeRegisterInfo->StatusAddress);
215     return (Status);
216 }
217 
218 
219 /******************************************************************************
220  *
221  * FUNCTION:    AcpiHwGetGpeStatus
222  *
223  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to queried
224  *              EventStatus         - Where the GPE status is returned
225  *
226  * RETURN:      Status
227  *
228  * DESCRIPTION: Return the status of a single GPE.
229  *
230  ******************************************************************************/
231 
232 ACPI_STATUS
233 AcpiHwGetGpeStatus (
234     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
235     ACPI_EVENT_STATUS       *EventStatus)
236 {
237     UINT32                  InByte;
238     UINT32                  RegisterBit;
239     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
240     ACPI_EVENT_STATUS       LocalEventStatus = 0;
241     ACPI_STATUS             Status;
242 
243 
244     ACPI_FUNCTION_ENTRY ();
245 
246 
247     if (!EventStatus)
248     {
249         return (AE_BAD_PARAMETER);
250     }
251 
252     /* GPE currently handled? */
253 
254     if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) !=
255         ACPI_GPE_DISPATCH_NONE)
256     {
257         LocalEventStatus |= ACPI_EVENT_FLAG_HAS_HANDLER;
258     }
259 
260     /* Get the info block for the entire GPE register */
261 
262     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
263 
264     /* Get the register bitmask for this GPE */
265 
266     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
267 
268     /* GPE currently enabled? (enabled for runtime?) */
269 
270     if (RegisterBit & GpeRegisterInfo->EnableForRun)
271     {
272         LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED;
273     }
274 
275     /* GPE currently masked? (masked for runtime?) */
276 
277     if (RegisterBit & GpeRegisterInfo->MaskForRun)
278     {
279         LocalEventStatus |= ACPI_EVENT_FLAG_MASKED;
280     }
281 
282     /* GPE enabled for wake? */
283 
284     if (RegisterBit & GpeRegisterInfo->EnableForWake)
285     {
286         LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED;
287     }
288 
289     /* GPE currently enabled (enable bit == 1)? */
290 
291     Status = AcpiHwRead (&InByte, &GpeRegisterInfo->EnableAddress);
292     if (ACPI_FAILURE (Status))
293     {
294         return (Status);
295     }
296 
297     if (RegisterBit & InByte)
298     {
299         LocalEventStatus |= ACPI_EVENT_FLAG_ENABLE_SET;
300     }
301 
302     /* GPE currently active (status bit == 1)? */
303 
304     Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress);
305     if (ACPI_FAILURE (Status))
306     {
307         return (Status);
308     }
309 
310     if (RegisterBit & InByte)
311     {
312         LocalEventStatus |= ACPI_EVENT_FLAG_STATUS_SET;
313     }
314 
315     /* Set return value */
316 
317     (*EventStatus) = LocalEventStatus;
318     return (AE_OK);
319 }
320 
321 
322 /******************************************************************************
323  *
324  * FUNCTION:    AcpiHwGpeEnableWrite
325  *
326  * PARAMETERS:  EnableMask          - Bit mask to write to the GPE register
327  *              GpeRegisterInfo     - Gpe Register info
328  *
329  * RETURN:      Status
330  *
331  * DESCRIPTION: Write the enable mask byte to the given GPE register.
332  *
333  ******************************************************************************/
334 
335 static ACPI_STATUS
336 AcpiHwGpeEnableWrite (
337     UINT8                   EnableMask,
338     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo)
339 {
340     ACPI_STATUS             Status;
341 
342 
343     GpeRegisterInfo->EnableMask = EnableMask;
344 
345     Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);
346     return (Status);
347 }
348 
349 
350 /******************************************************************************
351  *
352  * FUNCTION:    AcpiHwDisableGpeBlock
353  *
354  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
355  *              GpeBlock            - Gpe Block info
356  *
357  * RETURN:      Status
358  *
359  * DESCRIPTION: Disable all GPEs within a single GPE block
360  *
361  ******************************************************************************/
362 
363 ACPI_STATUS
364 AcpiHwDisableGpeBlock (
365     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
366     ACPI_GPE_BLOCK_INFO     *GpeBlock,
367     void                    *Context)
368 {
369     UINT32                  i;
370     ACPI_STATUS             Status;
371 
372 
373     /* Examine each GPE Register within the block */
374 
375     for (i = 0; i < GpeBlock->RegisterCount; i++)
376     {
377         /* Disable all GPEs in this register */
378 
379         Status = AcpiHwGpeEnableWrite (0x00, &GpeBlock->RegisterInfo[i]);
380         if (ACPI_FAILURE (Status))
381         {
382             return (Status);
383         }
384     }
385 
386     return (AE_OK);
387 }
388 
389 
390 /******************************************************************************
391  *
392  * FUNCTION:    AcpiHwClearGpeBlock
393  *
394  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
395  *              GpeBlock            - Gpe Block info
396  *
397  * RETURN:      Status
398  *
399  * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
400  *
401  ******************************************************************************/
402 
403 ACPI_STATUS
404 AcpiHwClearGpeBlock (
405     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
406     ACPI_GPE_BLOCK_INFO     *GpeBlock,
407     void                    *Context)
408 {
409     UINT32                  i;
410     ACPI_STATUS             Status;
411 
412 
413     /* Examine each GPE Register within the block */
414 
415     for (i = 0; i < GpeBlock->RegisterCount; i++)
416     {
417         /* Clear status on all GPEs in this register */
418 
419         Status = AcpiHwWrite (0xFF, &GpeBlock->RegisterInfo[i].StatusAddress);
420         if (ACPI_FAILURE (Status))
421         {
422             return (Status);
423         }
424     }
425 
426     return (AE_OK);
427 }
428 
429 
430 /******************************************************************************
431  *
432  * FUNCTION:    AcpiHwEnableRuntimeGpeBlock
433  *
434  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
435  *              GpeBlock            - Gpe Block info
436  *
437  * RETURN:      Status
438  *
439  * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
440  *              combination wake/run GPEs.
441  *
442  ******************************************************************************/
443 
444 ACPI_STATUS
445 AcpiHwEnableRuntimeGpeBlock (
446     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
447     ACPI_GPE_BLOCK_INFO     *GpeBlock,
448     void                    *Context)
449 {
450     UINT32                  i;
451     ACPI_STATUS             Status;
452     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
453     UINT8                   EnableMask;
454 
455 
456     /* NOTE: assumes that all GPEs are currently disabled */
457 
458     /* Examine each GPE Register within the block */
459 
460     for (i = 0; i < GpeBlock->RegisterCount; i++)
461     {
462         GpeRegisterInfo = &GpeBlock->RegisterInfo[i];
463         if (!GpeRegisterInfo->EnableForRun)
464         {
465             continue;
466         }
467 
468         /* Enable all "runtime" GPEs in this register */
469 
470         EnableMask = GpeRegisterInfo->EnableForRun &
471             ~GpeRegisterInfo->MaskForRun;
472         Status = AcpiHwGpeEnableWrite (EnableMask, GpeRegisterInfo);
473         if (ACPI_FAILURE (Status))
474         {
475             return (Status);
476         }
477     }
478 
479     return (AE_OK);
480 }
481 
482 
483 /******************************************************************************
484  *
485  * FUNCTION:    AcpiHwEnableWakeupGpeBlock
486  *
487  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
488  *              GpeBlock            - Gpe Block info
489  *
490  * RETURN:      Status
491  *
492  * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
493  *              combination wake/run GPEs.
494  *
495  ******************************************************************************/
496 
497 static ACPI_STATUS
498 AcpiHwEnableWakeupGpeBlock (
499     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
500     ACPI_GPE_BLOCK_INFO     *GpeBlock,
501     void                    *Context)
502 {
503     UINT32                  i;
504     ACPI_STATUS             Status;
505     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
506 
507 
508     /* Examine each GPE Register within the block */
509 
510     for (i = 0; i < GpeBlock->RegisterCount; i++)
511     {
512         GpeRegisterInfo = &GpeBlock->RegisterInfo[i];
513 
514         /*
515          * Enable all "wake" GPEs in this register and disable the
516          * remaining ones.
517          */
518         Status = AcpiHwGpeEnableWrite (GpeRegisterInfo->EnableForWake,
519             GpeRegisterInfo);
520         if (ACPI_FAILURE (Status))
521         {
522             return (Status);
523         }
524     }
525 
526     return (AE_OK);
527 }
528 
529 
530 /******************************************************************************
531  *
532  * FUNCTION:    AcpiHwDisableAllGpes
533  *
534  * PARAMETERS:  None
535  *
536  * RETURN:      Status
537  *
538  * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
539  *
540  ******************************************************************************/
541 
542 ACPI_STATUS
543 AcpiHwDisableAllGpes (
544     void)
545 {
546     ACPI_STATUS             Status;
547 
548 
549     ACPI_FUNCTION_TRACE (HwDisableAllGpes);
550 
551 
552     Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL);
553     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
554     return_ACPI_STATUS (Status);
555 }
556 
557 
558 /******************************************************************************
559  *
560  * FUNCTION:    AcpiHwEnableAllRuntimeGpes
561  *
562  * PARAMETERS:  None
563  *
564  * RETURN:      Status
565  *
566  * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
567  *
568  ******************************************************************************/
569 
570 ACPI_STATUS
571 AcpiHwEnableAllRuntimeGpes (
572     void)
573 {
574     ACPI_STATUS             Status;
575 
576 
577     ACPI_FUNCTION_TRACE (HwEnableAllRuntimeGpes);
578 
579 
580     Status = AcpiEvWalkGpeList (AcpiHwEnableRuntimeGpeBlock, NULL);
581     return_ACPI_STATUS (Status);
582 }
583 
584 
585 /******************************************************************************
586  *
587  * FUNCTION:    AcpiHwEnableAllWakeupGpes
588  *
589  * PARAMETERS:  None
590  *
591  * RETURN:      Status
592  *
593  * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
594  *
595  ******************************************************************************/
596 
597 ACPI_STATUS
598 AcpiHwEnableAllWakeupGpes (
599     void)
600 {
601     ACPI_STATUS             Status;
602 
603 
604     ACPI_FUNCTION_TRACE (HwEnableAllWakeupGpes);
605 
606 
607     Status = AcpiEvWalkGpeList (AcpiHwEnableWakeupGpeBlock, NULL);
608     return_ACPI_STATUS (Status);
609 }
610 
611 #endif /* !ACPI_REDUCED_HARDWARE */
612