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