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