xref: /openbmc/linux/drivers/acpi/acpica/hwgpe.c (revision d0b73b48)
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