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 "acpi.h"
  46 #include "accommon.h"
  47 #include "acevents.h"
  48 
  49 #define _COMPONENT          ACPI_HARDWARE
  50         ACPI_MODULE_NAME    ("hwgpe")
  51 
  52 /* Local prototypes */
  53 
  54 static ACPI_STATUS
  55 AcpiHwEnableWakeupGpeBlock (
  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 
  75 UINT32
  76 AcpiHwGetGpeRegisterBit (
  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 
  99 ACPI_STATUS
 100 AcpiHwLowSetGpe (
 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 
 177 ACPI_STATUS
 178 AcpiHwClearGpe (
 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 
 222 ACPI_STATUS
 223 AcpiHwGetGpeStatus (
 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 
 297 ACPI_STATUS
 298 AcpiHwDisableGpeBlock (
 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 
 337 ACPI_STATUS
 338 AcpiHwClearGpeBlock (
 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 
 378 ACPI_STATUS
 379 AcpiHwEnableRuntimeGpeBlock (
 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 
 427 static ACPI_STATUS
 428 AcpiHwEnableWakeupGpeBlock (
 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 
 472 ACPI_STATUS
 473 AcpiHwDisableAllGpes (
 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 
 500 ACPI_STATUS
 501 AcpiHwEnableAllRuntimeGpes (
 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 
 527 ACPI_STATUS
 528 AcpiHwEnableAllWakeupGpes (
 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