xref: /openbmc/linux/drivers/acpi/acpica/hwgpe.c (revision 05bcf503)
1 
2 /******************************************************************************
3  *
4  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2012, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 #include <acpi/acpi.h>
46 #include "accommon.h"
47 #include "acevents.h"
48 
49 #define _COMPONENT          ACPI_HARDWARE
50 ACPI_MODULE_NAME("hwgpe")
51 #if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
52 /* Local prototypes */
53 static acpi_status
54 acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
55 				struct acpi_gpe_block_info *gpe_block,
56 				void *context);
57 
58 /******************************************************************************
59  *
60  * FUNCTION:	acpi_hw_get_gpe_register_bit
61  *
62  * PARAMETERS:	gpe_event_info	    - Info block for the GPE
63  *
64  * RETURN:	Register mask with a one in the GPE bit position
65  *
66  * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the
67  *              correct position for the input GPE.
68  *
69  ******************************************************************************/
70 
71 u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info)
72 {
73 	return (u32)1 << (gpe_event_info->gpe_number -
74 		 gpe_event_info->register_info->base_gpe_number);
75 }
76 
77 /******************************************************************************
78  *
79  * FUNCTION:	acpi_hw_low_set_gpe
80  *
81  * PARAMETERS:	gpe_event_info	    - Info block for the GPE to be disabled
82  *		action		    - Enable or disable
83  *
84  * RETURN:	Status
85  *
86  * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
87  *
88  ******************************************************************************/
89 
90 acpi_status
91 acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
92 {
93 	struct acpi_gpe_register_info *gpe_register_info;
94 	acpi_status status;
95 	u32 enable_mask;
96 	u32 register_bit;
97 
98 	ACPI_FUNCTION_ENTRY();
99 
100 	/* Get the info block for the entire GPE register */
101 
102 	gpe_register_info = gpe_event_info->register_info;
103 	if (!gpe_register_info) {
104 		return (AE_NOT_EXIST);
105 	}
106 
107 	/* Get current value of the enable register that contains this GPE */
108 
109 	status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address);
110 	if (ACPI_FAILURE(status)) {
111 		return (status);
112 	}
113 
114 	/* Set or clear just the bit that corresponds to this GPE */
115 
116 	register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
117 	switch (action) {
118 	case ACPI_GPE_CONDITIONAL_ENABLE:
119 
120 		/* Only enable if the enable_for_run bit is set */
121 
122 		if (!(register_bit & gpe_register_info->enable_for_run)) {
123 			return (AE_BAD_PARAMETER);
124 		}
125 
126 		/*lint -fallthrough */
127 
128 	case ACPI_GPE_ENABLE:
129 		ACPI_SET_BIT(enable_mask, register_bit);
130 		break;
131 
132 	case ACPI_GPE_DISABLE:
133 		ACPI_CLEAR_BIT(enable_mask, register_bit);
134 		break;
135 
136 	default:
137 		ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u\n", action));
138 		return (AE_BAD_PARAMETER);
139 	}
140 
141 	/* Write the updated enable mask */
142 
143 	status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
144 	return (status);
145 }
146 
147 /******************************************************************************
148  *
149  * FUNCTION:    acpi_hw_clear_gpe
150  *
151  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be cleared
152  *
153  * RETURN:      Status
154  *
155  * DESCRIPTION: Clear the status bit for a single GPE.
156  *
157  ******************************************************************************/
158 
159 acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
160 {
161 	struct acpi_gpe_register_info *gpe_register_info;
162 	acpi_status status;
163 	u32 register_bit;
164 
165 	ACPI_FUNCTION_ENTRY();
166 
167 	/* Get the info block for the entire GPE register */
168 
169 	gpe_register_info = gpe_event_info->register_info;
170 	if (!gpe_register_info) {
171 		return (AE_NOT_EXIST);
172 	}
173 
174 	/*
175 	 * Write a one to the appropriate bit in the status register to
176 	 * clear this GPE.
177 	 */
178 	register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
179 
180 	status = acpi_hw_write(register_bit,
181 			       &gpe_register_info->status_address);
182 
183 	return (status);
184 }
185 
186 /******************************************************************************
187  *
188  * FUNCTION:    acpi_hw_get_gpe_status
189  *
190  * PARAMETERS:  gpe_event_info      - Info block for the GPE to queried
191  *              event_status        - Where the GPE status is returned
192  *
193  * RETURN:      Status
194  *
195  * DESCRIPTION: Return the status of a single GPE.
196  *
197  ******************************************************************************/
198 
199 acpi_status
200 acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
201 		       acpi_event_status * event_status)
202 {
203 	u32 in_byte;
204 	u32 register_bit;
205 	struct acpi_gpe_register_info *gpe_register_info;
206 	acpi_event_status local_event_status = 0;
207 	acpi_status status;
208 
209 	ACPI_FUNCTION_ENTRY();
210 
211 	if (!event_status) {
212 		return (AE_BAD_PARAMETER);
213 	}
214 
215 	/* Get the info block for the entire GPE register */
216 
217 	gpe_register_info = gpe_event_info->register_info;
218 
219 	/* Get the register bitmask for this GPE */
220 
221 	register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
222 
223 	/* GPE currently enabled? (enabled for runtime?) */
224 
225 	if (register_bit & gpe_register_info->enable_for_run) {
226 		local_event_status |= ACPI_EVENT_FLAG_ENABLED;
227 	}
228 
229 	/* GPE enabled for wake? */
230 
231 	if (register_bit & gpe_register_info->enable_for_wake) {
232 		local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED;
233 	}
234 
235 	/* GPE currently active (status bit == 1)? */
236 
237 	status = acpi_hw_read(&in_byte, &gpe_register_info->status_address);
238 	if (ACPI_FAILURE(status)) {
239 		return (status);
240 	}
241 
242 	if (register_bit & in_byte) {
243 		local_event_status |= ACPI_EVENT_FLAG_SET;
244 	}
245 
246 	/* Set return value */
247 
248 	(*event_status) = local_event_status;
249 	return (AE_OK);
250 }
251 
252 /******************************************************************************
253  *
254  * FUNCTION:    acpi_hw_disable_gpe_block
255  *
256  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
257  *              gpe_block           - Gpe Block info
258  *
259  * RETURN:      Status
260  *
261  * DESCRIPTION: Disable all GPEs within a single GPE block
262  *
263  ******************************************************************************/
264 
265 acpi_status
266 acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
267 			  struct acpi_gpe_block_info *gpe_block, void *context)
268 {
269 	u32 i;
270 	acpi_status status;
271 
272 	/* Examine each GPE Register within the block */
273 
274 	for (i = 0; i < gpe_block->register_count; i++) {
275 
276 		/* Disable all GPEs in this register */
277 
278 		status =
279 		    acpi_hw_write(0x00,
280 				  &gpe_block->register_info[i].enable_address);
281 		if (ACPI_FAILURE(status)) {
282 			return (status);
283 		}
284 	}
285 
286 	return (AE_OK);
287 }
288 
289 /******************************************************************************
290  *
291  * FUNCTION:    acpi_hw_clear_gpe_block
292  *
293  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
294  *              gpe_block           - Gpe Block info
295  *
296  * RETURN:      Status
297  *
298  * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
299  *
300  ******************************************************************************/
301 
302 acpi_status
303 acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
304 			struct acpi_gpe_block_info *gpe_block, void *context)
305 {
306 	u32 i;
307 	acpi_status status;
308 
309 	/* Examine each GPE Register within the block */
310 
311 	for (i = 0; i < gpe_block->register_count; i++) {
312 
313 		/* Clear status on all GPEs in this register */
314 
315 		status =
316 		    acpi_hw_write(0xFF,
317 				  &gpe_block->register_info[i].status_address);
318 		if (ACPI_FAILURE(status)) {
319 			return (status);
320 		}
321 	}
322 
323 	return (AE_OK);
324 }
325 
326 /******************************************************************************
327  *
328  * FUNCTION:    acpi_hw_enable_runtime_gpe_block
329  *
330  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
331  *              gpe_block           - Gpe Block info
332  *
333  * RETURN:      Status
334  *
335  * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
336  *              combination wake/run GPEs.
337  *
338  ******************************************************************************/
339 
340 acpi_status
341 acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
342 				 struct acpi_gpe_block_info *gpe_block, 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