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 <acpi/acpi.h> 45 #include "accommon.h" 46 #include "acevents.h" 47 48 #define _COMPONENT ACPI_HARDWARE 49 ACPI_MODULE_NAME("hwgpe") 50 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 51 /* Local prototypes */ 52 static acpi_status 53 acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 54 struct acpi_gpe_block_info *gpe_block, 55 void *context); 56 57 static acpi_status 58 acpi_hw_gpe_enable_write(u8 enable_mask, 59 struct acpi_gpe_register_info *gpe_register_info); 60 61 /****************************************************************************** 62 * 63 * FUNCTION: acpi_hw_get_gpe_register_bit 64 * 65 * PARAMETERS: gpe_event_info - Info block for the GPE 66 * 67 * RETURN: Register mask with a one in the GPE bit position 68 * 69 * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the 70 * correct position for the input GPE. 71 * 72 ******************************************************************************/ 73 74 u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info) 75 { 76 77 return ((u32)1 << 78 (gpe_event_info->gpe_number - 79 gpe_event_info->register_info->base_gpe_number)); 80 } 81 82 /****************************************************************************** 83 * 84 * FUNCTION: acpi_hw_low_set_gpe 85 * 86 * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled 87 * action - Enable or disable 88 * 89 * RETURN: Status 90 * 91 * DESCRIPTION: Enable or disable a single GPE in the parent enable register. 92 * 93 ******************************************************************************/ 94 95 acpi_status 96 acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) 97 { 98 struct acpi_gpe_register_info *gpe_register_info; 99 acpi_status status; 100 u32 enable_mask; 101 u32 register_bit; 102 103 ACPI_FUNCTION_ENTRY(); 104 105 /* Get the info block for the entire GPE register */ 106 107 gpe_register_info = gpe_event_info->register_info; 108 if (!gpe_register_info) { 109 return (AE_NOT_EXIST); 110 } 111 112 /* Get current value of the enable register that contains this GPE */ 113 114 status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address); 115 if (ACPI_FAILURE(status)) { 116 return (status); 117 } 118 119 /* Set or clear just the bit that corresponds to this GPE */ 120 121 register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); 122 switch (action & ~ACPI_GPE_SAVE_MASK) { 123 case ACPI_GPE_CONDITIONAL_ENABLE: 124 125 /* Only enable if the corresponding enable_mask bit is set */ 126 127 if (!(register_bit & gpe_register_info->enable_mask)) { 128 return (AE_BAD_PARAMETER); 129 } 130 131 /*lint -fallthrough */ 132 133 case ACPI_GPE_ENABLE: 134 135 ACPI_SET_BIT(enable_mask, register_bit); 136 break; 137 138 case ACPI_GPE_DISABLE: 139 140 ACPI_CLEAR_BIT(enable_mask, register_bit); 141 break; 142 143 default: 144 145 ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action)); 146 return (AE_BAD_PARAMETER); 147 } 148 149 /* Write the updated enable mask */ 150 151 status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); 152 if (ACPI_SUCCESS(status) && (action & ACPI_GPE_SAVE_MASK)) { 153 gpe_register_info->enable_mask = (u8)enable_mask; 154 } 155 return (status); 156 } 157 158 /****************************************************************************** 159 * 160 * FUNCTION: acpi_hw_clear_gpe 161 * 162 * PARAMETERS: gpe_event_info - Info block for the GPE to be cleared 163 * 164 * RETURN: Status 165 * 166 * DESCRIPTION: Clear the status bit for a single GPE. 167 * 168 ******************************************************************************/ 169 170 acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) 171 { 172 struct acpi_gpe_register_info *gpe_register_info; 173 acpi_status status; 174 u32 register_bit; 175 176 ACPI_FUNCTION_ENTRY(); 177 178 /* Get the info block for the entire GPE register */ 179 180 gpe_register_info = gpe_event_info->register_info; 181 if (!gpe_register_info) { 182 return (AE_NOT_EXIST); 183 } 184 185 /* 186 * Write a one to the appropriate bit in the status register to 187 * clear this GPE. 188 */ 189 register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); 190 191 status = acpi_hw_write(register_bit, 192 &gpe_register_info->status_address); 193 194 return (status); 195 } 196 197 /****************************************************************************** 198 * 199 * FUNCTION: acpi_hw_get_gpe_status 200 * 201 * PARAMETERS: gpe_event_info - Info block for the GPE to queried 202 * event_status - Where the GPE status is returned 203 * 204 * RETURN: Status 205 * 206 * DESCRIPTION: Return the status of a single GPE. 207 * 208 ******************************************************************************/ 209 210 acpi_status 211 acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, 212 acpi_event_status *event_status) 213 { 214 u32 in_byte; 215 u32 register_bit; 216 struct acpi_gpe_register_info *gpe_register_info; 217 acpi_event_status local_event_status = 0; 218 acpi_status status; 219 220 ACPI_FUNCTION_ENTRY(); 221 222 if (!event_status) { 223 return (AE_BAD_PARAMETER); 224 } 225 226 /* GPE currently handled? */ 227 228 if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != 229 ACPI_GPE_DISPATCH_NONE) { 230 local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER; 231 } 232 233 /* Get the info block for the entire GPE register */ 234 235 gpe_register_info = gpe_event_info->register_info; 236 237 /* Get the register bitmask for this GPE */ 238 239 register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); 240 241 /* GPE currently enabled? (enabled for runtime?) */ 242 243 if (register_bit & gpe_register_info->enable_for_run) { 244 local_event_status |= ACPI_EVENT_FLAG_ENABLED; 245 } 246 247 /* GPE enabled for wake? */ 248 249 if (register_bit & gpe_register_info->enable_for_wake) { 250 local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED; 251 } 252 253 /* GPE currently active (status bit == 1)? */ 254 255 status = acpi_hw_read(&in_byte, &gpe_register_info->status_address); 256 if (ACPI_FAILURE(status)) { 257 return (status); 258 } 259 260 if (register_bit & in_byte) { 261 local_event_status |= ACPI_EVENT_FLAG_SET; 262 } 263 264 /* Set return value */ 265 266 (*event_status) = local_event_status; 267 return (AE_OK); 268 } 269 270 /****************************************************************************** 271 * 272 * FUNCTION: acpi_hw_gpe_enable_write 273 * 274 * PARAMETERS: enable_mask - Bit mask to write to the GPE register 275 * gpe_register_info - Gpe Register info 276 * 277 * RETURN: Status 278 * 279 * DESCRIPTION: Write the enable mask byte to the given GPE register. 280 * 281 ******************************************************************************/ 282 283 static acpi_status 284 acpi_hw_gpe_enable_write(u8 enable_mask, 285 struct acpi_gpe_register_info *gpe_register_info) 286 { 287 acpi_status status; 288 289 status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); 290 if (ACPI_SUCCESS(status)) { 291 gpe_register_info->enable_mask = enable_mask; 292 } 293 return (status); 294 } 295 296 /****************************************************************************** 297 * 298 * FUNCTION: acpi_hw_disable_gpe_block 299 * 300 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info 301 * gpe_block - Gpe Block info 302 * 303 * RETURN: Status 304 * 305 * DESCRIPTION: Disable all GPEs within a single GPE block 306 * 307 ******************************************************************************/ 308 309 acpi_status 310 acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 311 struct acpi_gpe_block_info *gpe_block, void *context) 312 { 313 u32 i; 314 acpi_status status; 315 316 /* Examine each GPE Register within the block */ 317 318 for (i = 0; i < gpe_block->register_count; i++) { 319 320 /* Disable all GPEs in this register */ 321 322 status = 323 acpi_hw_gpe_enable_write(0x00, 324 &gpe_block->register_info[i]); 325 if (ACPI_FAILURE(status)) { 326 return (status); 327 } 328 } 329 330 return (AE_OK); 331 } 332 333 /****************************************************************************** 334 * 335 * FUNCTION: acpi_hw_clear_gpe_block 336 * 337 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info 338 * gpe_block - Gpe Block info 339 * 340 * RETURN: Status 341 * 342 * DESCRIPTION: Clear status bits for all GPEs within a single GPE block 343 * 344 ******************************************************************************/ 345 346 acpi_status 347 acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 348 struct acpi_gpe_block_info *gpe_block, void *context) 349 { 350 u32 i; 351 acpi_status status; 352 353 /* Examine each GPE Register within the block */ 354 355 for (i = 0; i < gpe_block->register_count; i++) { 356 357 /* Clear status on all GPEs in this register */ 358 359 status = 360 acpi_hw_write(0xFF, 361 &gpe_block->register_info[i].status_address); 362 if (ACPI_FAILURE(status)) { 363 return (status); 364 } 365 } 366 367 return (AE_OK); 368 } 369 370 /****************************************************************************** 371 * 372 * FUNCTION: acpi_hw_enable_runtime_gpe_block 373 * 374 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info 375 * gpe_block - Gpe Block info 376 * 377 * RETURN: Status 378 * 379 * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes 380 * combination wake/run GPEs. 381 * 382 ******************************************************************************/ 383 384 acpi_status 385 acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 386 struct acpi_gpe_block_info * gpe_block, 387 void *context) 388 { 389 u32 i; 390 acpi_status status; 391 struct acpi_gpe_register_info *gpe_register_info; 392 393 /* NOTE: assumes that all GPEs are currently disabled */ 394 395 /* Examine each GPE Register within the block */ 396 397 for (i = 0; i < gpe_block->register_count; i++) { 398 gpe_register_info = &gpe_block->register_info[i]; 399 if (!gpe_register_info->enable_for_run) { 400 continue; 401 } 402 403 /* Enable all "runtime" GPEs in this register */ 404 405 status = 406 acpi_hw_gpe_enable_write(gpe_register_info->enable_for_run, 407 gpe_register_info); 408 if (ACPI_FAILURE(status)) { 409 return (status); 410 } 411 } 412 413 return (AE_OK); 414 } 415 416 /****************************************************************************** 417 * 418 * FUNCTION: acpi_hw_enable_wakeup_gpe_block 419 * 420 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info 421 * gpe_block - Gpe Block info 422 * 423 * RETURN: Status 424 * 425 * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes 426 * combination wake/run GPEs. 427 * 428 ******************************************************************************/ 429 430 static acpi_status 431 acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 432 struct acpi_gpe_block_info *gpe_block, 433 void *context) 434 { 435 u32 i; 436 acpi_status status; 437 struct acpi_gpe_register_info *gpe_register_info; 438 439 /* Examine each GPE Register within the block */ 440 441 for (i = 0; i < gpe_block->register_count; i++) { 442 gpe_register_info = &gpe_block->register_info[i]; 443 444 /* 445 * Enable all "wake" GPEs in this register and disable the 446 * remaining ones. 447 */ 448 449 status = 450 acpi_hw_gpe_enable_write(gpe_register_info->enable_for_wake, 451 gpe_register_info); 452 if (ACPI_FAILURE(status)) { 453 return (status); 454 } 455 } 456 457 return (AE_OK); 458 } 459 460 /****************************************************************************** 461 * 462 * FUNCTION: acpi_hw_disable_all_gpes 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 acpi_hw_disable_all_gpes(void) 473 { 474 acpi_status status; 475 476 ACPI_FUNCTION_TRACE(hw_disable_all_gpes); 477 478 status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); 479 status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); 480 return_ACPI_STATUS(status); 481 } 482 483 /****************************************************************************** 484 * 485 * FUNCTION: acpi_hw_enable_all_runtime_gpes 486 * 487 * PARAMETERS: None 488 * 489 * RETURN: Status 490 * 491 * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks 492 * 493 ******************************************************************************/ 494 495 acpi_status acpi_hw_enable_all_runtime_gpes(void) 496 { 497 acpi_status status; 498 499 ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes); 500 501 status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block, NULL); 502 return_ACPI_STATUS(status); 503 } 504 505 /****************************************************************************** 506 * 507 * FUNCTION: acpi_hw_enable_all_wakeup_gpes 508 * 509 * PARAMETERS: None 510 * 511 * RETURN: Status 512 * 513 * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks 514 * 515 ******************************************************************************/ 516 517 acpi_status acpi_hw_enable_all_wakeup_gpes(void) 518 { 519 acpi_status status; 520 521 ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes); 522 523 status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL); 524 return_ACPI_STATUS(status); 525 } 526 527 #endif /* !ACPI_REDUCED_HARDWARE */ 528