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