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