[ACPICA] Update to version 20171215. CORE-15222
[reactos.git] / drivers / bus / acpi / acpica / hardware / hwregs.c
1 /*******************************************************************************
2 *
3 * Module Name: hwregs - Read/write access functions for the various ACPI
4 * control and status registers.
5 *
6 ******************************************************************************/
7
8 /*
9 * Copyright (C) 2000 - 2017, Intel Corp.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions, and the following disclaimer,
17 * without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 * substantially similar to the "NO WARRANTY" disclaimer below
20 * ("Disclaimer") and any redistribution must be conditioned upon
21 * including a substantially similar Disclaimer requirement for further
22 * binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 * of any contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
30 *
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
43 */
44
45 #include "acpi.h"
46 #include "accommon.h"
47 #include "acevents.h"
48
49 #define _COMPONENT ACPI_HARDWARE
50 ACPI_MODULE_NAME ("hwregs")
51
52
53 #if (!ACPI_REDUCED_HARDWARE)
54
55 /* Local Prototypes */
56
57 static UINT8
58 AcpiHwGetAccessBitWidth (
59 UINT64 Address,
60 ACPI_GENERIC_ADDRESS *Reg,
61 UINT8 MaxBitWidth);
62
63 static ACPI_STATUS
64 AcpiHwReadMultiple (
65 UINT32 *Value,
66 ACPI_GENERIC_ADDRESS *RegisterA,
67 ACPI_GENERIC_ADDRESS *RegisterB);
68
69 static ACPI_STATUS
70 AcpiHwWriteMultiple (
71 UINT32 Value,
72 ACPI_GENERIC_ADDRESS *RegisterA,
73 ACPI_GENERIC_ADDRESS *RegisterB);
74
75 #endif /* !ACPI_REDUCED_HARDWARE */
76
77
78 /******************************************************************************
79 *
80 * FUNCTION: AcpiHwGetAccessBitWidth
81 *
82 * PARAMETERS: Address - GAS register address
83 * Reg - GAS register structure
84 * MaxBitWidth - Max BitWidth supported (32 or 64)
85 *
86 * RETURN: Status
87 *
88 * DESCRIPTION: Obtain optimal access bit width
89 *
90 ******************************************************************************/
91
92 static UINT8
93 AcpiHwGetAccessBitWidth (
94 UINT64 Address,
95 ACPI_GENERIC_ADDRESS *Reg,
96 UINT8 MaxBitWidth)
97 {
98 UINT8 AccessBitWidth;
99
100
101 /*
102 * GAS format "register", used by FADT:
103 * 1. Detected if BitOffset is 0 and BitWidth is 8/16/32/64;
104 * 2. AccessSize field is ignored and BitWidth field is used for
105 * determining the boundary of the IO accesses.
106 * GAS format "region", used by APEI registers:
107 * 1. Detected if BitOffset is not 0 or BitWidth is not 8/16/32/64;
108 * 2. AccessSize field is used for determining the boundary of the
109 * IO accesses;
110 * 3. BitOffset/BitWidth fields are used to describe the "region".
111 *
112 * Note: This algorithm assumes that the "Address" fields should always
113 * contain aligned values.
114 */
115 if (!Reg->BitOffset && Reg->BitWidth &&
116 ACPI_IS_POWER_OF_TWO (Reg->BitWidth) &&
117 ACPI_IS_ALIGNED (Reg->BitWidth, 8))
118 {
119 AccessBitWidth = Reg->BitWidth;
120 }
121 else if (Reg->AccessWidth)
122 {
123 AccessBitWidth = ACPI_ACCESS_BIT_WIDTH (Reg->AccessWidth);
124 }
125 else
126 {
127 AccessBitWidth = ACPI_ROUND_UP_POWER_OF_TWO_8 (
128 Reg->BitOffset + Reg->BitWidth);
129 if (AccessBitWidth <= 8)
130 {
131 AccessBitWidth = 8;
132 }
133 else
134 {
135 while (!ACPI_IS_ALIGNED (Address, AccessBitWidth >> 3))
136 {
137 AccessBitWidth >>= 1;
138 }
139 }
140 }
141
142 /* Maximum IO port access bit width is 32 */
143
144 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
145 {
146 MaxBitWidth = 32;
147 }
148
149 /*
150 * Return access width according to the requested maximum access bit width,
151 * as the caller should know the format of the register and may enforce
152 * a 32-bit accesses.
153 */
154 if (AccessBitWidth < MaxBitWidth)
155 {
156 return (AccessBitWidth);
157 }
158 return (MaxBitWidth);
159 }
160
161
162 /******************************************************************************
163 *
164 * FUNCTION: AcpiHwValidateRegister
165 *
166 * PARAMETERS: Reg - GAS register structure
167 * MaxBitWidth - Max BitWidth supported (32 or 64)
168 * Address - Pointer to where the gas->address
169 * is returned
170 *
171 * RETURN: Status
172 *
173 * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
174 * pointer, Address, SpaceId, BitWidth, and BitOffset.
175 *
176 ******************************************************************************/
177
178 ACPI_STATUS
179 AcpiHwValidateRegister (
180 ACPI_GENERIC_ADDRESS *Reg,
181 UINT8 MaxBitWidth,
182 UINT64 *Address)
183 {
184 UINT8 BitWidth;
185 UINT8 AccessWidth;
186
187
188 /* Must have a valid pointer to a GAS structure */
189
190 if (!Reg)
191 {
192 return (AE_BAD_PARAMETER);
193 }
194
195 /*
196 * Copy the target address. This handles possible alignment issues.
197 * Address must not be null. A null address also indicates an optional
198 * ACPI register that is not supported, so no error message.
199 */
200 ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
201 if (!(*Address))
202 {
203 return (AE_BAD_ADDRESS);
204 }
205
206 /* Validate the SpaceID */
207
208 if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
209 (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
210 {
211 ACPI_ERROR ((AE_INFO,
212 "Unsupported address space: 0x%X", Reg->SpaceId));
213 return (AE_SUPPORT);
214 }
215
216 /* Validate the AccessWidth */
217
218 if (Reg->AccessWidth > 4)
219 {
220 ACPI_ERROR ((AE_INFO,
221 "Unsupported register access width: 0x%X", Reg->AccessWidth));
222 return (AE_SUPPORT);
223 }
224
225 /* Validate the BitWidth, convert AccessWidth into number of bits */
226
227 AccessWidth = AcpiHwGetAccessBitWidth (*Address, Reg, MaxBitWidth);
228 BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth);
229 if (MaxBitWidth < BitWidth)
230 {
231 ACPI_WARNING ((AE_INFO,
232 "Requested bit width 0x%X is smaller than register bit width 0x%X",
233 MaxBitWidth, BitWidth));
234 return (AE_SUPPORT);
235 }
236
237 return (AE_OK);
238 }
239
240
241 /******************************************************************************
242 *
243 * FUNCTION: AcpiHwRead
244 *
245 * PARAMETERS: Value - Where the value is returned
246 * Reg - GAS register structure
247 *
248 * RETURN: Status
249 *
250 * DESCRIPTION: Read from either memory or IO space. This is a 64-bit max
251 * version of AcpiRead.
252 *
253 * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
254 * SpaceID must be SystemMemory or SystemIO.
255 *
256 ******************************************************************************/
257
258 ACPI_STATUS
259 AcpiHwRead (
260 UINT64 *Value,
261 ACPI_GENERIC_ADDRESS *Reg)
262 {
263 UINT64 Address;
264 UINT8 AccessWidth;
265 UINT32 BitWidth;
266 UINT8 BitOffset;
267 UINT64 Value64;
268 UINT32 Value32;
269 UINT8 Index;
270 ACPI_STATUS Status;
271
272
273 ACPI_FUNCTION_NAME (HwRead);
274
275
276 /* Validate contents of the GAS register */
277
278 Status = AcpiHwValidateRegister (Reg, 64, &Address);
279 if (ACPI_FAILURE (Status))
280 {
281 return (Status);
282 }
283
284 /*
285 * Initialize entire 64-bit return value to zero, convert AccessWidth
286 * into number of bits based
287 */
288 *Value = 0;
289 AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64);
290 BitWidth = Reg->BitOffset + Reg->BitWidth;
291 BitOffset = Reg->BitOffset;
292
293 /*
294 * Two address spaces supported: Memory or IO. PCI_Config is
295 * not supported here because the GAS structure is insufficient
296 */
297 Index = 0;
298 while (BitWidth)
299 {
300 if (BitOffset >= AccessWidth)
301 {
302 Value64 = 0;
303 BitOffset -= AccessWidth;
304 }
305 else
306 {
307 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
308 {
309 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
310 Address + Index * ACPI_DIV_8 (AccessWidth),
311 &Value64, AccessWidth);
312 }
313 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
314 {
315 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
316 Address + Index * ACPI_DIV_8 (AccessWidth),
317 &Value32, AccessWidth);
318 Value64 = (UINT64) Value32;
319 }
320 }
321
322 /*
323 * Use offset style bit writes because "Index * AccessWidth" is
324 * ensured to be less than 64-bits by AcpiHwValidateRegister().
325 */
326 ACPI_SET_BITS (Value, Index * AccessWidth,
327 ACPI_MASK_BITS_ABOVE_64 (AccessWidth), Value64);
328
329 BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
330 Index++;
331 }
332
333 ACPI_DEBUG_PRINT ((ACPI_DB_IO,
334 "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
335 ACPI_FORMAT_UINT64 (*Value), AccessWidth,
336 ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId)));
337
338 return (Status);
339 }
340
341
342 /******************************************************************************
343 *
344 * FUNCTION: AcpiHwWrite
345 *
346 * PARAMETERS: Value - Value to be written
347 * Reg - GAS register structure
348 *
349 * RETURN: Status
350 *
351 * DESCRIPTION: Write to either memory or IO space. This is a 64-bit max
352 * version of AcpiWrite.
353 *
354 ******************************************************************************/
355
356 ACPI_STATUS
357 AcpiHwWrite (
358 UINT64 Value,
359 ACPI_GENERIC_ADDRESS *Reg)
360 {
361 UINT64 Address;
362 UINT8 AccessWidth;
363 UINT32 BitWidth;
364 UINT8 BitOffset;
365 UINT64 Value64;
366 UINT8 Index;
367 ACPI_STATUS Status;
368
369
370 ACPI_FUNCTION_NAME (HwWrite);
371
372
373 /* Validate contents of the GAS register */
374
375 Status = AcpiHwValidateRegister (Reg, 64, &Address);
376 if (ACPI_FAILURE (Status))
377 {
378 return (Status);
379 }
380
381 /* Convert AccessWidth into number of bits based */
382
383 AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64);
384 BitWidth = Reg->BitOffset + Reg->BitWidth;
385 BitOffset = Reg->BitOffset;
386
387 /*
388 * Two address spaces supported: Memory or IO. PCI_Config is
389 * not supported here because the GAS structure is insufficient
390 */
391 Index = 0;
392 while (BitWidth)
393 {
394 /*
395 * Use offset style bit reads because "Index * AccessWidth" is
396 * ensured to be less than 64-bits by AcpiHwValidateRegister().
397 */
398 Value64 = ACPI_GET_BITS (&Value, Index * AccessWidth,
399 ACPI_MASK_BITS_ABOVE_64 (AccessWidth));
400
401 if (BitOffset >= AccessWidth)
402 {
403 BitOffset -= AccessWidth;
404 }
405 else
406 {
407 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
408 {
409 Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
410 Address + Index * ACPI_DIV_8 (AccessWidth),
411 Value64, AccessWidth);
412 }
413 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
414 {
415 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
416 Address + Index * ACPI_DIV_8 (AccessWidth),
417 (UINT32) Value64, AccessWidth);
418 }
419 }
420
421 /*
422 * Index * AccessWidth is ensured to be less than 32-bits by
423 * AcpiHwValidateRegister().
424 */
425 BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
426 Index++;
427 }
428
429 ACPI_DEBUG_PRINT ((ACPI_DB_IO,
430 "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n",
431 ACPI_FORMAT_UINT64 (Value), AccessWidth,
432 ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId)));
433
434 return (Status);
435 }
436
437
438 #if (!ACPI_REDUCED_HARDWARE)
439 /*******************************************************************************
440 *
441 * FUNCTION: AcpiHwClearAcpiStatus
442 *
443 * PARAMETERS: None
444 *
445 * RETURN: Status
446 *
447 * DESCRIPTION: Clears all fixed and general purpose status bits
448 *
449 ******************************************************************************/
450
451 ACPI_STATUS
452 AcpiHwClearAcpiStatus (
453 void)
454 {
455 ACPI_STATUS Status;
456 ACPI_CPU_FLAGS LockFlags = 0;
457
458
459 ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
460
461
462 ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
463 ACPI_BITMASK_ALL_FIXED_STATUS,
464 ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
465
466 LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
467
468 /* Clear the fixed events in PM1 A/B */
469
470 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
471 ACPI_BITMASK_ALL_FIXED_STATUS);
472
473 AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
474
475 if (ACPI_FAILURE (Status))
476 {
477 goto Exit;
478 }
479
480 /* Clear the GPE Bits in all GPE registers in all GPE blocks */
481
482 Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
483
484 Exit:
485 return_ACPI_STATUS (Status);
486 }
487
488
489 /*******************************************************************************
490 *
491 * FUNCTION: AcpiHwGetBitRegisterInfo
492 *
493 * PARAMETERS: RegisterId - Index of ACPI Register to access
494 *
495 * RETURN: The bitmask to be used when accessing the register
496 *
497 * DESCRIPTION: Map RegisterId into a register bitmask.
498 *
499 ******************************************************************************/
500
501 ACPI_BIT_REGISTER_INFO *
502 AcpiHwGetBitRegisterInfo (
503 UINT32 RegisterId)
504 {
505 ACPI_FUNCTION_ENTRY ();
506
507
508 if (RegisterId > ACPI_BITREG_MAX)
509 {
510 ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
511 return (NULL);
512 }
513
514 return (&AcpiGbl_BitRegisterInfo[RegisterId]);
515 }
516
517
518 /******************************************************************************
519 *
520 * FUNCTION: AcpiHwWritePm1Control
521 *
522 * PARAMETERS: Pm1aControl - Value to be written to PM1A control
523 * Pm1bControl - Value to be written to PM1B control
524 *
525 * RETURN: Status
526 *
527 * DESCRIPTION: Write the PM1 A/B control registers. These registers are
528 * different than than the PM1 A/B status and enable registers
529 * in that different values can be written to the A/B registers.
530 * Most notably, the SLP_TYP bits can be different, as per the
531 * values returned from the _Sx predefined methods.
532 *
533 ******************************************************************************/
534
535 ACPI_STATUS
536 AcpiHwWritePm1Control (
537 UINT32 Pm1aControl,
538 UINT32 Pm1bControl)
539 {
540 ACPI_STATUS Status;
541
542
543 ACPI_FUNCTION_TRACE (HwWritePm1Control);
544
545
546 Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
547 if (ACPI_FAILURE (Status))
548 {
549 return_ACPI_STATUS (Status);
550 }
551
552 if (AcpiGbl_FADT.XPm1bControlBlock.Address)
553 {
554 Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
555 }
556 return_ACPI_STATUS (Status);
557 }
558
559
560 /******************************************************************************
561 *
562 * FUNCTION: AcpiHwRegisterRead
563 *
564 * PARAMETERS: RegisterId - ACPI Register ID
565 * ReturnValue - Where the register value is returned
566 *
567 * RETURN: Status and the value read.
568 *
569 * DESCRIPTION: Read from the specified ACPI register
570 *
571 ******************************************************************************/
572
573 ACPI_STATUS
574 AcpiHwRegisterRead (
575 UINT32 RegisterId,
576 UINT32 *ReturnValue)
577 {
578 UINT32 Value = 0;
579 UINT64 Value64;
580 ACPI_STATUS Status;
581
582
583 ACPI_FUNCTION_TRACE (HwRegisterRead);
584
585
586 switch (RegisterId)
587 {
588 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */
589
590 Status = AcpiHwReadMultiple (&Value,
591 &AcpiGbl_XPm1aStatus,
592 &AcpiGbl_XPm1bStatus);
593 break;
594
595 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */
596
597 Status = AcpiHwReadMultiple (&Value,
598 &AcpiGbl_XPm1aEnable,
599 &AcpiGbl_XPm1bEnable);
600 break;
601
602 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
603
604 Status = AcpiHwReadMultiple (&Value,
605 &AcpiGbl_FADT.XPm1aControlBlock,
606 &AcpiGbl_FADT.XPm1bControlBlock);
607
608 /*
609 * Zero the write-only bits. From the ACPI specification, "Hardware
610 * Write-Only Bits": "Upon reads to registers with write-only bits,
611 * software masks out all write-only bits."
612 */
613 Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
614 break;
615
616 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
617
618 Status = AcpiHwRead (&Value64, &AcpiGbl_FADT.XPm2ControlBlock);
619 Value = (UINT32) Value64;
620 break;
621
622 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
623
624 Status = AcpiHwRead (&Value64, &AcpiGbl_FADT.XPmTimerBlock);
625 Value = (UINT32) Value64;
626 break;
627
628 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
629
630 Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
631 break;
632
633 default:
634
635 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
636 RegisterId));
637 Status = AE_BAD_PARAMETER;
638 break;
639 }
640
641 if (ACPI_SUCCESS (Status))
642 {
643 *ReturnValue = (UINT32) Value;
644 }
645
646 return_ACPI_STATUS (Status);
647 }
648
649
650 /******************************************************************************
651 *
652 * FUNCTION: AcpiHwRegisterWrite
653 *
654 * PARAMETERS: RegisterId - ACPI Register ID
655 * Value - The value to write
656 *
657 * RETURN: Status
658 *
659 * DESCRIPTION: Write to the specified ACPI register
660 *
661 * NOTE: In accordance with the ACPI specification, this function automatically
662 * preserves the value of the following bits, meaning that these bits cannot be
663 * changed via this interface:
664 *
665 * PM1_CONTROL[0] = SCI_EN
666 * PM1_CONTROL[9]
667 * PM1_STATUS[11]
668 *
669 * ACPI References:
670 * 1) Hardware Ignored Bits: When software writes to a register with ignored
671 * bit fields, it preserves the ignored bit fields
672 * 2) SCI_EN: OSPM always preserves this bit position
673 *
674 ******************************************************************************/
675
676 ACPI_STATUS
677 AcpiHwRegisterWrite (
678 UINT32 RegisterId,
679 UINT32 Value)
680 {
681 ACPI_STATUS Status;
682 UINT32 ReadValue;
683 UINT64 ReadValue64;
684
685
686 ACPI_FUNCTION_TRACE (HwRegisterWrite);
687
688
689 switch (RegisterId)
690 {
691 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */
692 /*
693 * Handle the "ignored" bit in PM1 Status. According to the ACPI
694 * specification, ignored bits are to be preserved when writing.
695 * Normally, this would mean a read/modify/write sequence. However,
696 * preserving a bit in the status register is different. Writing a
697 * one clears the status, and writing a zero preserves the status.
698 * Therefore, we must always write zero to the ignored bit.
699 *
700 * This behavior is clarified in the ACPI 4.0 specification.
701 */
702 Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
703
704 Status = AcpiHwWriteMultiple (Value,
705 &AcpiGbl_XPm1aStatus,
706 &AcpiGbl_XPm1bStatus);
707 break;
708
709 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */
710
711 Status = AcpiHwWriteMultiple (Value,
712 &AcpiGbl_XPm1aEnable,
713 &AcpiGbl_XPm1bEnable);
714 break;
715
716 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
717 /*
718 * Perform a read first to preserve certain bits (per ACPI spec)
719 * Note: This includes SCI_EN, we never want to change this bit
720 */
721 Status = AcpiHwReadMultiple (&ReadValue,
722 &AcpiGbl_FADT.XPm1aControlBlock,
723 &AcpiGbl_FADT.XPm1bControlBlock);
724 if (ACPI_FAILURE (Status))
725 {
726 goto Exit;
727 }
728
729 /* Insert the bits to be preserved */
730
731 ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
732
733 /* Now we can write the data */
734
735 Status = AcpiHwWriteMultiple (Value,
736 &AcpiGbl_FADT.XPm1aControlBlock,
737 &AcpiGbl_FADT.XPm1bControlBlock);
738 break;
739
740 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
741 /*
742 * For control registers, all reserved bits must be preserved,
743 * as per the ACPI spec.
744 */
745 Status = AcpiHwRead (&ReadValue64, &AcpiGbl_FADT.XPm2ControlBlock);
746 if (ACPI_FAILURE (Status))
747 {
748 goto Exit;
749 }
750 ReadValue = (UINT32) ReadValue64;
751
752 /* Insert the bits to be preserved */
753
754 ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
755
756 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
757 break;
758
759 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
760
761 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
762 break;
763
764 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
765
766 /* SMI_CMD is currently always in IO space */
767
768 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
769 break;
770
771 default:
772
773 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
774 RegisterId));
775 Status = AE_BAD_PARAMETER;
776 break;
777 }
778
779 Exit:
780 return_ACPI_STATUS (Status);
781 }
782
783
784 /******************************************************************************
785 *
786 * FUNCTION: AcpiHwReadMultiple
787 *
788 * PARAMETERS: Value - Where the register value is returned
789 * RegisterA - First ACPI register (required)
790 * RegisterB - Second ACPI register (optional)
791 *
792 * RETURN: Status
793 *
794 * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
795 *
796 ******************************************************************************/
797
798 static ACPI_STATUS
799 AcpiHwReadMultiple (
800 UINT32 *Value,
801 ACPI_GENERIC_ADDRESS *RegisterA,
802 ACPI_GENERIC_ADDRESS *RegisterB)
803 {
804 UINT32 ValueA = 0;
805 UINT32 ValueB = 0;
806 UINT64 Value64;
807 ACPI_STATUS Status;
808
809
810 /* The first register is always required */
811
812 Status = AcpiHwRead (&Value64, RegisterA);
813 if (ACPI_FAILURE (Status))
814 {
815 return (Status);
816 }
817 ValueA = (UINT32) Value64;
818
819 /* Second register is optional */
820
821 if (RegisterB->Address)
822 {
823 Status = AcpiHwRead (&Value64, RegisterB);
824 if (ACPI_FAILURE (Status))
825 {
826 return (Status);
827 }
828 ValueB = (UINT32) Value64;
829 }
830
831 /*
832 * OR the two return values together. No shifting or masking is necessary,
833 * because of how the PM1 registers are defined in the ACPI specification:
834 *
835 * "Although the bits can be split between the two register blocks (each
836 * register block has a unique pointer within the FADT), the bit positions
837 * are maintained. The register block with unimplemented bits (that is,
838 * those implemented in the other register block) always returns zeros,
839 * and writes have no side effects"
840 */
841 *Value = (ValueA | ValueB);
842 return (AE_OK);
843 }
844
845
846 /******************************************************************************
847 *
848 * FUNCTION: AcpiHwWriteMultiple
849 *
850 * PARAMETERS: Value - The value to write
851 * RegisterA - First ACPI register (required)
852 * RegisterB - Second ACPI register (optional)
853 *
854 * RETURN: Status
855 *
856 * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
857 *
858 ******************************************************************************/
859
860 static ACPI_STATUS
861 AcpiHwWriteMultiple (
862 UINT32 Value,
863 ACPI_GENERIC_ADDRESS *RegisterA,
864 ACPI_GENERIC_ADDRESS *RegisterB)
865 {
866 ACPI_STATUS Status;
867
868
869 /* The first register is always required */
870
871 Status = AcpiHwWrite (Value, RegisterA);
872 if (ACPI_FAILURE (Status))
873 {
874 return (Status);
875 }
876
877 /*
878 * Second register is optional
879 *
880 * No bit shifting or clearing is necessary, because of how the PM1
881 * registers are defined in the ACPI specification:
882 *
883 * "Although the bits can be split between the two register blocks (each
884 * register block has a unique pointer within the FADT), the bit positions
885 * are maintained. The register block with unimplemented bits (that is,
886 * those implemented in the other register block) always returns zeros,
887 * and writes have no side effects"
888 */
889 if (RegisterB->Address)
890 {
891 Status = AcpiHwWrite (Value, RegisterB);
892 }
893
894 return (Status);
895 }
896
897 #endif /* !ACPI_REDUCED_HARDWARE */