Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /*******************************************************************************
3 : : *
4 : : * Module Name: hwregs - Read/write access functions for the various ACPI
5 : : * control and status registers.
6 : : *
7 : : ******************************************************************************/
8 : :
9 : : #include <acpi/acpi.h>
10 : : #include "accommon.h"
11 : : #include "acevents.h"
12 : :
13 : : #define _COMPONENT ACPI_HARDWARE
14 : : ACPI_MODULE_NAME("hwregs")
15 : :
16 : : #if (!ACPI_REDUCED_HARDWARE)
17 : : /* Local Prototypes */
18 : : static u8
19 : : acpi_hw_get_access_bit_width(u64 address,
20 : : struct acpi_generic_address *reg,
21 : : u8 max_bit_width);
22 : :
23 : : static acpi_status
24 : : acpi_hw_read_multiple(u32 *value,
25 : : struct acpi_generic_address *register_a,
26 : : struct acpi_generic_address *register_b);
27 : :
28 : : static acpi_status
29 : : acpi_hw_write_multiple(u32 value,
30 : : struct acpi_generic_address *register_a,
31 : : struct acpi_generic_address *register_b);
32 : :
33 : : #endif /* !ACPI_REDUCED_HARDWARE */
34 : :
35 : : /******************************************************************************
36 : : *
37 : : * FUNCTION: acpi_hw_get_access_bit_width
38 : : *
39 : : * PARAMETERS: address - GAS register address
40 : : * reg - GAS register structure
41 : : * max_bit_width - Max bit_width supported (32 or 64)
42 : : *
43 : : * RETURN: Status
44 : : *
45 : : * DESCRIPTION: Obtain optimal access bit width
46 : : *
47 : : ******************************************************************************/
48 : :
49 : : static u8
50 : 1482 : acpi_hw_get_access_bit_width(u64 address,
51 : : struct acpi_generic_address *reg, u8 max_bit_width)
52 : : {
53 : 1482 : u8 access_bit_width;
54 : :
55 : : /*
56 : : * GAS format "register", used by FADT:
57 : : * 1. Detected if bit_offset is 0 and bit_width is 8/16/32/64;
58 : : * 2. access_size field is ignored and bit_width field is used for
59 : : * determining the boundary of the IO accesses.
60 : : * GAS format "region", used by APEI registers:
61 : : * 1. Detected if bit_offset is not 0 or bit_width is not 8/16/32/64;
62 : : * 2. access_size field is used for determining the boundary of the
63 : : * IO accesses;
64 : : * 3. bit_offset/bit_width fields are used to describe the "region".
65 : : *
66 : : * Note: This algorithm assumes that the "Address" fields should always
67 : : * contain aligned values.
68 : : */
69 [ + - + - ]: 1482 : if (!reg->bit_offset && reg->bit_width &&
70 [ + - - + ]: 1482 : ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
71 : : ACPI_IS_ALIGNED(reg->bit_width, 8)) {
72 : : access_bit_width = reg->bit_width;
73 [ # # ]: 0 : } else if (reg->access_width) {
74 : 0 : access_bit_width = ACPI_ACCESS_BIT_WIDTH(reg->access_width);
75 : : } else {
76 : 0 : access_bit_width =
77 [ # # # # : 0 : ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset +
# # # # #
# # # #
# ]
78 : : reg->bit_width);
79 : 0 : if (access_bit_width <= 8) {
80 : : access_bit_width = 8;
81 : : } else {
82 [ # # ]: 0 : while (!ACPI_IS_ALIGNED(address, access_bit_width >> 3)) {
83 : 0 : access_bit_width >>= 1;
84 : : }
85 : : }
86 : : }
87 : :
88 : : /* Maximum IO port access bit width is 32 */
89 : :
90 [ + - ]: 1482 : if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
91 : 1482 : max_bit_width = 32;
92 : : }
93 : :
94 : : /*
95 : : * Return access width according to the requested maximum access bit width,
96 : : * as the caller should know the format of the register and may enforce
97 : : * a 32-bit accesses.
98 : : */
99 : 1482 : if (access_bit_width < max_bit_width) {
100 : : return (access_bit_width);
101 : : }
102 : : return (max_bit_width);
103 : : }
104 : :
105 : : /******************************************************************************
106 : : *
107 : : * FUNCTION: acpi_hw_validate_register
108 : : *
109 : : * PARAMETERS: reg - GAS register structure
110 : : * max_bit_width - Max bit_width supported (32 or 64)
111 : : * address - Pointer to where the gas->address
112 : : * is returned
113 : : *
114 : : * RETURN: Status
115 : : *
116 : : * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
117 : : * pointer, Address, space_id, bit_width, and bit_offset.
118 : : *
119 : : ******************************************************************************/
120 : :
121 : : acpi_status
122 : 741 : acpi_hw_validate_register(struct acpi_generic_address *reg,
123 : : u8 max_bit_width, u64 *address)
124 : : {
125 : 741 : u8 bit_width;
126 : 741 : u8 access_width;
127 : :
128 : : /* Must have a valid pointer to a GAS structure */
129 : :
130 [ + - ]: 741 : if (!reg) {
131 : : return (AE_BAD_PARAMETER);
132 : : }
133 : :
134 : : /*
135 : : * Copy the target address. This handles possible alignment issues.
136 : : * Address must not be null. A null address also indicates an optional
137 : : * ACPI register that is not supported, so no error message.
138 : : */
139 : 741 : ACPI_MOVE_64_TO_64(address, ®->address);
140 [ + - ]: 741 : if (!(*address)) {
141 : : return (AE_BAD_ADDRESS);
142 : : }
143 : :
144 : : /* Validate the space_ID */
145 : :
146 [ - + ]: 741 : if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
147 : : (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
148 : 0 : ACPI_ERROR((AE_INFO,
149 : : "Unsupported address space: 0x%X", reg->space_id));
150 : 0 : return (AE_SUPPORT);
151 : : }
152 : :
153 : : /* Validate the access_width */
154 : :
155 [ - + ]: 741 : if (reg->access_width > 4) {
156 : 0 : ACPI_ERROR((AE_INFO,
157 : : "Unsupported register access width: 0x%X",
158 : : reg->access_width));
159 : 0 : return (AE_SUPPORT);
160 : : }
161 : :
162 : : /* Validate the bit_width, convert access_width into number of bits */
163 : :
164 : 741 : access_width =
165 : 741 : acpi_hw_get_access_bit_width(*address, reg, max_bit_width);
166 : 741 : bit_width =
167 : 741 : ACPI_ROUND_UP(reg->bit_offset + reg->bit_width, access_width);
168 [ - + ]: 741 : if (max_bit_width < bit_width) {
169 : 0 : ACPI_WARNING((AE_INFO,
170 : : "Requested bit width 0x%X is smaller than register bit width 0x%X",
171 : : max_bit_width, bit_width));
172 : 0 : return (AE_SUPPORT);
173 : : }
174 : :
175 : : return (AE_OK);
176 : : }
177 : :
178 : : /******************************************************************************
179 : : *
180 : : * FUNCTION: acpi_hw_read
181 : : *
182 : : * PARAMETERS: value - Where the value is returned
183 : : * reg - GAS register structure
184 : : *
185 : : * RETURN: Status
186 : : *
187 : : * DESCRIPTION: Read from either memory or IO space. This is a 64-bit max
188 : : * version of acpi_read.
189 : : *
190 : : * LIMITATIONS: <These limitations also apply to acpi_hw_write>
191 : : * space_ID must be system_memory or system_IO.
192 : : *
193 : : ******************************************************************************/
194 : :
195 : 468 : acpi_status acpi_hw_read(u64 *value, struct acpi_generic_address *reg)
196 : : {
197 : 468 : u64 address;
198 : 468 : u8 access_width;
199 : 468 : u32 bit_width;
200 : 468 : u8 bit_offset;
201 : 468 : u64 value64;
202 : 468 : u32 value32;
203 : 468 : u8 index;
204 : 468 : acpi_status status;
205 : :
206 : 468 : ACPI_FUNCTION_NAME(hw_read);
207 : :
208 : : /* Validate contents of the GAS register */
209 : :
210 : 468 : status = acpi_hw_validate_register(reg, 64, &address);
211 [ + - ]: 468 : if (ACPI_FAILURE(status)) {
212 : : return (status);
213 : : }
214 : :
215 : : /*
216 : : * Initialize entire 64-bit return value to zero, convert access_width
217 : : * into number of bits based
218 : : */
219 : 468 : *value = 0;
220 : 468 : access_width = acpi_hw_get_access_bit_width(address, reg, 64);
221 : 468 : bit_width = reg->bit_offset + reg->bit_width;
222 : 468 : bit_offset = reg->bit_offset;
223 : :
224 : : /*
225 : : * Two address spaces supported: Memory or IO. PCI_Config is
226 : : * not supported here because the GAS structure is insufficient
227 : : */
228 : 468 : index = 0;
229 [ + + ]: 936 : while (bit_width) {
230 [ - + ]: 468 : if (bit_offset >= access_width) {
231 : 0 : value64 = 0;
232 : 0 : bit_offset -= access_width;
233 : : } else {
234 [ - + ]: 468 : if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
235 : 0 : status =
236 : 0 : acpi_os_read_memory((acpi_physical_address)
237 : : address +
238 : 0 : index *
239 : 0 : ACPI_DIV_8
240 : : (access_width),
241 : : &value64, access_width);
242 : : } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
243 : :
244 : 468 : status = acpi_hw_read_port((acpi_io_address)
245 : : address +
246 : 468 : index *
247 : 468 : ACPI_DIV_8
248 : : (access_width),
249 : : &value32,
250 : : access_width);
251 : 468 : value64 = (u64)value32;
252 : : }
253 : : }
254 : :
255 : : /*
256 : : * Use offset style bit writes because "Index * AccessWidth" is
257 : : * ensured to be less than 64-bits by acpi_hw_validate_register().
258 : : */
259 [ + - ]: 468 : ACPI_SET_BITS(value, index * access_width,
260 : : ACPI_MASK_BITS_ABOVE_64(access_width), value64);
261 : :
262 : 468 : bit_width -=
263 : 468 : bit_width > access_width ? access_width : bit_width;
264 : 468 : index++;
265 : : }
266 : :
267 : : ACPI_DEBUG_PRINT((ACPI_DB_IO,
268 : : "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
269 : : ACPI_FORMAT_UINT64(*value), access_width,
270 : : ACPI_FORMAT_UINT64(address),
271 : : acpi_ut_get_region_name(reg->space_id)));
272 : :
273 : : return (status);
274 : : }
275 : :
276 : : /******************************************************************************
277 : : *
278 : : * FUNCTION: acpi_hw_write
279 : : *
280 : : * PARAMETERS: value - Value to be written
281 : : * reg - GAS register structure
282 : : *
283 : : * RETURN: Status
284 : : *
285 : : * DESCRIPTION: Write to either memory or IO space. This is a 64-bit max
286 : : * version of acpi_write.
287 : : *
288 : : ******************************************************************************/
289 : :
290 : 273 : acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg)
291 : : {
292 : 273 : u64 address;
293 : 273 : u8 access_width;
294 : 273 : u32 bit_width;
295 : 273 : u8 bit_offset;
296 : 273 : u64 value64;
297 : 273 : u8 index;
298 : 273 : acpi_status status;
299 : :
300 : 273 : ACPI_FUNCTION_NAME(hw_write);
301 : :
302 : : /* Validate contents of the GAS register */
303 : :
304 : 273 : status = acpi_hw_validate_register(reg, 64, &address);
305 [ + - ]: 273 : if (ACPI_FAILURE(status)) {
306 : : return (status);
307 : : }
308 : :
309 : : /* Convert access_width into number of bits based */
310 : :
311 : 273 : access_width = acpi_hw_get_access_bit_width(address, reg, 64);
312 : 273 : bit_width = reg->bit_offset + reg->bit_width;
313 : 273 : bit_offset = reg->bit_offset;
314 : :
315 : : /*
316 : : * Two address spaces supported: Memory or IO. PCI_Config is
317 : : * not supported here because the GAS structure is insufficient
318 : : */
319 : 273 : index = 0;
320 [ + + ]: 546 : while (bit_width) {
321 : : /*
322 : : * Use offset style bit reads because "Index * AccessWidth" is
323 : : * ensured to be less than 64-bits by acpi_hw_validate_register().
324 : : */
325 [ + - ]: 273 : value64 = ACPI_GET_BITS(&value, index * access_width,
326 : : ACPI_MASK_BITS_ABOVE_64(access_width));
327 : :
328 [ - + ]: 273 : if (bit_offset >= access_width) {
329 : 0 : bit_offset -= access_width;
330 : : } else {
331 [ - + ]: 273 : if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
332 : 0 : status =
333 : 0 : acpi_os_write_memory((acpi_physical_address)
334 : : address +
335 : 0 : index *
336 : 0 : ACPI_DIV_8
337 : : (access_width),
338 : : value64, access_width);
339 : : } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
340 : :
341 : 273 : status = acpi_hw_write_port((acpi_io_address)
342 : : address +
343 : 273 : index *
344 : 273 : ACPI_DIV_8
345 : : (access_width),
346 : : (u32)value64,
347 : : access_width);
348 : : }
349 : : }
350 : :
351 : : /*
352 : : * Index * access_width is ensured to be less than 32-bits by
353 : : * acpi_hw_validate_register().
354 : : */
355 : 273 : bit_width -=
356 : 273 : bit_width > access_width ? access_width : bit_width;
357 : 273 : index++;
358 : : }
359 : :
360 : : ACPI_DEBUG_PRINT((ACPI_DB_IO,
361 : : "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n",
362 : : ACPI_FORMAT_UINT64(value), access_width,
363 : : ACPI_FORMAT_UINT64(address),
364 : : acpi_ut_get_region_name(reg->space_id)));
365 : :
366 : : return (status);
367 : : }
368 : :
369 : : #if (!ACPI_REDUCED_HARDWARE)
370 : : /*******************************************************************************
371 : : *
372 : : * FUNCTION: acpi_hw_clear_acpi_status
373 : : *
374 : : * PARAMETERS: None
375 : : *
376 : : * RETURN: Status
377 : : *
378 : : * DESCRIPTION: Clears all fixed and general purpose status bits
379 : : *
380 : : ******************************************************************************/
381 : :
382 : 0 : acpi_status acpi_hw_clear_acpi_status(void)
383 : : {
384 : 0 : acpi_status status;
385 : 0 : acpi_cpu_flags lock_flags = 0;
386 : :
387 : 0 : ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
388 : :
389 : : ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
390 : : ACPI_BITMASK_ALL_FIXED_STATUS,
391 : 0 : ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address)));
392 : :
393 : 0 : lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock);
394 : :
395 : : /* Clear the fixed events in PM1 A/B */
396 : :
397 : 0 : status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
398 : : ACPI_BITMASK_ALL_FIXED_STATUS);
399 : :
400 : 0 : acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags);
401 : :
402 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
403 : 0 : goto exit;
404 : : }
405 : :
406 : : /* Clear the GPE Bits in all GPE registers in all GPE blocks */
407 : :
408 : 0 : status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
409 : :
410 : 0 : exit:
411 : 0 : return_ACPI_STATUS(status);
412 : : }
413 : :
414 : : /*******************************************************************************
415 : : *
416 : : * FUNCTION: acpi_hw_get_bit_register_info
417 : : *
418 : : * PARAMETERS: register_id - Index of ACPI Register to access
419 : : *
420 : : * RETURN: The bitmask to be used when accessing the register
421 : : *
422 : : * DESCRIPTION: Map register_id into a register bitmask.
423 : : *
424 : : ******************************************************************************/
425 : :
426 : 260 : struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
427 : : {
428 : 260 : ACPI_FUNCTION_ENTRY();
429 : :
430 [ - + ]: 260 : if (register_id > ACPI_BITREG_MAX) {
431 : 0 : ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: 0x%X",
432 : : register_id));
433 : 0 : return (NULL);
434 : : }
435 : :
436 : 260 : return (&acpi_gbl_bit_register_info[register_id]);
437 : : }
438 : :
439 : : /******************************************************************************
440 : : *
441 : : * FUNCTION: acpi_hw_write_pm1_control
442 : : *
443 : : * PARAMETERS: pm1a_control - Value to be written to PM1A control
444 : : * pm1b_control - Value to be written to PM1B control
445 : : *
446 : : * RETURN: Status
447 : : *
448 : : * DESCRIPTION: Write the PM1 A/B control registers. These registers are
449 : : * different than than the PM1 A/B status and enable registers
450 : : * in that different values can be written to the A/B registers.
451 : : * Most notably, the SLP_TYP bits can be different, as per the
452 : : * values returned from the _Sx predefined methods.
453 : : *
454 : : ******************************************************************************/
455 : :
456 : 0 : acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
457 : : {
458 : 0 : acpi_status status;
459 : :
460 : 0 : ACPI_FUNCTION_TRACE(hw_write_pm1_control);
461 : :
462 : 0 : status =
463 : 0 : acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block);
464 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
465 : : return_ACPI_STATUS(status);
466 : : }
467 : :
468 [ # # ]: 0 : if (acpi_gbl_FADT.xpm1b_control_block.address) {
469 : 0 : status =
470 : 0 : acpi_hw_write(pm1b_control,
471 : : &acpi_gbl_FADT.xpm1b_control_block);
472 : : }
473 : : return_ACPI_STATUS(status);
474 : : }
475 : :
476 : : /******************************************************************************
477 : : *
478 : : * FUNCTION: acpi_hw_register_read
479 : : *
480 : : * PARAMETERS: register_id - ACPI Register ID
481 : : * return_value - Where the register value is returned
482 : : *
483 : : * RETURN: Status and the value read.
484 : : *
485 : : * DESCRIPTION: Read from the specified ACPI register
486 : : *
487 : : ******************************************************************************/
488 : 208 : acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
489 : : {
490 : 208 : u32 value = 0;
491 : 208 : u64 value64;
492 : 208 : acpi_status status;
493 : :
494 : 208 : ACPI_FUNCTION_TRACE(hw_register_read);
495 : :
496 [ - + + - : 208 : switch (register_id) {
- - - ]
497 : 0 : case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */
498 : :
499 : 0 : status = acpi_hw_read_multiple(&value,
500 : : &acpi_gbl_xpm1a_status,
501 : : &acpi_gbl_xpm1b_status);
502 : 0 : break;
503 : :
504 : 169 : case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */
505 : :
506 : 169 : status = acpi_hw_read_multiple(&value,
507 : : &acpi_gbl_xpm1a_enable,
508 : : &acpi_gbl_xpm1b_enable);
509 : 169 : break;
510 : :
511 : 39 : case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
512 : :
513 : 39 : status = acpi_hw_read_multiple(&value,
514 : : &acpi_gbl_FADT.
515 : : xpm1a_control_block,
516 : : &acpi_gbl_FADT.
517 : : xpm1b_control_block);
518 : :
519 : : /*
520 : : * Zero the write-only bits. From the ACPI specification, "Hardware
521 : : * Write-Only Bits": "Upon reads to registers with write-only bits,
522 : : * software masks out all write-only bits."
523 : : */
524 : 39 : value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
525 : 39 : break;
526 : :
527 : 0 : case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
528 : :
529 : 0 : status =
530 : 0 : acpi_hw_read(&value64, &acpi_gbl_FADT.xpm2_control_block);
531 [ # # ]: 0 : if (ACPI_SUCCESS(status)) {
532 : 0 : value = (u32)value64;
533 : : }
534 : : break;
535 : :
536 : 0 : case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
537 : :
538 : 0 : status = acpi_hw_read(&value64, &acpi_gbl_FADT.xpm_timer_block);
539 [ # # ]: 0 : if (ACPI_SUCCESS(status)) {
540 : 0 : value = (u32)value64;
541 : : }
542 : :
543 : : break;
544 : :
545 : 0 : case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
546 : :
547 : 0 : status =
548 : 0 : acpi_hw_read_port(acpi_gbl_FADT.smi_command, &value, 8);
549 : 0 : break;
550 : :
551 : 0 : default:
552 : :
553 : 0 : ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
554 : 0 : status = AE_BAD_PARAMETER;
555 : 0 : break;
556 : : }
557 : :
558 [ + - ]: 208 : if (ACPI_SUCCESS(status)) {
559 : 208 : *return_value = (u32)value;
560 : : }
561 : :
562 : 208 : return_ACPI_STATUS(status);
563 : : }
564 : :
565 : : /******************************************************************************
566 : : *
567 : : * FUNCTION: acpi_hw_register_write
568 : : *
569 : : * PARAMETERS: register_id - ACPI Register ID
570 : : * value - The value to write
571 : : *
572 : : * RETURN: Status
573 : : *
574 : : * DESCRIPTION: Write to the specified ACPI register
575 : : *
576 : : * NOTE: In accordance with the ACPI specification, this function automatically
577 : : * preserves the value of the following bits, meaning that these bits cannot be
578 : : * changed via this interface:
579 : : *
580 : : * PM1_CONTROL[0] = SCI_EN
581 : : * PM1_CONTROL[9]
582 : : * PM1_STATUS[11]
583 : : *
584 : : * ACPI References:
585 : : * 1) Hardware Ignored Bits: When software writes to a register with ignored
586 : : * bit fields, it preserves the ignored bit fields
587 : : * 2) SCI_EN: OSPM always preserves this bit position
588 : : *
589 : : ******************************************************************************/
590 : :
591 : 169 : acpi_status acpi_hw_register_write(u32 register_id, u32 value)
592 : : {
593 : 169 : acpi_status status;
594 : 169 : u32 read_value;
595 : 169 : u64 read_value64;
596 : :
597 : 169 : ACPI_FUNCTION_TRACE(hw_register_write);
598 : :
599 [ + + - - : 169 : switch (register_id) {
- - - ]
600 : 52 : case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */
601 : : /*
602 : : * Handle the "ignored" bit in PM1 Status. According to the ACPI
603 : : * specification, ignored bits are to be preserved when writing.
604 : : * Normally, this would mean a read/modify/write sequence. However,
605 : : * preserving a bit in the status register is different. Writing a
606 : : * one clears the status, and writing a zero preserves the status.
607 : : * Therefore, we must always write zero to the ignored bit.
608 : : *
609 : : * This behavior is clarified in the ACPI 4.0 specification.
610 : : */
611 : 52 : value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
612 : :
613 : 52 : status = acpi_hw_write_multiple(value,
614 : : &acpi_gbl_xpm1a_status,
615 : : &acpi_gbl_xpm1b_status);
616 : 52 : break;
617 : :
618 : 117 : case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */
619 : :
620 : 117 : status = acpi_hw_write_multiple(value,
621 : : &acpi_gbl_xpm1a_enable,
622 : : &acpi_gbl_xpm1b_enable);
623 : 117 : break;
624 : :
625 : 0 : case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
626 : : /*
627 : : * Perform a read first to preserve certain bits (per ACPI spec)
628 : : * Note: This includes SCI_EN, we never want to change this bit
629 : : */
630 : 0 : status = acpi_hw_read_multiple(&read_value,
631 : : &acpi_gbl_FADT.
632 : : xpm1a_control_block,
633 : : &acpi_gbl_FADT.
634 : : xpm1b_control_block);
635 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
636 : 0 : goto exit;
637 : : }
638 : :
639 : : /* Insert the bits to be preserved */
640 : :
641 : 0 : ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
642 : : read_value);
643 : :
644 : : /* Now we can write the data */
645 : :
646 : 0 : status = acpi_hw_write_multiple(value,
647 : : &acpi_gbl_FADT.
648 : : xpm1a_control_block,
649 : : &acpi_gbl_FADT.
650 : : xpm1b_control_block);
651 : 0 : break;
652 : :
653 : 0 : case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
654 : : /*
655 : : * For control registers, all reserved bits must be preserved,
656 : : * as per the ACPI spec.
657 : : */
658 : 0 : status =
659 : 0 : acpi_hw_read(&read_value64,
660 : : &acpi_gbl_FADT.xpm2_control_block);
661 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
662 : 0 : goto exit;
663 : : }
664 : 0 : read_value = (u32)read_value64;
665 : :
666 : : /* Insert the bits to be preserved */
667 : :
668 : 0 : ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS,
669 : : read_value);
670 : :
671 : 0 : status =
672 : 0 : acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block);
673 : 0 : break;
674 : :
675 : 0 : case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
676 : :
677 : 0 : status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block);
678 : 0 : break;
679 : :
680 : 0 : case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
681 : :
682 : : /* SMI_CMD is currently always in IO space */
683 : :
684 : 0 : status =
685 : 0 : acpi_hw_write_port(acpi_gbl_FADT.smi_command, value, 8);
686 : 0 : break;
687 : :
688 : 0 : default:
689 : :
690 : 0 : ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
691 : 0 : status = AE_BAD_PARAMETER;
692 : 0 : break;
693 : : }
694 : :
695 : 169 : exit:
696 : 169 : return_ACPI_STATUS(status);
697 : : }
698 : :
699 : : /******************************************************************************
700 : : *
701 : : * FUNCTION: acpi_hw_read_multiple
702 : : *
703 : : * PARAMETERS: value - Where the register value is returned
704 : : * register_a - First ACPI register (required)
705 : : * register_b - Second ACPI register (optional)
706 : : *
707 : : * RETURN: Status
708 : : *
709 : : * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
710 : : *
711 : : ******************************************************************************/
712 : :
713 : : static acpi_status
714 : 208 : acpi_hw_read_multiple(u32 *value,
715 : : struct acpi_generic_address *register_a,
716 : : struct acpi_generic_address *register_b)
717 : : {
718 : 208 : u32 value_a = 0;
719 : 208 : u32 value_b = 0;
720 : 208 : u64 value64;
721 : 208 : acpi_status status;
722 : :
723 : : /* The first register is always required */
724 : :
725 : 208 : status = acpi_hw_read(&value64, register_a);
726 [ + - ]: 208 : if (ACPI_FAILURE(status)) {
727 : : return (status);
728 : : }
729 : 208 : value_a = (u32)value64;
730 : :
731 : : /* Second register is optional */
732 : :
733 [ - + ]: 208 : if (register_b->address) {
734 : 0 : status = acpi_hw_read(&value64, register_b);
735 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
736 : : return (status);
737 : : }
738 : 0 : value_b = (u32)value64;
739 : : }
740 : :
741 : : /*
742 : : * OR the two return values together. No shifting or masking is necessary,
743 : : * because of how the PM1 registers are defined in the ACPI specification:
744 : : *
745 : : * "Although the bits can be split between the two register blocks (each
746 : : * register block has a unique pointer within the FADT), the bit positions
747 : : * are maintained. The register block with unimplemented bits (that is,
748 : : * those implemented in the other register block) always returns zeros,
749 : : * and writes have no side effects"
750 : : */
751 : 208 : *value = (value_a | value_b);
752 : 208 : return (AE_OK);
753 : : }
754 : :
755 : : /******************************************************************************
756 : : *
757 : : * FUNCTION: acpi_hw_write_multiple
758 : : *
759 : : * PARAMETERS: value - The value to write
760 : : * register_a - First ACPI register (required)
761 : : * register_b - Second ACPI register (optional)
762 : : *
763 : : * RETURN: Status
764 : : *
765 : : * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
766 : : *
767 : : ******************************************************************************/
768 : :
769 : : static acpi_status
770 : 169 : acpi_hw_write_multiple(u32 value,
771 : : struct acpi_generic_address *register_a,
772 : : struct acpi_generic_address *register_b)
773 : : {
774 : 169 : acpi_status status;
775 : :
776 : : /* The first register is always required */
777 : :
778 : 169 : status = acpi_hw_write(value, register_a);
779 [ + - ]: 169 : if (ACPI_FAILURE(status)) {
780 : : return (status);
781 : : }
782 : :
783 : : /*
784 : : * Second register is optional
785 : : *
786 : : * No bit shifting or clearing is necessary, because of how the PM1
787 : : * registers are defined in the ACPI specification:
788 : : *
789 : : * "Although the bits can be split between the two register blocks (each
790 : : * register block has a unique pointer within the FADT), the bit positions
791 : : * are maintained. The register block with unimplemented bits (that is,
792 : : * those implemented in the other register block) always returns zeros,
793 : : * and writes have no side effects"
794 : : */
795 [ - + ]: 169 : if (register_b->address) {
796 : 0 : status = acpi_hw_write(value, register_b);
797 : : }
798 : :
799 : : return (status);
800 : : }
801 : :
802 : : #endif /* !ACPI_REDUCED_HARDWARE */
|