hwgpe.c revision 284583
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
55static ACPI_STATUS
56AcpiHwEnableWakeupGpeBlock (
57    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
58    ACPI_GPE_BLOCK_INFO     *GpeBlock,
59    void                    *Context);
60
61static ACPI_STATUS
62AcpiHwGpeEnableWrite (
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
80UINT32
81AcpiHwGetGpeRegisterBit (
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
105ACPI_STATUS
106AcpiHwLowSetGpe (
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
186ACPI_STATUS
187AcpiHwClearGpe (
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
231ACPI_STATUS
232AcpiHwGetGpeStatus (
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
327static ACPI_STATUS
328AcpiHwGpeEnableWrite (
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
355ACPI_STATUS
356AcpiHwDisableGpeBlock (
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
395ACPI_STATUS
396AcpiHwClearGpeBlock (
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
436ACPI_STATUS
437AcpiHwEnableRuntimeGpeBlock (
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
487static ACPI_STATUS
488AcpiHwEnableWakeupGpeBlock (
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
532ACPI_STATUS
533AcpiHwDisableAllGpes (
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
560ACPI_STATUS
561AcpiHwEnableAllRuntimeGpes (
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
587ACPI_STATUS
588AcpiHwEnableAllWakeupGpes (
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