2 /******************************************************************************
4 * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface
7 *****************************************************************************/
10 * Copyright (C) 2000, 2001 R. Byron Moore
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #define _COMPONENT ACPI_HARDWARE
33 MODULE_NAME ("hwacpi")
36 /******************************************************************************
38 * FUNCTION: Acpi_hw_initialize
44 * DESCRIPTION: Initialize and validate various ACPI registers
46 ******************************************************************************/
52 acpi_status status = AE_OK;
56 FUNCTION_TRACE ("Hw_initialize");
59 /* We must have the ACPI tables by the time we get here */
62 acpi_gbl_restore_acpi_chipset = FALSE;
64 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No FADT!\n"));
66 return_ACPI_STATUS (AE_NO_ACPI_TABLES);
69 /* Identify current ACPI/legacy mode */
71 switch (acpi_gbl_system_flags & SYS_MODES_MASK) {
74 acpi_gbl_original_mode = SYS_MODE_ACPI;
75 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "System supports ACPI mode only.\n"));
79 case (SYS_MODE_LEGACY):
81 acpi_gbl_original_mode = SYS_MODE_LEGACY;
82 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
83 "Tables loaded from buffer, hardware assumed to support LEGACY mode only.\n"));
87 case (SYS_MODE_ACPI | SYS_MODE_LEGACY):
89 if (acpi_hw_get_mode () == SYS_MODE_ACPI) {
90 acpi_gbl_original_mode = SYS_MODE_ACPI;
93 acpi_gbl_original_mode = SYS_MODE_LEGACY;
96 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
97 "System supports both ACPI and LEGACY modes.\n"));
99 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
100 "System is currently in %s mode.\n",
101 (acpi_gbl_original_mode == SYS_MODE_ACPI) ? "ACPI" : "LEGACY"));
106 if (acpi_gbl_system_flags & SYS_MODE_ACPI) {
107 /* Target system supports ACPI mode */
110 * The purpose of this code is to save the initial state
111 * of the ACPI event enable registers. An exit function will be
112 * registered which will restore this state when the application
113 * exits. The exit function will also clear all of the ACPI event
114 * status bits prior to restoring the original mode.
116 * The location of the PM1a_evt_blk enable registers is defined as the
117 * base of PM1a_evt_blk + DIV_2(PM1a_evt_blk_length). Since the spec further
118 * fully defines the PM1a_evt_blk to be a total of 4 bytes, the offset
119 * for the enable registers is always 2 from the base. It is hard
120 * coded here. If this changes in the spec, this code will need to
121 * be modified. The PM1b_evt_blk behaves as expected.
123 acpi_gbl_pm1_enable_register_save = (u16) acpi_hw_register_read (
124 ACPI_MTX_LOCK, PM1_EN);
128 * The GPEs behave similarly, except that the length of the register
129 * block is not fixed, so the buffer must be allocated with malloc
131 if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) &&
132 acpi_gbl_FADT->gpe0blk_len) {
133 /* GPE0 specified in FADT */
135 acpi_gbl_gpe0enable_register_save = ACPI_MEM_ALLOCATE (
136 DIV_2 (acpi_gbl_FADT->gpe0blk_len));
137 if (!acpi_gbl_gpe0enable_register_save) {
138 return_ACPI_STATUS (AE_NO_MEMORY);
141 /* Save state of GPE0 enable bits */
143 for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe0blk_len); index++) {
144 acpi_gbl_gpe0enable_register_save[index] =
145 (u8) acpi_hw_register_read (ACPI_MTX_LOCK, GPE0_EN_BLOCK | index);
150 acpi_gbl_gpe0enable_register_save = NULL;
153 if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) &&
154 acpi_gbl_FADT->gpe1_blk_len) {
157 acpi_gbl_gpe1_enable_register_save = ACPI_MEM_ALLOCATE (
158 DIV_2 (acpi_gbl_FADT->gpe1_blk_len));
159 if (!acpi_gbl_gpe1_enable_register_save) {
160 return_ACPI_STATUS (AE_NO_MEMORY);
163 /* save state of GPE1 enable bits */
165 for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe1_blk_len); index++) {
166 acpi_gbl_gpe1_enable_register_save[index] =
167 (u8) acpi_hw_register_read (ACPI_MTX_LOCK, GPE1_EN_BLOCK | index);
172 acpi_gbl_gpe1_enable_register_save = NULL;
176 return_ACPI_STATUS (status);
180 /******************************************************************************
182 * FUNCTION: Acpi_hw_set_mode
184 * PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY
188 * DESCRIPTION: Transitions the system into the requested mode or does nothing
189 * if the system is already in that mode.
191 ******************************************************************************/
198 acpi_status status = AE_NO_HARDWARE_RESPONSE;
201 FUNCTION_TRACE ("Hw_set_mode");
204 if (mode == SYS_MODE_ACPI) {
205 /* BIOS should have disabled ALL fixed and GP events */
207 acpi_os_write_port (acpi_gbl_FADT->smi_cmd, acpi_gbl_FADT->acpi_enable, 8);
208 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Attempting to enable ACPI mode\n"));
211 else if (mode == SYS_MODE_LEGACY) {
213 * BIOS should clear all fixed status bits and restore fixed event
214 * enable bits to default
216 acpi_os_write_port (acpi_gbl_FADT->smi_cmd, acpi_gbl_FADT->acpi_disable, 8);
217 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
218 "Attempting to enable Legacy (non-ACPI) mode\n"));
221 /* Give the platform some time to react */
223 acpi_os_stall (20000);
225 if (acpi_hw_get_mode () == mode) {
226 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode));
230 return_ACPI_STATUS (status);
234 /******************************************************************************
236 * FUNCTION: Acpi_hw_get_mode
240 * RETURN: SYS_MODE_ACPI or SYS_MODE_LEGACY
242 * DESCRIPTION: Return current operating state of system. Determined by
243 * querying the SCI_EN bit.
245 ******************************************************************************/
248 acpi_hw_get_mode (void)
251 FUNCTION_TRACE ("Hw_get_mode");
254 if (acpi_hw_register_bit_access (ACPI_READ, ACPI_MTX_LOCK, SCI_EN)) {
255 return_VALUE (SYS_MODE_ACPI);
258 return_VALUE (SYS_MODE_LEGACY);
263 /******************************************************************************
265 * FUNCTION: Acpi_hw_get_mode_capabilities
269 * RETURN: logical OR of SYS_MODE_ACPI and SYS_MODE_LEGACY determined at initial
272 * DESCRIPTION: Returns capablities of system
274 ******************************************************************************/
277 acpi_hw_get_mode_capabilities (void)
280 FUNCTION_TRACE ("Hw_get_mode_capabilities");
283 if (!(acpi_gbl_system_flags & SYS_MODES_MASK)) {
284 if (acpi_hw_get_mode () == SYS_MODE_LEGACY) {
286 * Assume that if this call is being made, Acpi_init has been called
287 * and ACPI support has been established by the presence of the
288 * tables. Therefore since we're in SYS_MODE_LEGACY, the system
289 * must support both modes
291 acpi_gbl_system_flags |= (SYS_MODE_ACPI | SYS_MODE_LEGACY);
295 /* TBD: [Investigate] !!! this may be unsafe... */
297 * system is is ACPI mode, so try to switch back to LEGACY to see if
300 acpi_hw_set_mode (SYS_MODE_LEGACY);
302 if (acpi_hw_get_mode () == SYS_MODE_LEGACY) {
303 /* Now in SYS_MODE_LEGACY, so both are supported */
305 acpi_gbl_system_flags |= (SYS_MODE_ACPI | SYS_MODE_LEGACY);
306 acpi_hw_set_mode (SYS_MODE_ACPI);
310 /* Still in SYS_MODE_ACPI so this must be an ACPI only system */
312 acpi_gbl_system_flags |= SYS_MODE_ACPI;
317 return_VALUE (acpi_gbl_system_flags & SYS_MODES_MASK);