xref: /freebsd/sys/contrib/dev/acpica/components/hardware/hwgpe.c (revision c6db8143eda5c775467145ac73e8ebec47afdd8f)
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 <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 
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     /* GPE currently handled? */
245 
246     if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) !=
247             ACPI_GPE_DISPATCH_NONE)
248     {
249         LocalEventStatus |= ACPI_EVENT_FLAG_HAS_HANDLER;
250     }
251 
252     /* Get the info block for the entire GPE register */
253 
254     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
255 
256     /* Get the register bitmask for this GPE */
257 
258     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
259 
260     /* GPE currently enabled? (enabled for runtime?) */
261 
262     if (RegisterBit & GpeRegisterInfo->EnableForRun)
263     {
264         LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED;
265     }
266 
267     /* GPE enabled for wake? */
268 
269     if (RegisterBit & GpeRegisterInfo->EnableForWake)
270     {
271         LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED;
272     }
273 
274     /* GPE currently active (status bit == 1)? */
275 
276     Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress);
277     if (ACPI_FAILURE (Status))
278     {
279         return (Status);
280     }
281 
282     if (RegisterBit & InByte)
283     {
284         LocalEventStatus |= ACPI_EVENT_FLAG_SET;
285     }
286 
287     /* Set return value */
288 
289     (*EventStatus) = LocalEventStatus;
290     return (AE_OK);
291 }
292 
293 
294 /******************************************************************************
295  *
296  * FUNCTION:    AcpiHwDisableGpeBlock
297  *
298  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
299  *              GpeBlock            - Gpe Block info
300  *
301  * RETURN:      Status
302  *
303  * DESCRIPTION: Disable all GPEs within a single GPE block
304  *
305  ******************************************************************************/
306 
307 ACPI_STATUS
308 AcpiHwDisableGpeBlock (
309     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
310     ACPI_GPE_BLOCK_INFO     *GpeBlock,
311     void                    *Context)
312 {
313     UINT32                  i;
314     ACPI_STATUS             Status;
315 
316 
317     /* Examine each GPE Register within the block */
318 
319     for (i = 0; i < GpeBlock->RegisterCount; i++)
320     {
321         /* Disable all GPEs in this register */
322 
323         Status = AcpiHwWrite (0x00, &GpeBlock->RegisterInfo[i].EnableAddress);
324         if (ACPI_FAILURE (Status))
325         {
326             return (Status);
327         }
328     }
329 
330     return (AE_OK);
331 }
332 
333 
334 /******************************************************************************
335  *
336  * FUNCTION:    AcpiHwClearGpeBlock
337  *
338  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
339  *              GpeBlock            - Gpe Block info
340  *
341  * RETURN:      Status
342  *
343  * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
344  *
345  ******************************************************************************/
346 
347 ACPI_STATUS
348 AcpiHwClearGpeBlock (
349     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
350     ACPI_GPE_BLOCK_INFO     *GpeBlock,
351     void                    *Context)
352 {
353     UINT32                  i;
354     ACPI_STATUS             Status;
355 
356 
357     /* Examine each GPE Register within the block */
358 
359     for (i = 0; i < GpeBlock->RegisterCount; i++)
360     {
361         /* Clear status on all GPEs in this register */
362 
363         Status = AcpiHwWrite (0xFF, &GpeBlock->RegisterInfo[i].StatusAddress);
364         if (ACPI_FAILURE (Status))
365         {
366             return (Status);
367         }
368     }
369 
370     return (AE_OK);
371 }
372 
373 
374 /******************************************************************************
375  *
376  * FUNCTION:    AcpiHwEnableRuntimeGpeBlock
377  *
378  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
379  *              GpeBlock            - Gpe Block info
380  *
381  * RETURN:      Status
382  *
383  * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
384  *              combination wake/run GPEs.
385  *
386  ******************************************************************************/
387 
388 ACPI_STATUS
389 AcpiHwEnableRuntimeGpeBlock (
390     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
391     ACPI_GPE_BLOCK_INFO     *GpeBlock,
392     void                    *Context)
393 {
394     UINT32                  i;
395     ACPI_STATUS             Status;
396 
397 
398     /* NOTE: assumes that all GPEs are currently disabled */
399 
400     /* Examine each GPE Register within the block */
401 
402     for (i = 0; i < GpeBlock->RegisterCount; i++)
403     {
404         if (!GpeBlock->RegisterInfo[i].EnableForRun)
405         {
406             continue;
407         }
408 
409         /* Enable all "runtime" GPEs in this register */
410 
411         Status = AcpiHwWrite (GpeBlock->RegisterInfo[i].EnableForRun,
412                     &GpeBlock->RegisterInfo[i].EnableAddress);
413         if (ACPI_FAILURE (Status))
414         {
415             return (Status);
416         }
417     }
418 
419     return (AE_OK);
420 }
421 
422 
423 /******************************************************************************
424  *
425  * FUNCTION:    AcpiHwEnableWakeupGpeBlock
426  *
427  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
428  *              GpeBlock            - Gpe Block info
429  *
430  * RETURN:      Status
431  *
432  * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
433  *              combination wake/run GPEs.
434  *
435  ******************************************************************************/
436 
437 static ACPI_STATUS
438 AcpiHwEnableWakeupGpeBlock (
439     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
440     ACPI_GPE_BLOCK_INFO     *GpeBlock,
441     void                    *Context)
442 {
443     UINT32                  i;
444     ACPI_STATUS             Status;
445 
446 
447     /* Examine each GPE Register within the block */
448 
449     for (i = 0; i < GpeBlock->RegisterCount; i++)
450     {
451         if (!GpeBlock->RegisterInfo[i].EnableForWake)
452         {
453             continue;
454         }
455 
456         /* Enable all "wake" GPEs in this register */
457 
458         Status = AcpiHwWrite (GpeBlock->RegisterInfo[i].EnableForWake,
459                     &GpeBlock->RegisterInfo[i].EnableAddress);
460         if (ACPI_FAILURE (Status))
461         {
462             return (Status);
463         }
464     }
465 
466     return (AE_OK);
467 }
468 
469 
470 /******************************************************************************
471  *
472  * FUNCTION:    AcpiHwDisableAllGpes
473  *
474  * PARAMETERS:  None
475  *
476  * RETURN:      Status
477  *
478  * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
479  *
480  ******************************************************************************/
481 
482 ACPI_STATUS
483 AcpiHwDisableAllGpes (
484     void)
485 {
486     ACPI_STATUS             Status;
487 
488 
489     ACPI_FUNCTION_TRACE (HwDisableAllGpes);
490 
491 
492     Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL);
493     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
494     return_ACPI_STATUS (Status);
495 }
496 
497 
498 /******************************************************************************
499  *
500  * FUNCTION:    AcpiHwEnableAllRuntimeGpes
501  *
502  * PARAMETERS:  None
503  *
504  * RETURN:      Status
505  *
506  * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
507  *
508  ******************************************************************************/
509 
510 ACPI_STATUS
511 AcpiHwEnableAllRuntimeGpes (
512     void)
513 {
514     ACPI_STATUS             Status;
515 
516 
517     ACPI_FUNCTION_TRACE (HwEnableAllRuntimeGpes);
518 
519 
520     Status = AcpiEvWalkGpeList (AcpiHwEnableRuntimeGpeBlock, NULL);
521     return_ACPI_STATUS (Status);
522 }
523 
524 
525 /******************************************************************************
526  *
527  * FUNCTION:    AcpiHwEnableAllWakeupGpes
528  *
529  * PARAMETERS:  None
530  *
531  * RETURN:      Status
532  *
533  * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
534  *
535  ******************************************************************************/
536 
537 ACPI_STATUS
538 AcpiHwEnableAllWakeupGpes (
539     void)
540 {
541     ACPI_STATUS             Status;
542 
543 
544     ACPI_FUNCTION_TRACE (HwEnableAllWakeupGpes);
545 
546 
547     Status = AcpiEvWalkGpeList (AcpiHwEnableWakeupGpeBlock, NULL);
548     return_ACPI_STATUS (Status);
549 }
550 
551 #endif /* !ACPI_REDUCED_HARDWARE */
552