xref: /freebsd/sys/contrib/dev/acpica/components/hardware/hwgpe.c (revision e39e854e27f53a784c3982cbeb68f4ad1cfd9162)
1 
2 /******************************************************************************
3  *
4  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2012, Intel Corp.
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 <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <contrib/dev/acpica/include/acevents.h>
48 
49 #define _COMPONENT          ACPI_HARDWARE
50         ACPI_MODULE_NAME    ("hwgpe")
51 
52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53 
54 /* Local prototypes */
55 
56 static ACPI_STATUS
57 AcpiHwEnableWakeupGpeBlock (
58     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
59     ACPI_GPE_BLOCK_INFO     *GpeBlock,
60     void                    *Context);
61 
62 
63 /******************************************************************************
64  *
65  * FUNCTION:    AcpiHwGetGpeRegisterBit
66  *
67  * PARAMETERS:  GpeEventInfo        - Info block for the GPE
68  *              GpeRegisterInfo     - Info block for the GPE register
69  *
70  * RETURN:      Register mask with a one in the GPE bit position
71  *
72  * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the
73  *              correct position for the input GPE.
74  *
75  ******************************************************************************/
76 
77 UINT32
78 AcpiHwGetGpeRegisterBit (
79     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
80     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo)
81 {
82 
83     return ((UINT32) 1 <<
84         (GpeEventInfo->GpeNumber - GpeRegisterInfo->BaseGpeNumber));
85 }
86 
87 
88 /******************************************************************************
89  *
90  * FUNCTION:    AcpiHwLowSetGpe
91  *
92  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be disabled
93  *              Action              - Enable or disable
94  *
95  * RETURN:      Status
96  *
97  * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
98  *
99  ******************************************************************************/
100 
101 ACPI_STATUS
102 AcpiHwLowSetGpe (
103     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
104     UINT32                  Action)
105 {
106     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
107     ACPI_STATUS             Status;
108     UINT32                  EnableMask;
109     UINT32                  RegisterBit;
110 
111 
112     ACPI_FUNCTION_ENTRY ();
113 
114 
115     /* Get the info block for the entire GPE register */
116 
117     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
118     if (!GpeRegisterInfo)
119     {
120         return (AE_NOT_EXIST);
121     }
122 
123     /* Get current value of the enable register that contains this GPE */
124 
125     Status = AcpiHwRead (&EnableMask, &GpeRegisterInfo->EnableAddress);
126     if (ACPI_FAILURE (Status))
127     {
128         return (Status);
129     }
130 
131     /* Set or clear just the bit that corresponds to this GPE */
132 
133     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo, GpeRegisterInfo);
134     switch (Action)
135     {
136     case ACPI_GPE_CONDITIONAL_ENABLE:
137 
138         /* Only enable if the EnableForRun bit is set */
139 
140         if (!(RegisterBit & GpeRegisterInfo->EnableForRun))
141         {
142             return (AE_BAD_PARAMETER);
143         }
144 
145         /*lint -fallthrough */
146 
147     case ACPI_GPE_ENABLE:
148         ACPI_SET_BIT (EnableMask, RegisterBit);
149         break;
150 
151     case ACPI_GPE_DISABLE:
152         ACPI_CLEAR_BIT (EnableMask, RegisterBit);
153         break;
154 
155     default:
156         ACPI_ERROR ((AE_INFO, "Invalid GPE Action, %u\n", 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, GpeRegisterInfo);
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, GpeRegisterInfo);
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