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