hwregs.c 9.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9

/*******************************************************************************
 *
 * Module Name: hwregs - Read/write access functions for the various ACPI
 *                       control and status registers.
 *
 ******************************************************************************/

/*
L
Len Brown 已提交
10
 * Copyright (C) 2000 - 2008, Intel Corp.
L
Linus Torvalds 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
47
#include <acpi/accommon.h>
L
Linus Torvalds 已提交
48 49 50 51
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>

#define _COMPONENT          ACPI_HARDWARE
L
Len Brown 已提交
52
ACPI_MODULE_NAME("hwregs")
L
Linus Torvalds 已提交
53 54 55 56 57

/*******************************************************************************
 *
 * FUNCTION:    acpi_hw_clear_acpi_status
 *
58
 * PARAMETERS:  None
L
Linus Torvalds 已提交
59
 *
60
 * RETURN:      Status
L
Linus Torvalds 已提交
61 62 63 64 65
 *
 * DESCRIPTION: Clears all fixed and general purpose status bits
 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
 *
 ******************************************************************************/
66
acpi_status acpi_hw_clear_acpi_status(void)
L
Linus Torvalds 已提交
67
{
L
Len Brown 已提交
68
	acpi_status status;
B
Bob Moore 已提交
69
	acpi_cpu_flags lock_flags = 0;
L
Linus Torvalds 已提交
70

B
Bob Moore 已提交
71
	ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
L
Linus Torvalds 已提交
72

L
Len Brown 已提交
73 74
	ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
			  ACPI_BITMASK_ALL_FIXED_STATUS,
75
			  (u16) acpi_gbl_FADT.xpm1a_event_block.address));
L
Linus Torvalds 已提交
76

B
Bob Moore 已提交
77
	lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
L
Linus Torvalds 已提交
78

79
	status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
L
Len Brown 已提交
80 81
					ACPI_BITMASK_ALL_FIXED_STATUS);
	if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
82 83 84 85 86
		goto unlock_and_exit;
	}

	/* Clear the fixed events */

87
	if (acpi_gbl_FADT.xpm1b_event_block.address) {
88 89
		status = acpi_write(ACPI_BITMASK_ALL_FIXED_STATUS,
				    &acpi_gbl_FADT.xpm1b_event_block);
L
Len Brown 已提交
90
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
91 92 93 94 95 96
			goto unlock_and_exit;
		}
	}

	/* Clear the GPE Bits in all GPE registers in all GPE blocks */

97
	status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
L
Linus Torvalds 已提交
98

L
Len Brown 已提交
99
      unlock_and_exit:
B
Bob Moore 已提交
100
	acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
L
Len Brown 已提交
101
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
102 103 104 105 106 107 108 109
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_hw_get_register_bit_mask
 *
 * PARAMETERS:  register_id         - Index of ACPI Register to access
 *
R
Robert Moore 已提交
110
 * RETURN:      The bitmask to be used when accessing the register
L
Linus Torvalds 已提交
111
 *
R
Robert Moore 已提交
112
 * DESCRIPTION: Map register_id into a register bitmask.
L
Linus Torvalds 已提交
113 114
 *
 ******************************************************************************/
115

L
Len Brown 已提交
116
struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
L
Linus Torvalds 已提交
117
{
B
Bob Moore 已提交
118
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
119 120

	if (register_id > ACPI_BITREG_MAX) {
B
Bob Moore 已提交
121
		ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X",
B
Bob Moore 已提交
122
			    register_id));
L
Linus Torvalds 已提交
123 124 125 126 127 128 129 130 131 132
		return (NULL);
	}

	return (&acpi_gbl_bit_register_info[register_id]);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_register_read
 *
133
 * PARAMETERS:  register_id         - ACPI Register ID
R
Robert Moore 已提交
134
 *              return_value        - Where the register value is returned
L
Linus Torvalds 已提交
135 136 137
 *
 * RETURN:      Status and the value read.
 *
B
Bob Moore 已提交
138
 * DESCRIPTION: Read from the specified ACPI register
L
Linus Torvalds 已提交
139 140 141
 *
 ******************************************************************************/
acpi_status
142
acpi_hw_register_read(u32 register_id, u32 * return_value)
L
Linus Torvalds 已提交
143
{
L
Len Brown 已提交
144 145 146
	u32 value1 = 0;
	u32 value2 = 0;
	acpi_status status;
L
Linus Torvalds 已提交
147

B
Bob Moore 已提交
148
	ACPI_FUNCTION_TRACE(hw_register_read);
L
Linus Torvalds 已提交
149 150

	switch (register_id) {
L
Len Brown 已提交
151
	case ACPI_REGISTER_PM1_STATUS:	/* 16-bit access */
L
Linus Torvalds 已提交
152

153
		status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_event_block);
L
Len Brown 已提交
154
		if (ACPI_FAILURE(status)) {
155
			goto exit;
L
Linus Torvalds 已提交
156 157 158 159
		}

		/* PM1B is optional */

160
		status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_event_block);
L
Linus Torvalds 已提交
161 162 163
		value1 |= value2;
		break;

L
Len Brown 已提交
164
	case ACPI_REGISTER_PM1_ENABLE:	/* 16-bit access */
L
Linus Torvalds 已提交
165

166
		status = acpi_read(&value1, &acpi_gbl_xpm1a_enable);
L
Len Brown 已提交
167
		if (ACPI_FAILURE(status)) {
168
			goto exit;
L
Linus Torvalds 已提交
169 170 171 172
		}

		/* PM1B is optional */

173
		status = acpi_read(&value2, &acpi_gbl_xpm1b_enable);
L
Linus Torvalds 已提交
174 175 176
		value1 |= value2;
		break;

L
Len Brown 已提交
177
	case ACPI_REGISTER_PM1_CONTROL:	/* 16-bit access */
L
Linus Torvalds 已提交
178

179
		status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_control_block);
L
Len Brown 已提交
180
		if (ACPI_FAILURE(status)) {
181
			goto exit;
L
Linus Torvalds 已提交
182 183
		}

184
		status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_control_block);
L
Linus Torvalds 已提交
185 186 187
		value1 |= value2;
		break;

L
Len Brown 已提交
188
	case ACPI_REGISTER_PM2_CONTROL:	/* 8-bit access */
L
Linus Torvalds 已提交
189

190
		status = acpi_read(&value1, &acpi_gbl_FADT.xpm2_control_block);
L
Linus Torvalds 已提交
191 192
		break;

L
Len Brown 已提交
193
	case ACPI_REGISTER_PM_TIMER:	/* 32-bit access */
L
Linus Torvalds 已提交
194

195
		status = acpi_read(&value1, &acpi_gbl_FADT.xpm_timer_block);
L
Linus Torvalds 已提交
196 197
		break;

L
Len Brown 已提交
198
	case ACPI_REGISTER_SMI_COMMAND_BLOCK:	/* 8-bit access */
L
Linus Torvalds 已提交
199

200 201
		status =
		    acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
L
Linus Torvalds 已提交
202 203 204
		break;

	default:
B
Bob Moore 已提交
205
		ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id));
L
Linus Torvalds 已提交
206 207 208 209
		status = AE_BAD_PARAMETER;
		break;
	}

210
      exit:
L
Linus Torvalds 已提交
211

L
Len Brown 已提交
212
	if (ACPI_SUCCESS(status)) {
L
Linus Torvalds 已提交
213 214 215
		*return_value = value1;
	}

L
Len Brown 已提交
216
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
217 218 219 220 221 222
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_register_write
 *
223
 * PARAMETERS:  register_id         - ACPI Register ID
L
Linus Torvalds 已提交
224 225 226 227
 *              Value               - The value to write
 *
 * RETURN:      Status
 *
B
Bob Moore 已提交
228 229 230 231 232 233 234 235 236 237 238 239 240 241
 * DESCRIPTION: Write to the specified ACPI register
 *
 * NOTE: In accordance with the ACPI specification, this function automatically
 * preserves the value of the following bits, meaning that these bits cannot be
 * changed via this interface:
 *
 * PM1_CONTROL[0] = SCI_EN
 * PM1_CONTROL[9]
 * PM1_STATUS[11]
 *
 * ACPI References:
 * 1) Hardware Ignored Bits: When software writes to a register with ignored
 *      bit fields, it preserves the ignored bit fields
 * 2) SCI_EN: OSPM always preserves this bit position
L
Linus Torvalds 已提交
242 243 244
 *
 ******************************************************************************/

245
acpi_status acpi_hw_register_write(u32 register_id, u32 value)
L
Linus Torvalds 已提交
246
{
L
Len Brown 已提交
247
	acpi_status status;
B
Bob Moore 已提交
248
	u32 read_value;
L
Linus Torvalds 已提交
249

B
Bob Moore 已提交
250
	ACPI_FUNCTION_TRACE(hw_register_write);
L
Linus Torvalds 已提交
251 252

	switch (register_id) {
L
Len Brown 已提交
253
	case ACPI_REGISTER_PM1_STATUS:	/* 16-bit access */
L
Linus Torvalds 已提交
254

B
Bob Moore 已提交
255 256
		/* Perform a read first to preserve certain bits (per ACPI spec) */

257
		status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS,
B
Bob Moore 已提交
258 259
					       &read_value);
		if (ACPI_FAILURE(status)) {
260
			goto exit;
B
Bob Moore 已提交
261 262 263 264 265 266 267 268 269
		}

		/* Insert the bits to be preserved */

		ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS,
				 read_value);

		/* Now we can write the data */

270
		status = acpi_write(value, &acpi_gbl_FADT.xpm1a_event_block);
L
Len Brown 已提交
271
		if (ACPI_FAILURE(status)) {
272
			goto exit;
L
Linus Torvalds 已提交
273 274 275 276
		}

		/* PM1B is optional */

277
		status = acpi_write(value, &acpi_gbl_FADT.xpm1b_event_block);
L
Linus Torvalds 已提交
278 279
		break;

L
Len Brown 已提交
280
	case ACPI_REGISTER_PM1_ENABLE:	/* 16-bit access */
L
Linus Torvalds 已提交
281

282
		status = acpi_write(value, &acpi_gbl_xpm1a_enable);
L
Len Brown 已提交
283
		if (ACPI_FAILURE(status)) {
284
			goto exit;
L
Linus Torvalds 已提交
285 286 287 288
		}

		/* PM1B is optional */

289
		status = acpi_write(value, &acpi_gbl_xpm1b_enable);
L
Linus Torvalds 已提交
290 291
		break;

L
Len Brown 已提交
292
	case ACPI_REGISTER_PM1_CONTROL:	/* 16-bit access */
L
Linus Torvalds 已提交
293

B
Bob Moore 已提交
294 295 296
		/*
		 * Perform a read first to preserve certain bits (per ACPI spec)
		 */
297
		status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
B
Bob Moore 已提交
298 299
					       &read_value);
		if (ACPI_FAILURE(status)) {
300
			goto exit;
B
Bob Moore 已提交
301 302 303 304 305 306 307 308 309
		}

		/* Insert the bits to be preserved */

		ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
				 read_value);

		/* Now we can write the data */

310
		status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block);
L
Len Brown 已提交
311
		if (ACPI_FAILURE(status)) {
312
			goto exit;
L
Linus Torvalds 已提交
313 314
		}

315
		status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block);
L
Linus Torvalds 已提交
316 317
		break;

L
Len Brown 已提交
318
	case ACPI_REGISTER_PM1A_CONTROL:	/* 16-bit access */
L
Linus Torvalds 已提交
319

320
		status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block);
L
Linus Torvalds 已提交
321 322
		break;

L
Len Brown 已提交
323
	case ACPI_REGISTER_PM1B_CONTROL:	/* 16-bit access */
L
Linus Torvalds 已提交
324

325
		status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block);
L
Linus Torvalds 已提交
326 327
		break;

L
Len Brown 已提交
328
	case ACPI_REGISTER_PM2_CONTROL:	/* 8-bit access */
L
Linus Torvalds 已提交
329

330
		status = acpi_write(value, &acpi_gbl_FADT.xpm2_control_block);
L
Linus Torvalds 已提交
331 332
		break;

L
Len Brown 已提交
333
	case ACPI_REGISTER_PM_TIMER:	/* 32-bit access */
L
Linus Torvalds 已提交
334

335
		status = acpi_write(value, &acpi_gbl_FADT.xpm_timer_block);
L
Linus Torvalds 已提交
336 337
		break;

L
Len Brown 已提交
338
	case ACPI_REGISTER_SMI_COMMAND_BLOCK:	/* 8-bit access */
L
Linus Torvalds 已提交
339 340 341

		/* SMI_CMD is currently always in IO space */

342 343
		status =
		    acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
L
Linus Torvalds 已提交
344 345 346 347 348 349 350
		break;

	default:
		status = AE_BAD_PARAMETER;
		break;
	}

351
      exit:
L
Len Brown 已提交
352
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
353
}