[ACPICA]
[reactos.git] / reactos / 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 = (1 << (Reg->AccessWidth + 2));
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 32-bit max
251 * version of AcpiRead, used internally since the overhead of
252 * 64-bit values is not needed.
253 *
254 * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
255 * SpaceID must be SystemMemory or SystemIO.
256 *
257 ******************************************************************************/
258
259 ACPI_STATUS
260 AcpiHwRead (
261 UINT32 *Value,
262 ACPI_GENERIC_ADDRESS *Reg)
263 {
264 UINT64 Address;
265 UINT8 AccessWidth;
266 UINT32 BitWidth;
267 UINT8 BitOffset;
268 UINT64 Value64;
269 UINT32 Value32;
270 UINT8 Index;
271 ACPI_STATUS Status;
272
273
274 ACPI_FUNCTION_NAME (HwRead);
275
276
277 /* Validate contents of the GAS register */
278
279 Status = AcpiHwValidateRegister (Reg, 32, &Address);
280 if (ACPI_FAILURE (Status))
281 {
282 return (Status);
283 }
284
285 /*
286 * Initialize entire 32-bit return value to zero, convert AccessWidth
287 * into number of bits based
288 */
289 *Value = 0;
290 AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 32);
291 BitWidth = Reg->BitOffset + Reg->BitWidth;
292 BitOffset = Reg->BitOffset;
293
294 /*
295 * Two address spaces supported: Memory or IO. PCI_Config is
296 * not supported here because the GAS structure is insufficient
297 */
298 Index = 0;
299 while (BitWidth)
300 {
301 if (BitOffset >= AccessWidth)
302 {
303 Value32 = 0;
304 BitOffset -= AccessWidth;
305 }
306 else
307 {
308 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
309 {
310 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
311 Address + Index * ACPI_DIV_8 (AccessWidth),
312 &Value64, AccessWidth);
313 Value32 = (UINT32) Value64;
314 }
315 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
316 {
317 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
318 Address + Index * ACPI_DIV_8 (AccessWidth),
319 &Value32, AccessWidth);
320 }
321 }
322
323 /*
324 * Use offset style bit writes because "Index * AccessWidth" is
325 * ensured to be less than 32-bits by AcpiHwValidateRegister().
326 */
327 ACPI_SET_BITS (Value, Index * AccessWidth,
328 ACPI_MASK_BITS_ABOVE_32 (AccessWidth), Value32);
329
330 BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
331 Index++;
332 }
333
334 ACPI_DEBUG_PRINT ((ACPI_DB_IO,
335 "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
336 *Value, AccessWidth, ACPI_FORMAT_UINT64 (Address),
337 AcpiUtGetRegionName (Reg->SpaceId)));
338
339 return (Status);
340 }
341
342
343 /******************************************************************************
344 *
345 * FUNCTION: AcpiHwWrite
346 *
347 * PARAMETERS: Value - Value to be written
348 * Reg - GAS register structure
349 *
350 * RETURN: Status
351 *
352 * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
353 * version of AcpiWrite, used internally since the overhead of
354 * 64-bit values is not needed.
355 *
356 ******************************************************************************/
357
358 ACPI_STATUS
359 AcpiHwWrite (
360 UINT32 Value,
361 ACPI_GENERIC_ADDRESS *Reg)
362 {
363 UINT64 Address;
364 UINT8 AccessWidth;
365 UINT32 BitWidth;
366 UINT8 BitOffset;
367 UINT64 Value64;
368 UINT32 Value32;
369 UINT8 Index;
370 ACPI_STATUS Status;
371
372
373 ACPI_FUNCTION_NAME (HwWrite);
374
375
376 /* Validate contents of the GAS register */
377
378 Status = AcpiHwValidateRegister (Reg, 32, &Address);
379 if (ACPI_FAILURE (Status))
380 {
381 return (Status);
382 }
383
384 /* Convert AccessWidth into number of bits based */
385
386 AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 32);
387 BitWidth = Reg->BitOffset + Reg->BitWidth;
388 BitOffset = Reg->BitOffset;
389
390 /*
391 * Two address spaces supported: Memory or IO. PCI_Config is
392 * not supported here because the GAS structure is insufficient
393 */
394 Index = 0;
395 while (BitWidth)
396 {
397 /*
398 * Use offset style bit reads because "Index * AccessWidth" is
399 * ensured to be less than 32-bits by AcpiHwValidateRegister().
400 */
401 Value32 = ACPI_GET_BITS (&Value, Index * AccessWidth,
402 ACPI_MASK_BITS_ABOVE_32 (AccessWidth));
403
404 if (BitOffset >= AccessWidth)
405 {
406 BitOffset -= AccessWidth;
407 }
408 else
409 {
410 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
411 {
412 Value64 = (UINT64) Value32;
413 Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
414 Address + Index * ACPI_DIV_8 (AccessWidth),
415 Value64, AccessWidth);
416 }
417 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
418 {
419 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
420 Address + Index * ACPI_DIV_8 (AccessWidth),
421 Value32, AccessWidth);
422 }
423 }
424
425 /*
426 * Index * AccessWidth is ensured to be less than 32-bits by
427 * AcpiHwValidateRegister().
428 */
429 BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
430 Index++;
431 }
432
433 ACPI_DEBUG_PRINT ((ACPI_DB_IO,
434 "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
435 Value, AccessWidth, ACPI_FORMAT_UINT64 (Address),
436 AcpiUtGetRegionName (Reg->SpaceId)));
437
438 return (Status);
439 }
440
441
442 #if (!ACPI_REDUCED_HARDWARE)
443 /*******************************************************************************
444 *
445 * FUNCTION: AcpiHwClearAcpiStatus
446 *
447 * PARAMETERS: None
448 *
449 * RETURN: Status
450 *
451 * DESCRIPTION: Clears all fixed and general purpose status bits
452 *
453 ******************************************************************************/
454
455 ACPI_STATUS
456 AcpiHwClearAcpiStatus (
457 void)
458 {
459 ACPI_STATUS Status;
460 ACPI_CPU_FLAGS LockFlags = 0;
461
462
463 ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
464
465
466 ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
467 ACPI_BITMASK_ALL_FIXED_STATUS,
468 ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
469
470 LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
471
472 /* Clear the fixed events in PM1 A/B */
473
474 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
475 ACPI_BITMASK_ALL_FIXED_STATUS);
476
477 AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
478
479 if (ACPI_FAILURE (Status))
480 {
481 goto Exit;
482 }
483
484 /* Clear the GPE Bits in all GPE registers in all GPE blocks */
485
486 Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
487
488 Exit:
489 return_ACPI_STATUS (Status);
490 }
491
492
493 /*******************************************************************************
494 *
495 * FUNCTION: AcpiHwGetBitRegisterInfo
496 *
497 * PARAMETERS: RegisterId - Index of ACPI Register to access
498 *
499 * RETURN: The bitmask to be used when accessing the register
500 *
501 * DESCRIPTION: Map RegisterId into a register bitmask.
502 *
503 ******************************************************************************/
504
505 ACPI_BIT_REGISTER_INFO *
506 AcpiHwGetBitRegisterInfo (
507 UINT32 RegisterId)
508 {
509 ACPI_FUNCTION_ENTRY ();
510
511
512 if (RegisterId > ACPI_BITREG_MAX)
513 {
514 ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
515 return (NULL);
516 }
517
518 return (&AcpiGbl_BitRegisterInfo[RegisterId]);
519 }
520
521
522 /******************************************************************************
523 *
524 * FUNCTION: AcpiHwWritePm1Control
525 *
526 * PARAMETERS: Pm1aControl - Value to be written to PM1A control
527 * Pm1bControl - Value to be written to PM1B control
528 *
529 * RETURN: Status
530 *
531 * DESCRIPTION: Write the PM1 A/B control registers. These registers are
532 * different than than the PM1 A/B status and enable registers
533 * in that different values can be written to the A/B registers.
534 * Most notably, the SLP_TYP bits can be different, as per the
535 * values returned from the _Sx predefined methods.
536 *
537 ******************************************************************************/
538
539 ACPI_STATUS
540 AcpiHwWritePm1Control (
541 UINT32 Pm1aControl,
542 UINT32 Pm1bControl)
543 {
544 ACPI_STATUS Status;
545
546
547 ACPI_FUNCTION_TRACE (HwWritePm1Control);
548
549
550 Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
551 if (ACPI_FAILURE (Status))
552 {
553 return_ACPI_STATUS (Status);
554 }
555
556 if (AcpiGbl_FADT.XPm1bControlBlock.Address)
557 {
558 Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
559 }
560 return_ACPI_STATUS (Status);
561 }
562
563
564 /******************************************************************************
565 *
566 * FUNCTION: AcpiHwRegisterRead
567 *
568 * PARAMETERS: RegisterId - ACPI Register ID
569 * ReturnValue - Where the register value is returned
570 *
571 * RETURN: Status and the value read.
572 *
573 * DESCRIPTION: Read from the specified ACPI register
574 *
575 ******************************************************************************/
576
577 ACPI_STATUS
578 AcpiHwRegisterRead (
579 UINT32 RegisterId,
580 UINT32 *ReturnValue)
581 {
582 UINT32 Value = 0;
583 ACPI_STATUS Status;
584
585
586 ACPI_FUNCTION_TRACE (HwRegisterRead);
587
588
589 switch (RegisterId)
590 {
591 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */
592
593 Status = AcpiHwReadMultiple (&Value,
594 &AcpiGbl_XPm1aStatus,
595 &AcpiGbl_XPm1bStatus);
596 break;
597
598 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */
599
600 Status = AcpiHwReadMultiple (&Value,
601 &AcpiGbl_XPm1aEnable,
602 &AcpiGbl_XPm1bEnable);
603 break;
604
605 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
606
607 Status = AcpiHwReadMultiple (&Value,
608 &AcpiGbl_FADT.XPm1aControlBlock,
609 &AcpiGbl_FADT.XPm1bControlBlock);
610
611 /*
612 * Zero the write-only bits. From the ACPI specification, "Hardware
613 * Write-Only Bits": "Upon reads to registers with write-only bits,
614 * software masks out all write-only bits."
615 */
616 Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
617 break;
618
619 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
620
621 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
622 break;
623
624 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
625
626 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
627 break;
628
629 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
630
631 Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
632 break;
633
634 default:
635
636 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
637 RegisterId));
638 Status = AE_BAD_PARAMETER;
639 break;
640 }
641
642 if (ACPI_SUCCESS (Status))
643 {
644 *ReturnValue = Value;
645 }
646
647 return_ACPI_STATUS (Status);
648 }
649
650
651 /******************************************************************************
652 *
653 * FUNCTION: AcpiHwRegisterWrite
654 *
655 * PARAMETERS: RegisterId - ACPI Register ID
656 * Value - The value to write
657 *
658 * RETURN: Status
659 *
660 * DESCRIPTION: Write to the specified ACPI register
661 *
662 * NOTE: In accordance with the ACPI specification, this function automatically
663 * preserves the value of the following bits, meaning that these bits cannot be
664 * changed via this interface:
665 *
666 * PM1_CONTROL[0] = SCI_EN
667 * PM1_CONTROL[9]
668 * PM1_STATUS[11]
669 *
670 * ACPI References:
671 * 1) Hardware Ignored Bits: When software writes to a register with ignored
672 * bit fields, it preserves the ignored bit fields
673 * 2) SCI_EN: OSPM always preserves this bit position
674 *
675 ******************************************************************************/
676
677 ACPI_STATUS
678 AcpiHwRegisterWrite (
679 UINT32 RegisterId,
680 UINT32 Value)
681 {
682 ACPI_STATUS Status;
683 UINT32 ReadValue;
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 (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
746 if (ACPI_FAILURE (Status))
747 {
748 goto Exit;
749 }
750
751 /* Insert the bits to be preserved */
752
753 ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
754
755 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
756 break;
757
758 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
759
760 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
761 break;
762
763 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
764
765 /* SMI_CMD is currently always in IO space */
766
767 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
768 break;
769
770 default:
771
772 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
773 RegisterId));
774 Status = AE_BAD_PARAMETER;
775 break;
776 }
777
778 Exit:
779 return_ACPI_STATUS (Status);
780 }
781
782
783 /******************************************************************************
784 *
785 * FUNCTION: AcpiHwReadMultiple
786 *
787 * PARAMETERS: Value - Where the register value is returned
788 * RegisterA - First ACPI register (required)
789 * RegisterB - Second ACPI register (optional)
790 *
791 * RETURN: Status
792 *
793 * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
794 *
795 ******************************************************************************/
796
797 static ACPI_STATUS
798 AcpiHwReadMultiple (
799 UINT32 *Value,
800 ACPI_GENERIC_ADDRESS *RegisterA,
801 ACPI_GENERIC_ADDRESS *RegisterB)
802 {
803 UINT32 ValueA = 0;
804 UINT32 ValueB = 0;
805 ACPI_STATUS Status;
806
807
808 /* The first register is always required */
809
810 Status = AcpiHwRead (&ValueA, RegisterA);
811 if (ACPI_FAILURE (Status))
812 {
813 return (Status);
814 }
815
816 /* Second register is optional */
817
818 if (RegisterB->Address)
819 {
820 Status = AcpiHwRead (&ValueB, RegisterB);
821 if (ACPI_FAILURE (Status))
822 {
823 return (Status);
824 }
825 }
826
827 /*
828 * OR the two return values together. No shifting or masking is necessary,
829 * because of how the PM1 registers are defined in the ACPI specification:
830 *
831 * "Although the bits can be split between the two register blocks (each
832 * register block has a unique pointer within the FADT), the bit positions
833 * are maintained. The register block with unimplemented bits (that is,
834 * those implemented in the other register block) always returns zeros,
835 * and writes have no side effects"
836 */
837 *Value = (ValueA | ValueB);
838 return (AE_OK);
839 }
840
841
842 /******************************************************************************
843 *
844 * FUNCTION: AcpiHwWriteMultiple
845 *
846 * PARAMETERS: Value - The value to write
847 * RegisterA - First ACPI register (required)
848 * RegisterB - Second ACPI register (optional)
849 *
850 * RETURN: Status
851 *
852 * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
853 *
854 ******************************************************************************/
855
856 static ACPI_STATUS
857 AcpiHwWriteMultiple (
858 UINT32 Value,
859 ACPI_GENERIC_ADDRESS *RegisterA,
860 ACPI_GENERIC_ADDRESS *RegisterB)
861 {
862 ACPI_STATUS Status;
863
864
865 /* The first register is always required */
866
867 Status = AcpiHwWrite (Value, RegisterA);
868 if (ACPI_FAILURE (Status))
869 {
870 return (Status);
871 }
872
873 /*
874 * Second register is optional
875 *
876 * No bit shifting or clearing is necessary, because of how the PM1
877 * registers are defined in the ACPI specification:
878 *
879 * "Although the bits can be split between the two register blocks (each
880 * register block has a unique pointer within the FADT), the bit positions
881 * are maintained. The register block with unimplemented bits (that is,
882 * those implemented in the other register block) always returns zeros,
883 * and writes have no side effects"
884 */
885 if (RegisterB->Address)
886 {
887 Status = AcpiHwWrite (Value, RegisterB);
888 }
889
890 return (Status);
891 }
892
893 #endif /* !ACPI_REDUCED_HARDWARE */