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>
L
Len Brown 已提交
47 48 49
#include "accommon.h"
#include "acnamesp.h"
#include "acevents.h"
L
Linus Torvalds 已提交
50 51

#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_xpm1a_status.address));
L
Linus Torvalds 已提交
76

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

79 80
	/* Clear the fixed events */

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

87
	/* Write PM1B register if present */
L
Linus Torvalds 已提交
88

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

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

99
	status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
L
Linus Torvalds 已提交
100

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

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

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

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

	return (&acpi_gbl_bit_register_info[register_id]);
}

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

B
Bob Moore 已提交
150
	ACPI_FUNCTION_TRACE(hw_register_read);
L
Linus Torvalds 已提交
151 152

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

155
		status = acpi_read(&value1, &acpi_gbl_xpm1a_status);
L
Len Brown 已提交
156
		if (ACPI_FAILURE(status)) {
157
			goto exit;
L
Linus Torvalds 已提交
158 159 160 161
		}

		/* PM1B is optional */

162
		status = acpi_read(&value2, &acpi_gbl_xpm1b_status);
L
Linus Torvalds 已提交
163 164 165
		value1 |= value2;
		break;

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

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

		/* PM1B is optional */

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

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

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

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

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

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

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

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

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

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

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

212
      exit:
L
Linus Torvalds 已提交
213

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

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

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_register_write
 *
225
 * PARAMETERS:  register_id         - ACPI Register ID
L
Linus Torvalds 已提交
226 227 228 229
 *              Value               - The value to write
 *
 * RETURN:      Status
 *
B
Bob Moore 已提交
230 231 232 233 234 235 236 237 238 239 240 241 242 243
 * 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 已提交
244 245 246
 *
 ******************************************************************************/

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

B
Bob Moore 已提交
252
	ACPI_FUNCTION_TRACE(hw_register_write);
L
Linus Torvalds 已提交
253 254

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

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

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

		/* Insert the bits to be preserved */

		ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS,
				 read_value);

		/* Now we can write the data */

272
		status = acpi_write(value, &acpi_gbl_xpm1a_status);
L
Len Brown 已提交
273
		if (ACPI_FAILURE(status)) {
274
			goto exit;
L
Linus Torvalds 已提交
275 276 277 278
		}

		/* PM1B is optional */

279
		status = acpi_write(value, &acpi_gbl_xpm1b_status);
L
Linus Torvalds 已提交
280 281
		break;

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

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

		/* PM1B is optional */

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

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

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

		/* Insert the bits to be preserved */

		ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
				 read_value);

		/* Now we can write the data */

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

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

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

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

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

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

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

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

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

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

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

		/* SMI_CMD is currently always in IO space */

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

	default:
		status = AE_BAD_PARAMETER;
		break;
	}

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