Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: hwgpe - Low level GPE enable/disable/clear functions | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
fbb7a2dc | 8 | * Copyright (C) 2000 - 2014, Intel Corp. |
1da177e4 LT |
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> | |
e2f7a777 LB |
45 | #include "accommon.h" |
46 | #include "acevents.h" | |
1da177e4 LT |
47 | |
48 | #define _COMPONENT ACPI_HARDWARE | |
4be44fcd | 49 | ACPI_MODULE_NAME("hwgpe") |
33620c54 | 50 | #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
44f6c012 | 51 | /* Local prototypes */ |
44f6c012 | 52 | static acpi_status |
4be44fcd | 53 | acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
e97d6bf1 BM |
54 | struct acpi_gpe_block_info *gpe_block, |
55 | void *context); | |
1da177e4 | 56 | |
e4e9a735 RW |
57 | /****************************************************************************** |
58 | * | |
b76df673 | 59 | * FUNCTION: acpi_hw_get_gpe_register_bit |
e4e9a735 RW |
60 | * |
61 | * PARAMETERS: gpe_event_info - Info block for the GPE | |
e4e9a735 | 62 | * |
da503373 | 63 | * RETURN: Register mask with a one in the GPE bit position |
e4e9a735 | 64 | * |
da503373 LM |
65 | * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the |
66 | * correct position for the input GPE. | |
e4e9a735 RW |
67 | * |
68 | ******************************************************************************/ | |
69 | ||
1d94e1e8 | 70 | u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info) |
e4e9a735 | 71 | { |
9c0d7939 LZ |
72 | |
73 | return ((u32)1 << | |
74 | (gpe_event_info->gpe_number - | |
75 | gpe_event_info->register_info->base_gpe_number)); | |
e4e9a735 RW |
76 | } |
77 | ||
e38e8a07 BM |
78 | /****************************************************************************** |
79 | * | |
fd247447 | 80 | * FUNCTION: acpi_hw_low_set_gpe |
e38e8a07 BM |
81 | * |
82 | * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled | |
fd247447 | 83 | * action - Enable or disable |
e38e8a07 BM |
84 | * |
85 | * RETURN: Status | |
86 | * | |
da503373 | 87 | * DESCRIPTION: Enable or disable a single GPE in the parent enable register. |
e38e8a07 BM |
88 | * |
89 | ******************************************************************************/ | |
90 | ||
fd247447 | 91 | acpi_status |
da503373 | 92 | acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) |
e38e8a07 BM |
93 | { |
94 | struct acpi_gpe_register_info *gpe_register_info; | |
95 | acpi_status status; | |
96 | u32 enable_mask; | |
e4e9a735 | 97 | u32 register_bit; |
e38e8a07 | 98 | |
fd247447 RW |
99 | ACPI_FUNCTION_ENTRY(); |
100 | ||
e38e8a07 BM |
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 | ||
c6b5774c | 110 | status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address); |
e38e8a07 BM |
111 | if (ACPI_FAILURE(status)) { |
112 | return (status); | |
113 | } | |
114 | ||
da503373 | 115 | /* Set or clear just the bit that corresponds to this GPE */ |
e38e8a07 | 116 | |
1d94e1e8 | 117 | register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); |
fd247447 | 118 | switch (action) { |
3a37898d | 119 | case ACPI_GPE_CONDITIONAL_ENABLE: |
da503373 LM |
120 | |
121 | /* Only enable if the enable_for_run bit is set */ | |
122 | ||
123 | if (!(register_bit & gpe_register_info->enable_for_run)) { | |
c9a8bbb7 | 124 | return (AE_BAD_PARAMETER); |
da503373 LM |
125 | } |
126 | ||
127 | /*lint -fallthrough */ | |
c9a8bbb7 | 128 | |
fd247447 | 129 | case ACPI_GPE_ENABLE: |
1d1ea1b7 | 130 | |
fd247447 RW |
131 | ACPI_SET_BIT(enable_mask, register_bit); |
132 | break; | |
133 | ||
134 | case ACPI_GPE_DISABLE: | |
1d1ea1b7 | 135 | |
fd247447 RW |
136 | ACPI_CLEAR_BIT(enable_mask, register_bit); |
137 | break; | |
138 | ||
139 | default: | |
1d1ea1b7 | 140 | |
5e30a96e | 141 | ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action)); |
fd247447 RW |
142 | return (AE_BAD_PARAMETER); |
143 | } | |
e38e8a07 BM |
144 | |
145 | /* Write the updated enable mask */ | |
146 | ||
c6b5774c | 147 | status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); |
e38e8a07 BM |
148 | return (status); |
149 | } | |
150 | ||
1da177e4 LT |
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 | ||
4be44fcd | 163 | acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) |
1da177e4 | 164 | { |
e4e9a735 | 165 | struct acpi_gpe_register_info *gpe_register_info; |
4be44fcd | 166 | acpi_status status; |
e4e9a735 | 167 | u32 register_bit; |
1da177e4 | 168 | |
4be44fcd | 169 | ACPI_FUNCTION_ENTRY(); |
1da177e4 | 170 | |
e4e9a735 RW |
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 | ||
1da177e4 LT |
178 | /* |
179 | * Write a one to the appropriate bit in the status register to | |
180 | * clear this GPE. | |
181 | */ | |
1d94e1e8 | 182 | register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); |
da503373 | 183 | |
c6b5774c | 184 | status = acpi_hw_write(register_bit, |
e4e9a735 | 185 | &gpe_register_info->status_address); |
1da177e4 LT |
186 | |
187 | return (status); | |
188 | } | |
189 | ||
1da177e4 LT |
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 | ******************************************************************************/ | |
44f6c012 | 202 | |
1da177e4 | 203 | acpi_status |
4be44fcd LB |
204 | acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, |
205 | acpi_event_status * event_status) | |
1da177e4 | 206 | { |
4be44fcd | 207 | u32 in_byte; |
e4e9a735 | 208 | u32 register_bit; |
4be44fcd | 209 | struct acpi_gpe_register_info *gpe_register_info; |
4be44fcd | 210 | acpi_event_status local_event_status = 0; |
da503373 | 211 | acpi_status status; |
1da177e4 | 212 | |
4be44fcd | 213 | ACPI_FUNCTION_ENTRY(); |
1da177e4 LT |
214 | |
215 | if (!event_status) { | |
216 | return (AE_BAD_PARAMETER); | |
217 | } | |
218 | ||
219 | /* Get the info block for the entire GPE register */ | |
220 | ||
221 | gpe_register_info = gpe_event_info->register_info; | |
222 | ||
223 | /* Get the register bitmask for this GPE */ | |
224 | ||
1d94e1e8 | 225 | register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); |
1da177e4 LT |
226 | |
227 | /* GPE currently enabled? (enabled for runtime?) */ | |
228 | ||
229 | if (register_bit & gpe_register_info->enable_for_run) { | |
230 | local_event_status |= ACPI_EVENT_FLAG_ENABLED; | |
231 | } | |
232 | ||
233 | /* GPE enabled for wake? */ | |
234 | ||
235 | if (register_bit & gpe_register_info->enable_for_wake) { | |
236 | local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED; | |
237 | } | |
238 | ||
239 | /* GPE currently active (status bit == 1)? */ | |
240 | ||
c6b5774c | 241 | status = acpi_hw_read(&in_byte, &gpe_register_info->status_address); |
4be44fcd | 242 | if (ACPI_FAILURE(status)) { |
2147d3f0 | 243 | return (status); |
1da177e4 LT |
244 | } |
245 | ||
246 | if (register_bit & in_byte) { | |
247 | local_event_status |= ACPI_EVENT_FLAG_SET; | |
248 | } | |
249 | ||
250 | /* Set return value */ | |
251 | ||
252 | (*event_status) = local_event_status; | |
2147d3f0 | 253 | return (AE_OK); |
1da177e4 | 254 | } |
1da177e4 LT |
255 | |
256 | /****************************************************************************** | |
257 | * | |
258 | * FUNCTION: acpi_hw_disable_gpe_block | |
259 | * | |
260 | * PARAMETERS: gpe_xrupt_info - GPE Interrupt info | |
261 | * gpe_block - Gpe Block info | |
262 | * | |
263 | * RETURN: Status | |
264 | * | |
44f6c012 | 265 | * DESCRIPTION: Disable all GPEs within a single GPE block |
1da177e4 LT |
266 | * |
267 | ******************************************************************************/ | |
268 | ||
269 | acpi_status | |
e97d6bf1 BM |
270 | acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
271 | struct acpi_gpe_block_info *gpe_block, void *context) | |
1da177e4 | 272 | { |
4be44fcd LB |
273 | u32 i; |
274 | acpi_status status; | |
1da177e4 LT |
275 | |
276 | /* Examine each GPE Register within the block */ | |
277 | ||
278 | for (i = 0; i < gpe_block->register_count; i++) { | |
52fc0b02 | 279 | |
1da177e4 LT |
280 | /* Disable all GPEs in this register */ |
281 | ||
ecfbbc7b | 282 | status = |
c6b5774c BM |
283 | acpi_hw_write(0x00, |
284 | &gpe_block->register_info[i].enable_address); | |
4be44fcd | 285 | if (ACPI_FAILURE(status)) { |
1da177e4 LT |
286 | return (status); |
287 | } | |
288 | } | |
289 | ||
290 | return (AE_OK); | |
291 | } | |
292 | ||
1da177e4 LT |
293 | /****************************************************************************** |
294 | * | |
295 | * FUNCTION: acpi_hw_clear_gpe_block | |
296 | * | |
297 | * PARAMETERS: gpe_xrupt_info - GPE Interrupt info | |
298 | * gpe_block - Gpe Block info | |
299 | * | |
300 | * RETURN: Status | |
301 | * | |
44f6c012 | 302 | * DESCRIPTION: Clear status bits for all GPEs within a single GPE block |
1da177e4 LT |
303 | * |
304 | ******************************************************************************/ | |
305 | ||
306 | acpi_status | |
e97d6bf1 BM |
307 | acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
308 | struct acpi_gpe_block_info *gpe_block, void *context) | |
1da177e4 | 309 | { |
4be44fcd LB |
310 | u32 i; |
311 | acpi_status status; | |
1da177e4 LT |
312 | |
313 | /* Examine each GPE Register within the block */ | |
314 | ||
315 | for (i = 0; i < gpe_block->register_count; i++) { | |
52fc0b02 | 316 | |
1da177e4 LT |
317 | /* Clear status on all GPEs in this register */ |
318 | ||
ecfbbc7b | 319 | status = |
c6b5774c BM |
320 | acpi_hw_write(0xFF, |
321 | &gpe_block->register_info[i].status_address); | |
4be44fcd | 322 | if (ACPI_FAILURE(status)) { |
1da177e4 LT |
323 | return (status); |
324 | } | |
325 | } | |
326 | ||
327 | return (AE_OK); | |
328 | } | |
329 | ||
1da177e4 LT |
330 | /****************************************************************************** |
331 | * | |
332 | * FUNCTION: acpi_hw_enable_runtime_gpe_block | |
333 | * | |
334 | * PARAMETERS: gpe_xrupt_info - GPE Interrupt info | |
335 | * gpe_block - Gpe Block info | |
336 | * | |
337 | * RETURN: Status | |
338 | * | |
44f6c012 RM |
339 | * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes |
340 | * combination wake/run GPEs. | |
1da177e4 LT |
341 | * |
342 | ******************************************************************************/ | |
343 | ||
344 | acpi_status | |
e97d6bf1 | 345 | acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
1f86e8c1 LZ |
346 | struct acpi_gpe_block_info * gpe_block, |
347 | void *context) | |
1da177e4 | 348 | { |
4be44fcd LB |
349 | u32 i; |
350 | acpi_status status; | |
1da177e4 LT |
351 | |
352 | /* NOTE: assumes that all GPEs are currently disabled */ | |
353 | ||
354 | /* Examine each GPE Register within the block */ | |
355 | ||
356 | for (i = 0; i < gpe_block->register_count; i++) { | |
357 | if (!gpe_block->register_info[i].enable_for_run) { | |
358 | continue; | |
359 | } | |
360 | ||
361 | /* Enable all "runtime" GPEs in this register */ | |
362 | ||
c6b5774c BM |
363 | status = |
364 | acpi_hw_write(gpe_block->register_info[i].enable_for_run, | |
365 | &gpe_block->register_info[i].enable_address); | |
4be44fcd | 366 | if (ACPI_FAILURE(status)) { |
1da177e4 LT |
367 | return (status); |
368 | } | |
369 | } | |
370 | ||
371 | return (AE_OK); | |
372 | } | |
373 | ||
1da177e4 LT |
374 | /****************************************************************************** |
375 | * | |
376 | * FUNCTION: acpi_hw_enable_wakeup_gpe_block | |
377 | * | |
378 | * PARAMETERS: gpe_xrupt_info - GPE Interrupt info | |
379 | * gpe_block - Gpe Block info | |
380 | * | |
381 | * RETURN: Status | |
382 | * | |
44f6c012 RM |
383 | * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes |
384 | * combination wake/run GPEs. | |
1da177e4 LT |
385 | * |
386 | ******************************************************************************/ | |
387 | ||
44f6c012 | 388 | static acpi_status |
4be44fcd | 389 | acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
e97d6bf1 BM |
390 | struct acpi_gpe_block_info *gpe_block, |
391 | void *context) | |
1da177e4 | 392 | { |
4be44fcd LB |
393 | u32 i; |
394 | acpi_status status; | |
1da177e4 LT |
395 | |
396 | /* Examine each GPE Register within the block */ | |
397 | ||
398 | for (i = 0; i < gpe_block->register_count; i++) { | |
399 | if (!gpe_block->register_info[i].enable_for_wake) { | |
400 | continue; | |
401 | } | |
402 | ||
403 | /* Enable all "wake" GPEs in this register */ | |
404 | ||
c6b5774c BM |
405 | status = |
406 | acpi_hw_write(gpe_block->register_info[i].enable_for_wake, | |
407 | &gpe_block->register_info[i].enable_address); | |
4be44fcd | 408 | if (ACPI_FAILURE(status)) { |
1da177e4 LT |
409 | return (status); |
410 | } | |
411 | } | |
412 | ||
413 | return (AE_OK); | |
414 | } | |
415 | ||
1da177e4 LT |
416 | /****************************************************************************** |
417 | * | |
418 | * FUNCTION: acpi_hw_disable_all_gpes | |
419 | * | |
73459f73 | 420 | * PARAMETERS: None |
1da177e4 LT |
421 | * |
422 | * RETURN: Status | |
423 | * | |
44f6c012 | 424 | * DESCRIPTION: Disable and clear all GPEs in all GPE blocks |
1da177e4 LT |
425 | * |
426 | ******************************************************************************/ | |
427 | ||
4be44fcd | 428 | acpi_status acpi_hw_disable_all_gpes(void) |
1da177e4 | 429 | { |
4be44fcd | 430 | acpi_status status; |
1da177e4 | 431 | |
b229cf92 | 432 | ACPI_FUNCTION_TRACE(hw_disable_all_gpes); |
1da177e4 | 433 | |
e97d6bf1 BM |
434 | status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); |
435 | status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); | |
4be44fcd | 436 | return_ACPI_STATUS(status); |
1da177e4 LT |
437 | } |
438 | ||
1da177e4 LT |
439 | /****************************************************************************** |
440 | * | |
441 | * FUNCTION: acpi_hw_enable_all_runtime_gpes | |
442 | * | |
73459f73 | 443 | * PARAMETERS: None |
1da177e4 LT |
444 | * |
445 | * RETURN: Status | |
446 | * | |
44f6c012 | 447 | * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks |
1da177e4 LT |
448 | * |
449 | ******************************************************************************/ | |
450 | ||
4be44fcd | 451 | acpi_status acpi_hw_enable_all_runtime_gpes(void) |
1da177e4 | 452 | { |
4be44fcd | 453 | acpi_status status; |
1da177e4 | 454 | |
b229cf92 | 455 | ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes); |
1da177e4 | 456 | |
e97d6bf1 | 457 | status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block, NULL); |
4be44fcd | 458 | return_ACPI_STATUS(status); |
1da177e4 LT |
459 | } |
460 | ||
1da177e4 LT |
461 | /****************************************************************************** |
462 | * | |
463 | * FUNCTION: acpi_hw_enable_all_wakeup_gpes | |
464 | * | |
73459f73 | 465 | * PARAMETERS: None |
1da177e4 LT |
466 | * |
467 | * RETURN: Status | |
468 | * | |
44f6c012 | 469 | * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks |
1da177e4 LT |
470 | * |
471 | ******************************************************************************/ | |
472 | ||
4be44fcd | 473 | acpi_status acpi_hw_enable_all_wakeup_gpes(void) |
1da177e4 | 474 | { |
4be44fcd | 475 | acpi_status status; |
1da177e4 | 476 | |
b229cf92 | 477 | ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes); |
1da177e4 | 478 | |
e97d6bf1 | 479 | status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL); |
4be44fcd | 480 | return_ACPI_STATUS(status); |
1da177e4 | 481 | } |
33620c54 BM |
482 | |
483 | #endif /* !ACPI_REDUCED_HARDWARE */ |