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