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