1 /******************************************************************************
   2  *
   3  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2014, 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 "acpi.h"
  45 #include "accommon.h"
  46 #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 
  55 static ACPI_STATUS
  56 AcpiHwEnableWakeupGpeBlock (
  57     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
  58     ACPI_GPE_BLOCK_INFO     *GpeBlock,
  59     void                    *Context);
  60 
  61 
  62 /******************************************************************************
  63  *
  64  * FUNCTION:    AcpiHwGetGpeRegisterBit
  65  *
  66  * PARAMETERS:  GpeEventInfo        - Info block for the GPE
  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 {
  79 
  80     return ((UINT32) 1 <<
  81         (GpeEventInfo->GpeNumber - GpeEventInfo->RegisterInfo->BaseGpeNumber));
  82 }
  83 
  84 
  85 /******************************************************************************
  86  *
  87  * FUNCTION:    AcpiHwLowSetGpe
  88  *
  89  * PARAMETERS:  GpeEventInfo        - Info block for the GPE to be disabled
  90  *              Action              - Enable or disable
  91  *
  92  * RETURN:      Status
  93  *
  94  * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
  95  *
  96  ******************************************************************************/
  97 
  98 ACPI_STATUS
  99 AcpiHwLowSetGpe (
 100     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
 101     UINT32                  Action)
 102 {
 103     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
 104     ACPI_STATUS             Status;
 105     UINT32                  EnableMask;
 106     UINT32                  RegisterBit;
 107 
 108 
 109     ACPI_FUNCTION_ENTRY ();
 110 
 111 
 112     /* Get the info block for the entire GPE register */
 113 
 114     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
 115     if (!GpeRegisterInfo)
 116     {
 117         return (AE_NOT_EXIST);
 118     }
 119 
 120     /* Get current value of the enable register that contains this GPE */
 121 
 122     Status = AcpiHwRead (&EnableMask, &GpeRegisterInfo->EnableAddress);
 123     if (ACPI_FAILURE (Status))
 124     {
 125         return (Status);
 126     }
 127 
 128     /* Set or clear just the bit that corresponds to this GPE */
 129 
 130     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
 131     switch (Action)
 132     {
 133     case ACPI_GPE_CONDITIONAL_ENABLE:
 134 
 135         /* Only enable if the EnableForRun bit is set */
 136 
 137         if (!(RegisterBit & GpeRegisterInfo->EnableForRun))
 138         {
 139             return (AE_BAD_PARAMETER);
 140         }
 141 
 142         /*lint -fallthrough */
 143 
 144     case ACPI_GPE_ENABLE:
 145 
 146         ACPI_SET_BIT (EnableMask, RegisterBit);
 147         break;
 148 
 149     case ACPI_GPE_DISABLE:
 150 
 151         ACPI_CLEAR_BIT (EnableMask, RegisterBit);
 152         break;
 153 
 154     default:
 155 
 156         ACPI_ERROR ((AE_INFO, "Invalid GPE Action, %u", 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);
 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);
 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 */