1
2/******************************************************************************
3 *
4 * Module Name: hwgpe - Low level GPE enable/disable/clear functions
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2011, 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/* Local prototypes */
53
54static ACPI_STATUS
55AcpiHwEnableWakeupGpeBlock (
56    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
57    ACPI_GPE_BLOCK_INFO     *GpeBlock,
58    void                    *Context);
59
60
61/******************************************************************************
62 *
63 * FUNCTION:    AcpiHwGetGpeRegisterBit
64 *
65 * PARAMETERS:  GpeEventInfo        - Info block for the GPE
66 *              GpeRegisterInfo     - Info block for the GPE register
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
75UINT32
76AcpiHwGetGpeRegisterBit (
77    ACPI_GPE_EVENT_INFO     *GpeEventInfo,
78    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo)
79{
80
81    return ((UINT32) 1 <<
82        (GpeEventInfo->GpeNumber - GpeRegisterInfo->BaseGpeNumber));
83}
84
85
86/******************************************************************************
87 *
88 * FUNCTION:    AcpiHwLowSetGpe
89 *
90 * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be disabled
91 *              Action              - Enable or disable
92 *
93 * RETURN:      Status
94 *
95 * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
96 *
97 ******************************************************************************/
98
99ACPI_STATUS
100AcpiHwLowSetGpe (
101    ACPI_GPE_EVENT_INFO     *GpeEventInfo,
102    UINT32                  Action)
103{
104    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
105    ACPI_STATUS             Status;
106    UINT32                  EnableMask;
107    UINT32                  RegisterBit;
108
109
110    ACPI_FUNCTION_ENTRY ();
111
112
113    /* Get the info block for the entire GPE register */
114
115    GpeRegisterInfo = GpeEventInfo->RegisterInfo;
116    if (!GpeRegisterInfo)
117    {
118        return (AE_NOT_EXIST);
119    }
120
121    /* Get current value of the enable register that contains this GPE */
122
123    Status = AcpiHwRead (&EnableMask, &GpeRegisterInfo->EnableAddress);
124    if (ACPI_FAILURE (Status))
125    {
126        return (Status);
127    }
128
129    /* Set or clear just the bit that corresponds to this GPE */
130
131    RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo, GpeRegisterInfo);
132    switch (Action)
133    {
134    case ACPI_GPE_CONDITIONAL_ENABLE:
135
136        /* Only enable if the EnableForRun bit is set */
137
138        if (!(RegisterBit & GpeRegisterInfo->EnableForRun))
139        {
140            return (AE_BAD_PARAMETER);
141        }
142
143        /*lint -fallthrough */
144
145    case ACPI_GPE_ENABLE:
146        ACPI_SET_BIT (EnableMask, RegisterBit);
147        break;
148
149    case ACPI_GPE_DISABLE:
150        ACPI_CLEAR_BIT (EnableMask, RegisterBit);
151        break;
152
153    default:
154        ACPI_ERROR ((AE_INFO, "Invalid GPE Action, %u\n", Action));
155        return (AE_BAD_PARAMETER);
156    }
157
158    /* Write the updated enable mask */
159
160    Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);
161    return (Status);
162}
163
164
165/******************************************************************************
166 *
167 * FUNCTION:    AcpiHwClearGpe
168 *
169 * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be cleared
170 *
171 * RETURN:      Status
172 *
173 * DESCRIPTION: Clear the status bit for a single GPE.
174 *
175 ******************************************************************************/
176
177ACPI_STATUS
178AcpiHwClearGpe (
179    ACPI_GPE_EVENT_INFO     *GpeEventInfo)
180{
181    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
182    ACPI_STATUS             Status;
183    UINT32                  RegisterBit;
184
185
186    ACPI_FUNCTION_ENTRY ();
187
188    /* Get the info block for the entire GPE register */
189
190    GpeRegisterInfo = GpeEventInfo->RegisterInfo;
191    if (!GpeRegisterInfo)
192    {
193        return (AE_NOT_EXIST);
194    }
195
196    /*
197     * Write a one to the appropriate bit in the status register to
198     * clear this GPE.
199     */
200    RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo, GpeRegisterInfo);
201
202    Status = AcpiHwWrite (RegisterBit,
203                    &GpeRegisterInfo->StatusAddress);
204
205    return (Status);
206}
207
208
209/******************************************************************************
210 *
211 * FUNCTION:    AcpiHwGetGpeStatus
212 *
213 * PARAMETERS:  GpeEventInfo        - Info block for the GPE to queried
214 *              EventStatus         - Where the GPE status is returned
215 *
216 * RETURN:      Status
217 *
218 * DESCRIPTION: Return the status of a single GPE.
219 *
220 ******************************************************************************/
221
222ACPI_STATUS
223AcpiHwGetGpeStatus (
224    ACPI_GPE_EVENT_INFO     *GpeEventInfo,
225    ACPI_EVENT_STATUS       *EventStatus)
226{
227    UINT32                  InByte;
228    UINT32                  RegisterBit;
229    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
230    ACPI_EVENT_STATUS       LocalEventStatus = 0;
231    ACPI_STATUS             Status;
232
233
234    ACPI_FUNCTION_ENTRY ();
235
236
237    if (!EventStatus)
238    {
239        return (AE_BAD_PARAMETER);
240    }
241
242    /* Get the info block for the entire GPE register */
243
244    GpeRegisterInfo = GpeEventInfo->RegisterInfo;
245
246    /* Get the register bitmask for this GPE */
247
248    RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo, GpeRegisterInfo);
249
250    /* GPE currently enabled? (enabled for runtime?) */
251
252    if (RegisterBit & GpeRegisterInfo->EnableForRun)
253    {
254        LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED;
255    }
256
257    /* GPE enabled for wake? */
258
259    if (RegisterBit & GpeRegisterInfo->EnableForWake)
260    {
261        LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED;
262    }
263
264    /* GPE currently active (status bit == 1)? */
265
266    Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress);
267    if (ACPI_FAILURE (Status))
268    {
269        return (Status);
270    }
271
272    if (RegisterBit & InByte)
273    {
274        LocalEventStatus |= ACPI_EVENT_FLAG_SET;
275    }
276
277    /* Set return value */
278
279    (*EventStatus) = LocalEventStatus;
280    return (AE_OK);
281}
282
283
284/******************************************************************************
285 *
286 * FUNCTION:    AcpiHwDisableGpeBlock
287 *
288 * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
289 *              GpeBlock            - Gpe Block info
290 *
291 * RETURN:      Status
292 *
293 * DESCRIPTION: Disable all GPEs within a single GPE block
294 *
295 ******************************************************************************/
296
297ACPI_STATUS
298AcpiHwDisableGpeBlock (
299    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
300    ACPI_GPE_BLOCK_INFO     *GpeBlock,
301    void                    *Context)
302{
303    UINT32                  i;
304    ACPI_STATUS             Status;
305
306
307    /* Examine each GPE Register within the block */
308
309    for (i = 0; i < GpeBlock->RegisterCount; i++)
310    {
311        /* Disable all GPEs in this register */
312
313        Status = AcpiHwWrite (0x00, &GpeBlock->RegisterInfo[i].EnableAddress);
314        if (ACPI_FAILURE (Status))
315        {
316            return (Status);
317        }
318    }
319
320    return (AE_OK);
321}
322
323
324/******************************************************************************
325 *
326 * FUNCTION:    AcpiHwClearGpeBlock
327 *
328 * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
329 *              GpeBlock            - Gpe Block info
330 *
331 * RETURN:      Status
332 *
333 * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
334 *
335 ******************************************************************************/
336
337ACPI_STATUS
338AcpiHwClearGpeBlock (
339    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
340    ACPI_GPE_BLOCK_INFO     *GpeBlock,
341    void                    *Context)
342{
343    UINT32                  i;
344    ACPI_STATUS             Status;
345
346
347    /* Examine each GPE Register within the block */
348
349    for (i = 0; i < GpeBlock->RegisterCount; i++)
350    {
351        /* Clear status on all GPEs in this register */
352
353        Status = AcpiHwWrite (0xFF, &GpeBlock->RegisterInfo[i].StatusAddress);
354        if (ACPI_FAILURE (Status))
355        {
356            return (Status);
357        }
358    }
359
360    return (AE_OK);
361}
362
363
364/******************************************************************************
365 *
366 * FUNCTION:    AcpiHwEnableRuntimeGpeBlock
367 *
368 * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
369 *              GpeBlock            - Gpe Block info
370 *
371 * RETURN:      Status
372 *
373 * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
374 *              combination wake/run GPEs.
375 *
376 ******************************************************************************/
377
378ACPI_STATUS
379AcpiHwEnableRuntimeGpeBlock (
380    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
381    ACPI_GPE_BLOCK_INFO     *GpeBlock,
382    void                    *Context)
383{
384    UINT32                  i;
385    ACPI_STATUS             Status;
386
387
388    /* NOTE: assumes that all GPEs are currently disabled */
389
390    /* Examine each GPE Register within the block */
391
392    for (i = 0; i < GpeBlock->RegisterCount; i++)
393    {
394        if (!GpeBlock->RegisterInfo[i].EnableForRun)
395        {
396            continue;
397        }
398
399        /* Enable all "runtime" GPEs in this register */
400
401        Status = AcpiHwWrite (GpeBlock->RegisterInfo[i].EnableForRun,
402                    &GpeBlock->RegisterInfo[i].EnableAddress);
403        if (ACPI_FAILURE (Status))
404        {
405            return (Status);
406        }
407    }
408
409    return (AE_OK);
410}
411
412
413/******************************************************************************
414 *
415 * FUNCTION:    AcpiHwEnableWakeupGpeBlock
416 *
417 * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
418 *              GpeBlock            - Gpe Block info
419 *
420 * RETURN:      Status
421 *
422 * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
423 *              combination wake/run GPEs.
424 *
425 ******************************************************************************/
426
427static ACPI_STATUS
428AcpiHwEnableWakeupGpeBlock (
429    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
430    ACPI_GPE_BLOCK_INFO     *GpeBlock,
431    void                    *Context)
432{
433    UINT32                  i;
434    ACPI_STATUS             Status;
435
436
437    /* Examine each GPE Register within the block */
438
439    for (i = 0; i < GpeBlock->RegisterCount; i++)
440    {
441        if (!GpeBlock->RegisterInfo[i].EnableForWake)
442        {
443            continue;
444        }
445
446        /* Enable all "wake" GPEs in this register */
447
448        Status = AcpiHwWrite (GpeBlock->RegisterInfo[i].EnableForWake,
449                    &GpeBlock->RegisterInfo[i].EnableAddress);
450        if (ACPI_FAILURE (Status))
451        {
452            return (Status);
453        }
454    }
455
456    return (AE_OK);
457}
458
459
460/******************************************************************************
461 *
462 * FUNCTION:    AcpiHwDisableAllGpes
463 *
464 * PARAMETERS:  None
465 *
466 * RETURN:      Status
467 *
468 * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
469 *
470 ******************************************************************************/
471
472ACPI_STATUS
473AcpiHwDisableAllGpes (
474    void)
475{
476    ACPI_STATUS             Status;
477
478
479    ACPI_FUNCTION_TRACE (HwDisableAllGpes);
480
481
482    Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL);
483    Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
484    return_ACPI_STATUS (Status);
485}
486
487
488/******************************************************************************
489 *
490 * FUNCTION:    AcpiHwEnableAllRuntimeGpes
491 *
492 * PARAMETERS:  None
493 *
494 * RETURN:      Status
495 *
496 * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
497 *
498 ******************************************************************************/
499
500ACPI_STATUS
501AcpiHwEnableAllRuntimeGpes (
502    void)
503{
504    ACPI_STATUS             Status;
505
506
507    ACPI_FUNCTION_TRACE (HwEnableAllRuntimeGpes);
508
509
510    Status = AcpiEvWalkGpeList (AcpiHwEnableRuntimeGpeBlock, NULL);
511    return_ACPI_STATUS (Status);
512}
513
514
515/******************************************************************************
516 *
517 * FUNCTION:    AcpiHwEnableAllWakeupGpes
518 *
519 * PARAMETERS:  None
520 *
521 * RETURN:      Status
522 *
523 * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
524 *
525 ******************************************************************************/
526
527ACPI_STATUS
528AcpiHwEnableAllWakeupGpes (
529    void)
530{
531    ACPI_STATUS             Status;
532
533
534    ACPI_FUNCTION_TRACE (HwEnableAllWakeupGpes);
535
536
537    Status = AcpiEvWalkGpeList (AcpiHwEnableWakeupGpeBlock, NULL);
538    return_ACPI_STATUS (Status);
539}
540
541